wip(guardrails): wrapper-argv resolver for the env -S / sudo / -C fail-open family - #1864
wip(guardrails): wrapper-argv resolver for the env -S / sudo / -C fail-open family#1864kyle-sexton wants to merge 6 commits into
Conversation
…tils Work-in-progress save before machine wind-down. The wrapper-argv resolver closing the #1814/#1811/#1810 fail-open family (env -S restart bypass, sudo option-cluster peeling, whole-argv effective_dir) implemented in lib/hook-utils.sh with tests, and propagated to every plugin's vendored hooks/hook-utils.sh copy with per-plugin version bumps and CHANGELOG entries. Convention suite was green (36/0) before the stop; the remaining suites, the unfixed-hook evidence for the #1810 rows, and the decision comment on #1814 are NOT yet done — see the draft PR body for exact state. Refs #1814 #1811 #1810 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RhS3T7ShwJgKTrvk2Mvd3C
Brings the wrapper-argv resolver branch current with main (c308e57), which shipped the OS-temp-tree project-membership fix (#1769) and re-synced every vendored hook-utils.sh with per-plugin version bumps. Resolutions: - lib/hook-utils.sh and all 16 vendored hooks/hook-utils.sh copies auto-merged: main's hook::under_temp_root plus the hook::read_file_path temp exemption sit in a different region from this branch's git_resolve_index / git_effective_dir work, so both sides compose. All 16 vendored copies verified byte-identical to lib/hook-utils.sh, which is the sync contract this branch and main both assert. - plugins/*/CHANGELOG.md: main's file structure is kept verbatim -- including its relocation of the "predate this file" preamble to directly under the header -- and this branch's entry is re-inserted above main's newest entry under its newly allocated version. Verified as a pure insertion over main for all 16. - plugins/*/.claude-plugin/plugin.json: both sides bumped every plugin from the merge base, so all 16 version claims collided; seven collided exactly (actionlint 0.7.7, biome-format 0.5.8, desktop-notification 0.5.9, eol-normalizer 0.5.8, go-format 0.2.8, powershell-format 0.6.5, ruff-format 0.5.8) and would otherwise have re-claimed a number main has already published with different content. Each manifest is main's, with the version line alone advanced past main's shipped version. autonomy takes the centrally allocated 0.12.3 (0.12.2 is claimed by docs/fixbatch-goal-budget-cap). The other fifteen are provisional pending central allocation and are the reason this branch is not yet pushed. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Brings the branch current with 1e08c6a. Only claude-ops conflicted: main's #1945 shipped claude-ops 0.27.1, the number this branch had taken, so the two 0.27.1 entries collided. Resolved the same way as the first merge -- main's CHANGELOG structure kept verbatim, this branch's entry re-inserted above main's newest under 0.27.2, and the manifest is main's with the version line alone advanced. An equal version is invisible to check-changelog-parity --check-bump (an unchanged version reads as "not bumped", so the entry check is skipped), so the collision was caught by comparing every plugin's version against main's directly rather than by the gate. The other fifteen remain strictly greater than main. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 4m 42s —— View job Security Review — PR #1864 (wrapper-argv resolver)Task list
ScopeReviewed the diff against FindingsIMPORTANT —
block-convention-violation.sh#L268 This deliberately folds rc 1 (not-git) and rc 2 (the resolver's new fail-closed refusal — an unparseable wrapper prefix, e.g. That assumption breaks under a configuration the plugin explicitly documents and supports: each of the twelve guards, including these two, is "independently toggleable" ( Failure scenario: a user/team runs with The Confidence: High that the coupling exists and is exploitable exactly as designed; the plugin's own README/plugin.json confirm the "independently toggleable" contract that the implicit cross-process dependency violates. Whether this is accepted risk (WIP PR's own body already flags "verification is incomplete") is a product decision, but it's currently undocumented at the code site making the assumption. Other areas reviewed, no issues found
Per this lane's scope, unpinned-action/supply-chain risk, dangerous trigger patterns, and template injection are deferred to zizmor's static advisory lane and not re-reported here (none applicable — no workflow files changed anyway). |
Branch refreshed against main — version allocation needs adjudicationBrought current with Why this needed 16 version decisions, not oneThis branch bumps every plugin that vendors Every number below is now strictly greater than what main has shipped.
Only The claude-ops collision is why that mattersMid-refresh, main merged #1945, which shipped
Conflict resolution
Gates
Still a draftThe refresh did not touch the test plan in the PR body. The remaining per-guard suites, the unfixed-hook evidence for the #1810 rows, the delegated-authority decision comment on #1814, and an independent review of the resolver logic itself are all still open. "Gates green" here means the merge is clean and the versions are consistent — not that this is ready to merge. |
Thirteen of the sixteen provisional numbers already matched. Three move up to clear versions claimed by open pull requests that "next patch above main" could not see: bash-format 0.6.11 -> 0.6.12 (#1867 claims 0.6.11) rate-limit-guard 0.4.1 -> 0.4.2 (#1866 claims 0.4.1) source-control 0.45.2 -> 0.46.1 (#1830 claims 0.46.0) Manifest and CHANGELOG heading move together; each entry keeps its position above that plugin's newest shipped entry, and all sixteen remain strictly greater than main. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Brings the branch current with a2a526a. One conflict: main shipped autonomy 0.12.2 via #1960, so this branch's entry had to be re-seated above it. Resolved as every earlier conflict here was -- main's CHANGELOG structure kept verbatim, this branch's entry re-inserted on top, manifest taken from main with the version line alone advanced. The centrally allocated 0.12.3 is unchanged and still clears main: 0.12.2 was held by docs/fixbatch-goal-budget-cap, which has now landed, which is exactly what the allocation anticipated. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 2m 52s —— View job Security Review — PR #1864 (wrapper-argv resolver)Task list
ScopeThis is a re-review after the branch was refreshed against FindingsIMPORTANT — block-convention-violation.sh#L268 Unchanged from the prior pass. block-dangerous-git.sh#L438-L450, block-no-verify.sh#L141-L153, block-noncanonical-commit.sh#L538-L551 — each carrying the comment "per-hook kill switches mean no guard may delegate its fail-closed posture [to a sibling]".
That written rationale directly contradicts the sibling guards' own stated invariant in the same commit ("no guard may delegate its fail-closed posture"), and contradicts the plugin's shipped contract that all twelve guards, including these two, are independently toggleable with separate kill switches — Failure scenario, unchanged: a config with No test in Confidence: High that the coupling exists and is exploitable exactly as designed and now explicitly documented as accepted, rather than fixed. Whether that's the intended resolution is a product call for the maintainer — the PR body itself still says "verification is incomplete" — but the CHANGELOG language asserting this is "per its existing rule" reads as treating a known gap as settled when the sibling guards' own new comments argue against that resting position. Other areas reviewed, no issues found
Per this lane's scope, unpinned-action/supply-chain risk, dangerous trigger patterns, and template injection are deferred to zizmor's static advisory lane (not applicable anyway — no workflow files changed). |
Version allocation resolved — supersedes the provisional table aboveAll sixteen numbers are now centrally allocated, verified against every open PR's actual head claim. Head is Thirteen of my provisional numbers were confirmed unchanged. Three moved up to clear versions held by open PRs that a "next patch above main" rule could not see:
Final allocation: actionlint 0.7.8 · autonomy 0.12.3 · bash-format 0.6.12 · biome-format 0.5.9 · claude-ops 0.27.2 · context-guard 0.4.6 · desktop-notification 0.5.10 · eol-normalizer 0.5.9 · go-format 0.2.9 · guardrails 0.19.1 · markdown-format 0.9.1 · powershell-format 0.6.6 · rate-limit-guard 0.4.2 · ruff-format 0.5.9 · source-control 0.46.1 · typos-format 0.5.1.
Brought current through two more merges ( An independent fresh-context verifier, rationale withheld and read-only, passed exact-allocation match, changelog ordering, survival of the resolver delta (all 16 vendored copies byte-identical to Still a draft — the PR's own test plan is untouched by this refresh. |
|
Status note (2026-08-09 board sweep): this draft is the standing WIP artifact for the wrapper-argv fail-open family — issues #1814, #1811, #1810 remain the durable record, and this branch holds the in-progress resolver. Deliberately open-as-draft, not orphaned; it graduates to ready when the resolver covers the env -S / sudo / -C family with tests, or closes if that work restarts fresh. |
|
Closing superseded WIP — the wrapper-argv resolver work landed on Evidence: #1814's |
Summary
DRAFT — work-in-progress save from an autonomous lane stopped at operator wind-down. Refs #1814. Refs #1811. Refs #1810. (Refs, not Fixes: verification is incomplete; a partial merge must not close the security family.)
Implements the wrapper-argv resolver closing the guardrails fail-open family:
env -Srestart bypass (#1814, critical), sudo option-cluster peeling losing the wrapper chdir (#1811), andblock-convention-violationpassing whole argv toeffective_dirso a wrapper's-Chides a persisted alias (#1810). Implemented inlib/hook-utils.shwith tests and propagated to every plugin's vendoredhooks/hook-utils.shwith per-plugin version bumps and CHANGELOG entries (56 files, +2829/-457).State at stop
env -S '-i git commit -m x'bypasses every git guard (fail-open, shared with main) #1814, an independent fresh-context review, and the full repo gate battery (changelog parity x3, check-changed-skills, shellcheck across all vendored copies, portability gates).Test plan
env -S '-i git commit -m x',sudo -bD <dir> git ..., wrapper-Calias-hiding, plus adversarial variantsRelated
No linked issue closed by this draft. Refs #1814 #1811 #1810. Resume context: this body + the three issue threads carry everything a cold agent needs; local worktree claude-code-plugins-issue-1814.