Skip to content

Verify read-only, workspace-contained commands before LOW auto-run - #21

Merged
lavindeep merged 4 commits into
mainfrom
fix/command-policy-low-invariant
Jul 10, 2026
Merged

Verify read-only, workspace-contained commands before LOW auto-run#21
lavindeep merged 4 commits into
mainfrom
fix/command-policy-low-invariant

Conversation

@lavindeep

@lavindeep lavindeep commented Jul 10, 2026

Copy link
Copy Markdown
Owner

Summary

Tighten the deterministic command classifier's LOW criteria under the balanced profile. A command now runs without approval only when its exact argv form is verified to be read-only, workspace-contained, and free of external-helper execution — LOW is established per option, not inferred from the executable basename. Before a command classifies LOW, the policy must confirm its argv cannot execute helpers, write or truncate files, perform network I/O, or read outside the workspace boundary.

Per-tool checks now enforce that requirement; forms the policy cannot verify are classified MEDIUM or HIGH, which routes them through the standard approval prompt:

  • Searchers (grep / egrep / fgrep / rg)--pre / --pre-glob preprocessor options classify HIGH (they run a configured program over matched files); unrecognized long options classify MEDIUM; path operands resolving outside the workspace classify HIGH.
  • Git read-only verbs--ext-diff / --textconv classify MEDIUM (they invoke configured external helpers); git diff --no-index with paths resolving outside the workspace classifies HIGH.
  • tree — output-writing forms (-o / --output, -R, clustered -ao) classify MEDIUM, or HIGH when the output path is outside the workspace; unrecognized long options classify MEDIUM; out-of-workspace operands classify HIGH.
  • ps — forms that display process environments (e, -E, -o environ, --format=…,env, including clustered auxe) classify MEDIUM; unrecognized long options classify MEDIUM.
  • ls — unrecognized long options classify MEDIUM; path operands resolving outside the workspace classify HIGH.
  • date — file-backed reads via -r / -f / --file / --reference (split, =-attached, glued, and clustered forms) classify HIGH outside the workspace and MEDIUM inside it.

Everyday read-only forms still classify LOW and run without a prompt: plain searches, git diff --stat, tree -L 2, ps aux, ls -la, and bare date.

Behavior change

ls ../ now classifies HIGH — its path operand resolves outside the workspace — rather than LOW; its regression expectation is updated accordingly. A new parametrized regression corpus in test_command_policy.py pins each classification above, alongside the everyday forms that must keep running without a prompt.

Testing

  • pytest tests/test_command_policy.py tests/test_approvals.py tests/test_run_command.py
  • ruff check / ruff format --check on touched files
  • mypy shellpilot/policy/command_policy.py --strict
  • CI green on Python 3.11 and 3.14.

…sses.

Require capability-bearing LOW tools to prove they cannot execute helpers, write files, or read outside the workspace, with an adversarial regression corpus for the previously auto-run cases.
Escalate tree -R and clustered -o writes, path-check date file reads, and treat ps format env/environ columns as environment exposure.
Parse -r/-f path operands in split, glued, and clustered forms so out-of-workspace date reads cannot auto-run.
@lavindeep lavindeep changed the title Harden LOW command policy against auto-run bypasses Require capability proof before LOW auto-run in command policy Jul 10, 2026
@lavindeep lavindeep changed the title Require capability proof before LOW auto-run in command policy Require capability proof before a command auto-runs as LOW Jul 10, 2026
@lavindeep lavindeep changed the title Require capability proof before a command auto-runs as LOW Verify read-only, workspace-contained commands before LOW auto-run Jul 10, 2026
Extend DESIGN.md 36.1 to cover the LOW-invariant hardening: searcher
preprocessor and unrecognized-option escalation with the out-of-workspace
operand check, read-only git verb external-helper and no-index boundary
escalation, tree output-writing forms, ps environment-display forms, the
ls boundary check, and date file-backed reads across split, =, glued, and
clustered forms. Correct the now-false "Accepted residual" paragraph: the
date/tree/ps glued and clustered forms are closed, leaving only the searcher
glued pattern-file form (grep -f/etc/passwd) as the documented LOW residual.
Add the matching residual note to the command_policy module docstring so the
code and spec agree.
@lavindeep
lavindeep force-pushed the fix/command-policy-low-invariant branch from d879a6d to 71273f3 Compare July 10, 2026 12:23
@lavindeep
lavindeep merged commit 10e5048 into main Jul 10, 2026
2 checks passed
@lavindeep
lavindeep deleted the fix/command-policy-low-invariant branch July 10, 2026 12:30
Repository owner deleted a comment from cursor Bot Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant