{"record":{"id":"1a82d1d112c48e60","repo":"datawhalechina/hello-agents","slug":"disallowed-file-suffix-for-write-target-suffix","errorCode":null,"errorMessage":"Disallowed file suffix for write: {target.suffix}","messagePattern":"Disallowed file suffix for write: (.+?)","errorType":"exception","errorClass":"PatchApplyError","httpStatus":null,"severity":"error","filePath":"Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py","lineNumber":221,"sourceCode":"        if not str(target).startswith(str(self.repo_root.resolve()) + os.sep) and target != self.repo_root.resolve():\n            raise PatchApplyError(f\"Path escapes repo_root: {rel_path}\")\n        if target.exists() and target.is_symlink():\n            raise PatchApplyError(f\"Refusing to modify symlink: {rel_path}\")\n        return target\n\n    def _enforce_suffix(self, target: Path) -> None:\n        \"\"\"\n        检查目标文件的后缀是否在允许的列表中。\n        防止意外修改二进制文件、配置文件或其他敏感文件。\n        \n        参数:\n            target: 目标文件路径对象\n            \n        异常:\n            PatchApplyError: 当文件后缀不在允许列表中时抛出\n        \"\"\"\n        if target.suffix and target.suffix not in self.allowed_write_suffixes:\n            raise PatchApplyError(f\"Disallowed file suffix for write: {target.suffix}\")\n\n    def _backup_file(self, target: Path, backup_run_dir: Path) -> Path:\n        \"\"\"\n        备份目标文件到指定的备份目录。\n        备份文件保持与原文件相同的相对路径结构，后缀添加 .bak。\n        \n        参数:\n            target: 要备份的目标文件路径\n            backup_run_dir: 本次运行的备份目录\n            \n        返回:\n            Path: 创建的备份文件路径\n        \"\"\"\n        # 获取文件相对于仓库根目录的路径\n        rel = target.relative_to(self.repo_root)\n        # 构建备份文件路径\n        backup_path = backup_run_dir / (str(rel) + \".bak\")\n        # 创建备份文件的父目录（如果不存在）","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/YYHDBL-HelloCodeAgentCli/code_agent/executors/apply_patch_executor.py#L203-L239","documentation":"Raised by _enforce_suffix when the target file has a non-empty suffix that is not in the executor's allowed_write_suffixes allowlist. This confines writes to known-safe text file types and blocks accidental edits to binaries, lockfiles, secrets, and config files. Files with no suffix at all (Makefile, Dockerfile) pass through.","triggerScenarios":"Patching a .env, .bin, .pem, .lock, or any extension not in allowed_write_suffixes; creating a new file with a disallowed extension via '*** Add File: '.","commonSituations":"Agent tries to edit package-lock.json, .env, or an image; a project policy allowlist that omits a legitimate extension (e.g. .md, .yaml) the team needs; generated patches referencing asset files.","solutions":["Change the patch to target an allowed text file, or split binary/asset edits out of the patch workflow.","If the extension is genuinely safe to edit, add it to the allowed_write_suffixes list when constructing the executor.","For extensionless files, confirm they pass (no suffix) rather than fighting the allowlist."],"exampleFix":"# before\nexecutor = ApplyPatchExecutor(repo_root=root)  # default allowlist\npatch targets 'config/secrets.env' -> PatchApplyError\n\n# after\nexecutor = ApplyPatchExecutor(\n    repo_root=root,\n    allowed_write_suffixes={'.py', '.md', '.txt', '.yaml', '.json'},\n)","handlingStrategy":"validation","validationCode":"ALLOWED = executor.allowed_write_suffixes\nfor kind, path, _ in executor._parse_patch(patch_text):\n    suffix = Path(path).suffix\n    if suffix and suffix not in ALLOWED:\n        raise ValueError(f'{path}: suffix {suffix} not in allowlist; edit an allowed file type')","typeGuard":"def suffix_allowed(path: str, allowed: set) -> bool:\n    s = Path(path).suffix\n    return (not s) or (s in allowed)","tryCatchPattern":"try:\n    executor.apply(patch)\nexcept PatchApplyError as e:\n    if 'Disallowed file suffix' in str(e):\n        drop_disallowed_files_from_patch_and_retry()\n    raise","preventionTips":["Configure allowed_write_suffixes explicitly at executor construction.","Instruct the agent never to patch binaries, lockfiles, or .env files.","Validate all patch target suffixes before apply()."],"tags":["patch","file-type","validation","apply-patch"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}