Repository navigation
fix(ci): read ci-status hold config from the default branch's tip at run time - #11106
Conversation
…run time A re-run replays the event payload, so pull_request.base.sha stays stale and a hold-policy switch merged to main later (merge.diff-check.path-holds, merge.trust-path-hold-apps) never reached an open pull request until a new event arrived. A new hold_ref step resolves the hold-config commit: for a pull request into the default branch it reads the branch tip with an unauthenticated git ls-remote of the public repository, run outside any checkout, and validates it as 40 hex; any other base and a merge group keep the event's base SHA, and a failed or malformed read falls back to it with a warning. base_config checks out that SHA and skips when hold_ref outputs none, so an empty ref can never check out the pull request's own merge commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-security-review reviewed No security issues found in this pull request. I read the whole diff. It changes the What the change does. A new Who can change the config source.
Injection and parsing.
Failure modes.
critical-findings: 0 Spend: no paid resources or billing settings change. The step adds one unauthenticated |
|
claude-review reviewed No blocking or advisory findings. I read all 5 changed files in the diff and the PR context. I ran nothing, and the PR's pass counts (PASS=74 FAIL=0) are the author's claim, not something I confirmed. What the change does. A new Checks that held up:
Not blocking:
Cost: none. The change adds one No manifest items are hit. |
No related issue: GitHub Support proposal, switch flips reach open PRs
Summary
ci-status's hold steps read their config (pr-pipeline.yaml, the trusted-actor list, the tracker config, merge-holds.mjs and its siblings) from a sparse checkout at
github.event.pull_request.base.sha. A re-run replays the event payload, so that SHA stays stale: a policy switch merged to main later, such asmerge.diff-check.path-holdsormerge.trust-path-hold-apps, never reached an open pull request until a new event with a newer base arrived. #11072, #10919, #10973 and #10983 hit this.Fix
hold_ref("Resolve the hold config's commit"), sameif:asbase_config. For apull_requestevent whose base ref is the repository's default branch, it reads the branch tip with an unauthenticatedgit ls-remote https://github.com/$GITHUB_REPOSITORY refs/heads/<default>, run from$RUNNER_TEMP(outside any checkout) underGIT_TERMINAL_PROMPT=0and a 60 s timeout. It keeps only the line whose ref is exactlyrefs/heads/<default>and requires 40 hex. Any other base, and a merge group, keep the event's base SHA. A failed or malformed read falls back to the base SHA with a::warning::naming the fallback. Every event value comes throughenv.base_configchecks out${{ steps.hold_ref.outputs.sha }}, still a 40-hex SHA, so actions/checkout still skips its API calls. Itsif:also requires that output to be non-empty: with an emptyref, checkout falls back to the event's ref, the pull request's own merge commit.hold_refexits 1 without an output when the event's base SHA is not 40 hex, so the checkout skips and the hold steps fail closed on an emptyBASE_CONFIG, as they already do.BASE_CONFIGnow say the config is the default branch's tip at run time, or the base commit for another base. The safety argument stands: no pull request code is checked out, and a PR head cannot change main.hold_patternsblock (chore(pr-pipeline): turn off the agent App trust-path and exempt-author path holds #11068) is untouched.Verification
scripts/ci-hold-human-gated.test.shnow pins the checkout'sref:tohold_refand its non-empty guard. It also runshold_ref's body against a stubgitin eight cases: default-branch tip, another base, merge group, ls-remote failure, non-hex answer, tail-matching decoy ref, decoy plus exact ref, and a non-SHA base. Before the workflow change: PASS=56 FAIL=18. After: PASS=74 FAIL=0.scripts/*.test.shscoped to this workflow pass, including the four whose message pins changed.actionlintclean;zizmor --offlineno findings;scripts/check-lane-coverage.sh --checkpasses.hold_refhas nocontinue-on-error, so it needs no opt-out entry.Related
🤖 Generated with Claude Code