Skip to content

fix(ci): pin-resolver probes ancestry for reusable pins — orphan-pin class (#782) - #832

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/782-orphan-pin-ancestry
Sep 17, 2026
Merged

hyperpolymath merged 1 commit into
mainfrom
fix/782-orphan-pin-ancestry

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Closes #782 (detector + regression half).

The measured class

Estate census (435 repos × 4 reusable workflows, 31 distinct pin SHAs):

ancestor of main? SHAs alive rows dead rows
NO 7fdc2705 (squash-merge orphan), 892497fe (deleted unmerged branch), 46960521 (remote-branch-only), 5b1d0022 (non-object) 0 61
YES other 27 1,100 124

The orphan pins all return 200 from commits/<sha> — the old predicate passed them.

Fix (Defect 1 — the predicate)

Reusable-workflow pins (.github/workflows/*.yml@sha) now get a second server-side probe after commits 200: compare/<default>...<sha> —
behind|identical ⇒ consumable; ahead|diverged ⇒ determinate negative, new failure class NOT-ANCESTOR with remedy ("repin to the merge commit, never a PR head — a PR head orphans at squash-merge"). Indeterminate probes (default-branch fetch failure, compare 4xx/5xx) stay loud-UNVERIFIED, never verdicts. Action pins are not probed (fetched by object id at run time; non-default-branch action commits are legitimate) — with a suite case proving the compare endpoint is never even called for an action-only fixture.

Not in this PR, per the issue's disposition: the 61-row repin is owner-ordered; Defect 3's generator rule is already satisfied by scripts/apply-workflow-pins-remote.sh (validate_target accepts only identical|ahead from compare/<sha>...main — the mirror-image predicate); Defect 2's placement note (this gate runs inside governance-reusable.yml, inert when the host's own pin is fatal) is restated in the story — relocation is a separate governance decision.

Found during live validation: a SIGPIPE bug in the fix itself

api() had to start capturing response BODIES (for default_branch / compare status). My first cut isolated the code with printf | grep -q — under pipefail, grep exits on first match, printf dies on SIGPIPE for any body over the 64 KB pipe buffer, and the whole blob landed in $HTTP. Caught live: a 146 KB github/codeql-action compare body turned a healthy pin into a mysteriously-shaped UNVERIFIED row. Fixed with a builtin glob test; the suite now carries three >64 KB differential cases, and the piped-vs-builtin differential was run to prove they bite (piped: swallows pin as UNVERIFIED / builtin: correct verdict).

Validation

  • bash -n + full offline suite: 30/30 — the 4 witness SHAs with their measured verdicts, probe semantics, overreach guard, SIGPIPE cases
  • Live estate run on this repo: 24 unique pins, 9 reusable pins ancestry-probed OK, rc=0; the only UNVERIFIED is a pre-existing HTTP 301 (hyperpolymath/a2ml-ecosystem repo redirect), exactly as the old script reported
  • Diff: 2 files, +243/−15

Close-out per protocol on merge: evidence comment → close #782 completed → board → Done; detector docs ride in the script/test headers (no other doc references the gate).

…#782)

reachable != consumable. A reusable-workflow pin can name a REAL commit
object that GitHub still refuses to run: the resolver needs the commit to
be reachable from the repo's DEFAULT BRANCH. Estate census 2026-09 (435
repos x 4 reusable workflows): four such SHAs — 7fdc270 (squash-merge
orphan, PR head discarded at squash), 892497f (deleted unmerged branch),
4696052 (alive on a remote branch, not an ancestor of main), 5b1d002
(not an object) — account for 61 dead workflow-run rows with ZERO alive
rows, and this gate's existence predicate passed the first three.

Changes:

- Reusable-workflow pins (.github/workflows/*.yml@sha) now get a second,
  server-side probe after the commits-200: compare/<default>...<sha>.
  behind|identical => ancestor => consumable; ahead|diverged => NOT an
  ancestor => determinate negative, new failure class NOT-ANCESTOR with a
  remedy block ('repin to the merge commit, never a PR head'). An
  indeterminate probe (default-branch fetch, compare 4xx/5xx) is
  UNVERIFIED-loud, exactly like every other indeterminate answer.
- Ordinary action pins are deliberately NOT probed: actions are fetched
  by object id at run time and non-default-branch commits are a working
  pattern there. A suite case asserts the compare endpoint is never even
  hit for an action-only fixture.
- api() now also captures the response body (needed for default_branch
  and compare status). The newline test that isolates the code from the
  body is a BUILTIN — a printf | grep -q pipeline lets grep exit on the
  first match and kills printf with SIGPIPE under pipefail for any body
  over the 64 KB pipe buffer, smuggling the entire blob into $HTTP
  (caught live against the 146 KB codeql-action compare body; the
  gate silently soft-passed a real reusable pin).
- Regression suite, stub-driven and offline: the four witness SHAs with
  their measured compare verdicts, probe semantics (behind/identical
  pass; diverged/ahead fail; compare-403 and default-branch-404 are
  loud-indeterminate, never verdicts), action-pin overreach guard, and
  three >64 KB SIGPIPE differential cases. 30 cases, all green; the
  piped-vs-builtin differential confirms the SIGPIPE tests bite.

Out of scope per the issue's own disposition: the 61-row repin is
owner-ordered; the pin-writer (apply-workflow-pins-remote.sh) already
enforces the mirror-image rule (compare/<sha>...main must be
identical|ahead) so the generator half needs no change.

Refs #782
@coderabbitai

coderabbitai Bot commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 24 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 8d55f94f-a7eb-4712-bf64-be4fe2a2d7cf

📥 Commits

Reviewing files that changed from the base of the PR and between 61362e7 and f4b12e1.

📒 Files selected for processing (2)
  • scripts/check-action-pins-resolve.sh
  • scripts/tests/check-action-pins-resolve-test.sh

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant