Harden ob1-gate.yml against gate-bypass holes#2
Merged
Conversation
Fix four pre-existing weaknesses that defeated the PR gate's blocking
guarantee:
1. HIGH shell injection: PR title was interpolated raw via ${{ }} inside
run: blocks (review + artifact steps). A crafted title could execute
arbitrary shell in the runner and force failed=false. All untrusted
PR-controlled values now pass through env: and are referenced as
quoted shell variables.
2. HIGH [docs] bypass: any "[docs] ..." title exited 0 before any check
ran, skipping the credential and binary scans regardless of changed
files. Skip decision is now based solely on the actual changed-file
list (no contribution folders touched), and the credential + binary
scans always run and still block.
3. MEDIUM shallow fetch: base was fetched with --depth=1, which could
lose the merge base and silently under-report changes. Base is now
fetched in full, the diff fails closed (no last-commit-only fallback),
and the merge base is verified.
4. LOW Rule 6 counting bug: grep -c || echo "0" could emit "0\n0" and
break the integer comparison, letting empty recipes pass. Fixed with
grep -c || true plus a default.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OB1 PR GateThis PR does not touch contribution folders (docs/governance change). Contribution checks were skipped, but credential and binary-file scans still ran. ✅ No credentials — No API keys, tokens, or secrets detected Result: All 2 security scans passed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR #1 added a
ready_for_reviewtrigger to the OB1 PR gate and assessed that "the gate already blocks." An adversarial review found pre-existing holes inob1-gate.ymlthat defeat that blocking guarantee. This PR fixes them. No other file is touched.Fixes
PR_TITLE="${{ github.event.pull_request.title }}"(and the same raw interpolation of title/number/login/sha in the artifact step) was substituted into therun:script body before the shell parsed it.$(...), backticks, or"; echo "failed=false" >> $GITHUB_OUTPUT; #) executed arbitrary shell in the runner and could force the gate green.env:and referenced as quoted shell variables. The title is now inert data; injection payloads do not execute.[docs]title bypass. The skip decision keyed off the PR title prefix^\[docs\].[docs] ...hitexit 0before any check ran, including the credential scan and binary-blob check — regardless of which files were actually changed. A secret could be merged under a[docs]title.failed=trueto block. The title is no longer authoritative for skipping anything.--depth=1; the diff usedorigin/main...HEADwith a silent fallback toHEAD~1 HEAD.mainhad advanced, the merge base could be lost and the fallback diffed only the last commit of a multi-commit PR, so checks under-reported the changed files.fetch-depth: 0on checkout, full base fetch (no--depth), merge base verified withgit merge-base, and the diff has no last-commit-only fallback — it fails closed if the diff cannot be computed.Note on check count
This PR does not change it, but for the record: Rule 11 (LLM clarity review) is a hardcoded pass stub — it calls
pass_checkunconditionally and defers the actual review to a separateclaude-review.ymlworkflow. So the advertised "15 checks" are effectively 14 enforceable within this gate.Verification
SC2086quote-$GITHUB_OUTPUTinfos) were fixed by quoting"$GITHUB_OUTPUT"throughout. Remaining findings (SC2001,SC2034,SC2129style/info) are all pre-existing and untouched by this PR.bash -non every extractedrun:script: all pass (exit 0).[docs]-titled PR containing a leakedghp_…token in a changed.md→ nowfailed=true(was: all checks skipped, passed).docs/note.md, no contribution dirs) → passes (convenience preserved).$(touch /tmp/pwned)/ backtick /"; echo failed=false >> $GITHUB_OUTPUTpayloads → no file created, no injection executed, title treated as literal data.docs/with a[docs]title →failed=true(binary scan now runs in the docs path).Fail if checks failedstep (exit 1whenfailed == 'true'); the[docs]convenience is preserved for genuine docs-only PRs.🤖 Generated with Claude Code