fix(opencode): block recursive deletes and review decisions - #3676
Conversation
Signed-off-by: kerberosmansour <13433538+kerberosmansour@users.noreply.github.com>
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
PR Review Summary
Verdict: AI review comments are untrusted advisory output. The summary reports workflow-generated completion status only, not model-authored pass/fail claims. |
|
🟡 Contributor Check: MEDIUM
Automated check by AGT Contributor Check. |
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Imran Siddique (imran-siddique)
left a comment
There was a problem hiding this comment.
Tested the regex claim rather than reading it, because "this pattern cannot match as written" is worth confirming before it goes in a changelog. It is correct, and it is worse than the summary implies.
\brm\b[\s\S]*\b-rf\b matched nothing at all. \b before - requires a word-to-non-word transition, and in rm -rf / the character before the hyphen is a space, so non-word meets non-word and there is no boundary. Ten cases through both patterns:
command OLD NEW
rm -rf / False True
rm -fr / False True
rm -r -f / False True
rm --recursive --force / False True
rm --force --recursive / False True
rm -rf ./build False True
rm file.txt False False
rm -r /tmp/x False False
rm -f /tmp/x False False
confirm -rf thing False False
So the bundled default policy shipped a recursive-delete deny rule that never fired. For a governance toolkit that is the worst failure mode available: the control is present in the policy file, visible to anyone auditing it, and inert. Nothing downstream could have noticed, because a rule that never matches is indistinguishable from a rule whose condition is never met.
The new pattern holds on both sides. It catches combined, split and long-form flags in either order, and it does not match rm without both flags, or confirm -rf. Requiring recursive and force is a deliberate narrowing rather than an oversight, so rm -r /tmp/x still passes; that matches the rule's stated intent, and widening it is a separate policy decision rather than a bug fix.
The second half is a genuinely dead branch: return state.policy.mode === "advisory" ? "review" : "review" returns the same value either way. Given the adapter has no approval continuation, an enforce-mode review meant the call proceeded with nobody reviewing it, which reads as enforcement and is not. Returning deny there and keeping non-blocking review in advisory mode is the right split.
On #3251: agreed it is the maintainers' call to sequence, and flagging it rather than opening a third implementation is the right instinct. Worth noting it is currently sitting with fixes pushed after its last review, so it needs a maintainer look either way.
No approve bit on this repo, so a comment, but I would merge it.
Summary
rmflag forms are deniedreview, because the OpenCode adapter has no approval continuationreviewbehavior in advisory modeRoot cause
The regular expression treated
-rfas a word-boundary token, which cannot match as written. Separately, enforce-modereviewdecisions were allowed to continue even though the adapter cannot complete an approval flow.Validation
cd agent-governance-opencode && npm run check— 26/26 tests passedCloses #3662
Tracking and overlapping work