mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-07-29 02:29:31 +00:00
Some checks failed
* fix(tools): sandbox FileWriterTool writes and fix file tool rough edges FileReadTool confined reads to the working directory, but FileWriterTool only checked that `filename` stayed inside `directory` — and `directory` itself is an LLM-supplied schema field. An agent could therefore write anywhere the process had permission to, including ~/.ssh and site-packages, while the reader refused to read back what the writer had just written. FileWriterTool was the only filesystem tool in the package that did not go through validate_file_path; files_compressor_tool validates even its output path. Writes are now confined to base_dir (the working directory by default): the resolved directory must sit inside base_dir, and the resolved file must sit inside that directory. The pre-existing filename containment check is kept as-is and still applies even when the unsafe-paths escape hatch is on, so no existing guarantee is weakened. Both tools gain a base_dir field so a developer can widen the sandbox deliberately instead of reaching for the process-wide CREWAI_TOOLS_ALLOW_UNSAFE_PATHS kill switch. FileReadTool also stops rejecting a file_path given to its own constructor: that is developer-declared intent, and declaring one file does not expose its siblings. Also fixed: - FileReadTool scanned the whole file when reading a line window; it now stops via islice once the requested lines are collected. - FileWriterTool._run(**kwargs) made the documented positional call signature raise TypeError and turned a missing overwrite into "error accessing key". It now takes named parameters in the documented (filename, content, directory) order. - A directory naming an existing file reported "already exists and overwrite option was not passed" even with overwrite=True; it now explains the real problem. - Subdirectories inside filename are created, matching what passing directory already did. - Both tools now write and decode UTF-8 by default instead of the platform locale encoding, with an encoding field to override. The docs already claimed UTF-8 and recommended the writer to Windows users. - The writer's schema fields had no descriptions for the LLM. - Docs claimed FileReadTool parses JSON into a dict (it never has), shipped a snippet that raised TypeError, and did not mention the path sandbox. The writer README also began with a stray "Here's the rewritten README" preamble. BREAKING CHANGE: FileWriterTool no longer writes outside the working directory. Pass base_dir to authorize a different tree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * chore: update tool specifications * fix(tools): make the declared FileReadTool file reachable by agents Addresses review feedback on #6692. The constructor-path exemption did not actually work the way an agent calls the tool. The description only advertises a redacted label (the basename, when the file sits outside the sandbox), but resolution required the exact absolute path, so the model's call was sandboxed and the declared file was never read. Worse, file_path was a required schema field, so the long-documented "call with no arguments to read the default file" raised a validation error instead: FileReadTool(file_path="/outside/declared.txt") .run() -> ValueError: validation failed .run(file_path="declared.txt") -> Error: File not found .run(file_path="/outside/declared.txt") -> works, but the model was never told this path file_path is now optional in the schema, so omitting it reads the default, and the declared file is addressable by the label the description shows the model as well as by its real path. Declaring one file still does not expose its siblings. The declared path is also pinned to its real path at construction, so a later chdir cannot silently repoint it at a different file — previously a relative constructor path re-resolved against the new working directory on every call. Also guards the writer's filepath resolution, which could raise ValueError out of _run for a filename containing a null byte, breaking the contract of always returning a descriptive string. The directory and read paths were already guarded. Adds docstrings to strtobool and both _run methods, corrects an Arabic tanween spelling and a kaf-as-descriptor calque in the localized read docs, and regenerates tool.specs.json for the schema change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(tools): anchor the declared read path to base_dir, not the cwd Addresses the second round of review feedback on #6692. The previous commit pinned a relative constructor file_path with os.path.realpath, which anchors to the working directory, while both format_path_for_display and validate_file_path anchor a relative path to base_dir. With the two roots disagreeing, the same relative string meant two different files — and the tool served the cwd one under a label that looks like it belongs to the sandbox: FileReadTool(file_path="data.txt", base_dir="/allowed") # cwd=/work label advertised to the model -> "data.txt" run(file_path="data.txt") -> contents of /work/data.txt That reads a file from outside base_dir, so it was a sandbox escape introduced by the exemption itself, not just a wrong-file bug. Resolution now goes through a single _resolve_against_base helper that anchors relative paths exactly the way the sandbox does, so the pinned path, the advertised label and the containment check all agree. Covered by test_relative_declared_path_anchors_to_base_dir. Also softens "always readable" to "always allowed past the containment check" in the docstring, README and docs, since bypassing containment does not guarantee the read succeeds — it can still fail on a missing file, a directory, or permissions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(tools): tell the LLM about the path sandbox in tool descriptions Addresses the low-confidence notes from the Copilot review on #6692. Both tools' descriptions were pre-sandbox wording, so the model learned about containment only by attempting a path and reading the error back. Both now state that access is confined to the tool's allowed directory and that a path resolving outside it is rejected. The wording deliberately says "the tool's allowed directory" rather than "the working directory", because the root is base_dir when one is set, and naming the absolute root would leak it into the prompt — the same reason paths are redacted in errors. Not changed: the notes also suggested advertising `encoding`. That is a constructor-only field the model cannot set, so describing it to the LLM would be misleading. Also fixes a test docstring that contradicted its own assertion — the public run() path does raise on schema validation failure, which is what the test asserts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(tools): anchor base_dir at construction so the sandbox cannot move Addresses the third review round on #6692. Both remaining findings came from the same habit: storing an unanchored string and re-resolving it later. A relative base_dir was kept verbatim and re-resolved against getcwd() on every call, while the declared file was pinned once at construction. After a chdir the sandbox root moved but the declared default did not, so one tool applied two different roots. base_dir is now resolved once — in the reader's __init__, and via a field_validator on the writer so it also applies on the model_validate path. That also covers the serialization concern. model_dump drops the private pin, and __init__ re-runs on restore, so a relative file_path was re-anchored against whatever the working directory happened to be at load time. With base_dir anchored, restore rebuilds the identical pin. The residual case is a relative file_path with no base_dir, where the sandbox root is the working directory too — so both move together and the tool stays self-consistent. Covered by test_declared_path_survives_a_serialization_round_trip and test_relative_base_dir_is_anchored_at_construction on both tools. Also corrects the writer's 'directory' description, README and docs: the default resolves inside the tool's allowed directory, which is base_dir when one is set, not always the working directory. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
56 lines
2.2 KiB
Plaintext
56 lines
2.2 KiB
Plaintext
---
|
|
title: 파일 쓰기
|
|
description: FileWriterTool은 파일에 내용을 쓰도록 설계되었습니다.
|
|
icon: file-pen
|
|
mode: "wide"
|
|
---
|
|
|
|
# `FileWriterTool`
|
|
|
|
## 설명
|
|
|
|
`FileWriterTool`은 crewai_tools 패키지의 구성 요소로, 다양한 운영 체제(Windows, Linux, macOS)에서 파일에 내용을 작성하는 과정을 간소화하도록 설계되었습니다.
|
|
이 도구는 보고서 생성, 로그 저장, 설정 파일 작성 등과 같은 시나리오에서 특히 유용합니다.
|
|
운영 체제마다 다른 경로 처리를 지원하며, UTF-8 인코딩을 지원하고, 디렉토리가 존재하지 않으면 자동으로 생성하여, 다양한 플랫폼에서 출력 결과를 안정적으로 정리할 수 있도록 도와줍니다.
|
|
|
|
## 설치
|
|
|
|
프로젝트에서 `FileWriterTool`을 사용하려면 crewai_tools 패키지를 설치하세요:
|
|
|
|
```shell
|
|
pip install 'crewai[tools]'
|
|
```
|
|
|
|
## 예시
|
|
|
|
`FileWriterTool`을(를) 시작하려면:
|
|
|
|
```python Code
|
|
from crewai_tools import FileWriterTool
|
|
|
|
# Initialize the tool
|
|
file_writer_tool = FileWriterTool()
|
|
|
|
# Write content to a file in a specified directory
|
|
result = file_writer_tool.run(
|
|
filename='example.txt',
|
|
content='This is a test content.',
|
|
directory='test_directory',
|
|
)
|
|
print(result)
|
|
```
|
|
|
|
## 인자
|
|
|
|
- `filename`: 생성하거나 덮어쓸 파일의 이름입니다.
|
|
- `content`: 파일에 쓸 내용입니다.
|
|
- `directory` (선택 사항): 파일이 생성될 디렉터리의 경로입니다. 기본값은 현재 디렉터리(`.`)입니다. 디렉터리가 존재하지 않으면 생성됩니다.
|
|
|
|
## 결론
|
|
|
|
`FileWriterTool`을 crew에 통합함으로써, 에이전트는 다양한 운영 체제에서 파일에 내용을 안정적으로 쓸 수 있습니다.
|
|
이 도구는 출력 데이터를 저장하거나, 구조화된 파일 시스템을 생성하거나, 크로스 플랫폼 파일 작업을 처리해야 하는 작업에 필수적입니다.
|
|
특히 표준 Python 파일 작업에서 파일 쓰기 이슈가 발생할 수 있는 Windows 사용자에게 권장됩니다.
|
|
|
|
제공된 설정 및 사용 가이드라인을 준수하면, 이 도구를 프로젝트에 통합하는 과정이 간단하며 모든 플랫폼에서 일관된 파일 쓰기 동작을 보장합니다.
|