fix(s03,s04,s20): remove dead safe_path, sync READMEs

- Delete safe_path entirely (following PR #483 approach) — no dead code
- Update all 3 READMEs per module to reflect read_file in Gate 2
- s04: also update permission_hook snippet in READMEs
- s20: remove safe_path (already replaced with inline resolution)

Closes #482
This commit is contained in:
root
2026-07-28 19:29:01 +08:00
parent 97b8541b36
commit 581241cdc7
8 changed files with 7 additions and 25 deletions

View File

@@ -61,7 +61,7 @@ PERMISSION_RULES = [
{ {
"tools": ["read_file", "write_file", "edit_file"], "tools": ["read_file", "write_file", "edit_file"],
"check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR), "check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR),
"message": "Writing outside workspace", "message": "Access outside workspace",
}, },
{ {
"tools": ["bash"], "tools": ["bash"],

View File

@@ -61,7 +61,7 @@ PERMISSION_RULES = [
{ {
"tools": ["read_file", "write_file", "edit_file"], "tools": ["read_file", "write_file", "edit_file"],
"check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR), "check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR),
"message": "Writing outside workspace", "message": "Access outside workspace",
}, },
{ {
"tools": ["bash"], "tools": ["bash"],

View File

@@ -61,7 +61,7 @@ PERMISSION_RULES = [
{ {
"tools": ["read_file", "write_file", "edit_file"], "tools": ["read_file", "write_file", "edit_file"],
"check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR), "check": lambda args: not (WORKDIR / args.get("path", "")).resolve().is_relative_to(WORKDIR),
"message": "Writing outside workspace", "message": "Access outside workspace",
}, },
{ {
"tools": ["bash"], "tools": ["bash"],

View File

@@ -108,7 +108,7 @@ def permission_hook(block):
for pattern in DENY_LIST: for pattern in DENY_LIST:
if pattern in block.input.get("command", ""): if pattern in block.input.get("command", ""):
return "Permission denied by deny list" return "Permission denied by deny list"
if block.name in ("write_file", "edit_file"): if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "") path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR): if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
choice = input(" Allow? [y/N] ").strip().lower() choice = input(" Allow? [y/N] ").strip().lower()

View File

@@ -108,7 +108,7 @@ def permission_hook(block):
for pattern in DENY_LIST: for pattern in DENY_LIST:
if pattern in block.input.get("command", ""): if pattern in block.input.get("command", ""):
return "Permission denied by deny list" return "Permission denied by deny list"
if block.name in ("write_file", "edit_file"): if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "") path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR): if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
choice = input(" Allow? [y/N] ").strip().lower() choice = input(" Allow? [y/N] ").strip().lower()

View File

@@ -108,7 +108,7 @@ def permission_hook(block):
for pattern in DENY_LIST: for pattern in DENY_LIST:
if pattern in block.input.get("command", ""): if pattern in block.input.get("command", ""):
return "Permission denied by deny list" return "Permission denied by deny list"
if block.name in ("write_file", "edit_file"): if block.name in ("read_file", "write_file", "edit_file"):
path = block.input.get("path", "") path = block.input.get("path", "")
if not (WORKDIR / path).resolve().is_relative_to(WORKDIR): if not (WORKDIR / path).resolve().is_relative_to(WORKDIR):
choice = input(" Allow? [y/N] ").strip().lower() choice = input(" Allow? [y/N] ").strip().lower()

View File

@@ -75,17 +75,9 @@ SYSTEM = f"You are a coding agent at {WORKDIR}. Use tools to solve tasks. Act, d
# ═══════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════
# FROM s02-s03 (unchanged): Tool Implementations # FROM s02-s03 : Tool Implementations
# ═══════════════════════════════════════════════════════════ # ═══════════════════════════════════════════════════════════
def safe_path(p: str) -> Path:
"""Convert a string path to a resolved Path relative to WORKDIR.
NOTE: Path escape checking is now handled by permission_hook,
which asks the user for approval. safe_path only does str→Path conversion.
"""
return (WORKDIR / p).resolve()
def run_bash(command: str) -> str: def run_bash(command: str) -> str:
try: try:
r = subprocess.run(command, shell=True, cwd=WORKDIR, r = subprocess.run(command, shell=True, cwd=WORKDIR,

View File

@@ -376,16 +376,6 @@ def assemble_system_prompt(context: dict) -> str:
# ── Basic Tools ── # ── Basic Tools ──
def safe_path(p: str, cwd: Path = None) -> Path:
"""Convert a string path to a resolved Path relative to base.
NOTE: Path escape checking is now handled by permission_hook,
which asks the user for approval. safe_path only does str→Path conversion.
"""
base = cwd or WORKDIR
return (base / p).resolve()
def run_bash(command: str, cwd: Path = None, def run_bash(command: str, cwd: Path = None,
run_in_background: bool = False) -> str: run_in_background: bool = False) -> str:
# run_in_background is consumed by the dispatcher; direct execution ignores it. # run_in_background is consumed by the dispatcher; direct execution ignores it.