Extracted from pi-workspaces/memo-inbox/.pi/extensions/memo-guard.ts, which has enforced these patterns in production since 2026-07. Exports: - inside() / safeRealPath() / makePathResolver(): path containment that resolves symlinks before checking, so a link inside an allowed root cannot escape it - registerRestrictedRead(): a path-restricted 'read' that shadows the built-in. Required rather than optional: pi emits the skills block only when a tool named 'read' is active and skill bodies load through it, while the built-in 'read' accepts absolute paths and could reach the service's credential files - installGuard(): the two capability layers, setActiveTools plus a tool_call block, re-asserted on resources_discover as well as session_start - truncate(): byte-aware truncation ahead of pi's 50 KB / 2000 line caps - registerBridgeTools() / fetchBridgeSpecs(): loopback HTTP bridge, with the baseUrl asserted to be loopback. Since registerTool accepts a plain JSON Schema object, the backend can own the schema instead of a drifting copy Verified against a real pi process with zero model tokens (shared/extensions/tests/run-guard-checks.sh, 14 assertions): active tools are exactly the declared set, the read override wins with source=cli, the skills section is present and contains only the scenario's own skill, and reads of an outside file, a ../ traversal and an absolute path to ~/.config/curator/curator.env are all denied. The deny-path fixture is named .txt and renamed to .env only inside the temp work directory, because verify-no-secrets.sh correctly refused to track a file called *.env.sample.
2 lines
25 B
Plaintext
2 lines
25 B
Plaintext
SHOULD_NOT_BE_READABLE=1
|