Like :meth:`ensure_allowed_path` but also permits harness-internal readable paths (tool-results / budget spill / scratchpad / memdir). The Read tool uses this so reading back the runtime's own spilled tool results — which sit outside ``workspace_root`` — does not raise. Mirr
(self, path: str | Path)
| 336 | raise ToolPermissionError(f"path is outside allowed working directories: {p} (allowed: {roots_str})") |
| 337 | |
| 338 | def ensure_readable_path(self, path: str | Path) -> Path: |
| 339 | """Like :meth:`ensure_allowed_path` but also permits harness-internal |
| 340 | readable paths (tool-results / budget spill / scratchpad / memdir). |
| 341 | |
| 342 | The Read tool uses this so reading back the runtime's own spilled tool |
| 343 | results — which sit outside ``workspace_root`` — does not raise. Mirrors |
| 344 | TS keeping ``checkReadableInternalPath`` separate from the write/cwd |
| 345 | allowlist; writes still go through :meth:`ensure_allowed_path`, so this |
| 346 | never widens write or ``cd`` scope. |
| 347 | """ |
| 348 | p = Path(path).expanduser() if isinstance(path, str) else path.expanduser() |
| 349 | if not p.is_absolute(): |
| 350 | base = self.cwd or self.workspace_root |
| 351 | p = (base / p).resolve() |
| 352 | else: |
| 353 | p = p.resolve() |
| 354 | mode = self.permission_context.mode |
| 355 | if mode == "bypassPermissions" or ( |
| 356 | mode == "plan" |
| 357 | and self.permission_context.is_bypass_permissions_mode_available |
| 358 | ): |
| 359 | return p |
| 360 | roots = self.allowed_roots() |
| 361 | if any(_is_within(p, root) for root in roots): |
| 362 | return p |
| 363 | # Harness-internal readable paths (spilled tool results, scratchpad, |
| 364 | # memory) are readable even though they sit outside the working roots. |
| 365 | from src.permissions.filesystem import check_readable_internal_path |
| 366 | |
| 367 | if check_readable_internal_path(str(p), self): |
| 368 | return p |
| 369 | roots_str = ", ".join(str(r) for r in roots) |
| 370 | raise ToolPermissionError( |
| 371 | f"path is outside allowed working directories: {p} (allowed: {roots_str})" |
| 372 | ) |
| 373 | |
| 374 | def ensure_tool_allowed(self, tool_name: str) -> None: |
| 375 | if self.permission_context.blocks(tool_name): |