Problem
The approval gate treats an empty candidate list as proof that every shell candidate is approval-exempt.
The empty list has two possible causes:
- The matcher extracted candidates, and every candidate is a pure side effect.
- The matcher could not extract any candidate.
Only the first case can run without approval.
A parser rejection can return no candidates while the legacy messy-command scan returns false. The approval-required policy can then allow the command automatically.
This behavior exists on dev. PR #1745 only makes the decision visible through ApprovalExemptShellCandidates.
Related review: #1745 (comment)
Required change
- Require at least one extracted candidate before the pure-side-effect exemption applies.
- Return
RequiresApproval when the matcher extracts no candidates.
- Preserve the exemption for commands such as
echo observable, printf, :, true, and false.
- Keep parser failures fail-closed.
Test proof
Add evaluator tests that prove:
- An empty shell command does not receive
ApprovalExemptShellCandidates.
- A parser-rejected command returns
RequiresApproval.
- A nonempty set of pure-side-effect candidates remains allowed.
- The tool does not execute during authorization evaluation.
Implement this fix immediately after PR #1745 merges.
Problem
The approval gate treats an empty candidate list as proof that every shell candidate is approval-exempt.
The empty list has two possible causes:
Only the first case can run without approval.
A parser rejection can return no candidates while the legacy messy-command scan returns false. The approval-required policy can then allow the command automatically.
This behavior exists on
dev. PR #1745 only makes the decision visible throughApprovalExemptShellCandidates.Related review: #1745 (comment)
Required change
RequiresApprovalwhen the matcher extracts no candidates.echo observable,printf,:,true, andfalse.Test proof
Add evaluator tests that prove:
ApprovalExemptShellCandidates.RequiresApproval.Implement this fix immediately after PR #1745 merges.