Route allow-always through command authorization planner#80922
Route allow-always through command authorization planner#80922jesse-merhi wants to merge 65 commits into
Conversation
|
Codex review: found issues before merge. Reviewed July 3, 2026, 11:49 PM ET / 03:49 UTC. Summary PR surface: Source +2334, Tests +2944, Docs +8. Total +5286 across 36 files. Reproducibility: yes. from source inspection and live PR metadata: current main has the merged planner path while this PR is a conflicting older implementation of the same approval-planner direction. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Treat the merged Do we have a high-confidence way to reproduce the issue? Yes from source inspection and live PR metadata: current main has the merged planner path while this PR is a conflicting older implementation of the same approval-planner direction. Is this the best way to solve the issue? No. The submitted branch is no longer the best merge shape because the canonical implementation now lives in current main's Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 9d68f877ac3e. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +2334, Tests +2944, Docs +8. Total +5286 across 36 files. View PR surface stats
Security concerns:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
There was a problem hiding this comment.
Pull request overview
Introduces a new internal “command authorization planner” contract and a first-pass implementation that classifies commands into analyzable, prompt-only, or unanalyzable, producing a tree of command units suitable for downstream allowlist/trust evaluation.
Changes:
- Added planner contract types (
CommandAuthorizationPlan, units, tree relationships, and reason enums). - Implemented
planCommandForAuthorization()with dialect handling and conservative prompt-only detection (inline eval, command substitution, Windows wrappers). - Added a corpus-style Vitest suite covering representative argv/POSIX/Windows wrapper/malformed cases.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| src/infra/command-authorization/types.ts | Defines the planner contract types, tree structure, and reason enums. |
| src/infra/command-authorization/plan.ts | Implements the planner and unit/tree construction logic using existing exec-approvals analyzers. |
| src/infra/command-authorization/index.ts | Exposes the planner entrypoint and exported types. |
| src/infra/command-authorization/corpus.test.ts | Adds corpus tests to lock in planner behavior across common command shapes and risk cases. |
| const source = command ?? argvInput.join(" "); | ||
| const argv = argvInput.map((entry) => entry.trim()).filter((entry) => entry.length > 0); |
| const source = command.trim(); | ||
| if (!source) { | ||
| return unanalyzablePlan(command, "posix-shell", ["empty-command"]); | ||
| } |
| relationship: "wrapper-inline", | ||
| promptOnlyReasons: [reason], | ||
| }); | ||
| return promptOnlyPlan(command, dialect, { kind: "unit", unitId: unit.id }, [unit]); |
| if (executable === "cmd" || executable === "cmd.exe") { | ||
| return { dialect: "windows-cmd", reason: "unsupported-cmd-wrapper" }; | ||
| } | ||
| if (executable === "powershell" || executable === "powershell.exe" || executable === "pwsh") { |
| command: part.part, | ||
| cwd: context.cwd, | ||
| env: context.env, | ||
| platform: context.platform, |
| function unanalyzableFromAnalysis( | ||
| source: string, | ||
| dialect: CommandDialect, | ||
| analysis: ExecCommandAnalysis, | ||
| ): CommandAuthorizationPlan { | ||
| const reason: CommandUnanalyzableReason = | ||
| analysis.reason === "empty command" ? "empty-command" : "malformed-shell"; | ||
| return unanalyzablePlan(source, dialect, [reason]); |
eb63177 to
f95d24b
Compare
76666de to
68a9521
Compare
|
Thanks @jesse-merhi. Closing this older planner branch as superseded by #84172, which landed the current |
Summary
Real Behavior Proof
fnm exec --using 22.21.0 pnpm exec tsx -e '<planner allowlist proof>''/usr/bin/printf' 'hi' | '/usr/bin/wc' '-c'executed through/bin/sh -lcand returned2.sh -c 'echo ok'persisted/bin/echo; a latersh -c 'id > /tmp/openclaw-parser-proof-marker'still hadallowlistSatisfied: false.Manual Validation Screenshots
Tested the planner-backed
allow-alwaysflow through the local Discord approval path against this branch.Identical structured command reuse
echo PR80922_BASELINEwas approved withallow-always; the identical rerun executed without another approval.Changed command chain prompts separately
echo PR80922_A && echo PR80922_Bdid not broadly coverecho PR80922_A && touch /tmp/pr80922_changed_chain; the changed chain prompted separately.Inline eval prompts separately
python3 -c 'print("PR80922_INLINE")'did not broadly coverpython3 -c 'import os; print(os.getcwd())'; the changed inline payload prompted separately.Command carrier prompts separately
find ... -exec cat {} \;did not broadly coverfind ... -exec wc -c {} \;; the changed-execaction prompted separately.PowerShell was not covered in this local pass because the test machine is macOS-only.
Verification
fnm exec --using 22.21.0 pnpm test src/infra/command-authorization/corpus.test.ts src/infra/exec-approvals-analysis.test.ts src/infra/exec-approvals-allow-always.test.ts src/infra/exec-approvals-store.test.ts src/infra/exec-approvals-safe-bins.test.ts src/infra/command-analysis/explain.test.ts src/infra/command-analysis/explain.lazy.test.ts src/infra/exec-approvals-parity.test.ts src/agents/bash-tools.exec-host-gateway.test.ts src/node-host/invoke-system-run.test.tsfnm exec --using 22.21.0 pnpm tsgo:corefnm exec --using 22.21.0 pnpm tsgo:core:testfnm exec --using 22.21.0 pnpm check:changed