Record the commit the job actually checked out, not GITHUB_SHA - #255
Conversation
The run's revision came from GITHUB_SHA, which is fixed when the workflow run starts. A job that checks out a different ref therefore labelled the run with a commit it did not build: a reusable workflow called with a freshly rebased commit, a workflow_run handler, an explicit `ref:` on actions/checkout. Downstream tooling that compares the run's revision with the branch head then reads a healthy run as stale. Seen on savantenvs/delta (2026-09-20): the weekly sync rebased `mayhem` to 6ac2067, called mayhem.yml with that ref, the fuzz job checked out and built commit-6ac2067, and the Mayhem run recorded 4b79bc9 — the pre-rebase head the cron started from. Revision now resolves, in order of trust: an explicit `revision` input; the pull request head on pull_request events (unchanged, the checkout there is the merge commit); the commit checked out under `package` (`git rev-parse HEAD`); GITHUB_SHA. The source is logged. A new optional `revision` input lets a workflow override it. Behaviour is unchanged for push events and pull requests, where the checkout and GITHUB_SHA agree. __tests__/revision.test.ts pins the precedence and the git lookup; dist rebuilt with ncc. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Mayhem Automated Code Testing Passed! ✔️ ✔️✔️ 🎆 0 Defects FoundTesting details found at https://app.mayhem.security/forallsecure/mcode-action/lighttpd/172 |
…ITHUB_SHA Dispatch-only (it starts a real Mayhem run): check out the dispatched ref's parent into a second checkout, run the action against it, then read the run back from the Mayhem API and assert its revision is that parent — different from GITHUB_SHA. This is the reusable-workflow case where the fuzzed commit is not the one the workflow run started from. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A workflow that exists only on a branch cannot be dispatched; main.yml can, and runs the branch's copy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Tried on a real run now. Added a dispatch-only CI job ( Run 35633403754, branch Before this change the same job would have recorded Not yet exercised on a fleet fork; the first weekly sync after the Bump after merge: |
d-dot-one
left a comment
There was a problem hiding this comment.
If you're OK with the 1 comment, I'm OK with this PR :)
| export function checkedOutRevision(cwd: string): string | undefined { | ||
| try { | ||
| const out = execFileSync("git", ["rev-parse", "HEAD"], { | ||
| cwd, | ||
| stdio: ["ignore", "pipe", "ignore"], | ||
| }) | ||
| .toString() | ||
| .trim(); | ||
| return /^[0-9a-f]{40}$/.test(out) ? out : undefined; | ||
| } catch { | ||
| return undefined; |
There was a problem hiding this comment.
This func silently swallows all git errors. Having the catch {return undefined} combined with stdio: [ignore, pipe, ignore] is basically equivalent to "no checkout present" and falls through to GITHUB_SHA with a normal log entry. The problem this PR is trying to solve is most likely to hit this
There was a problem hiding this comment.
Agreed, a silent fallback there hides exactly the case this PR is for. Changed:
checkedOutRevisionnow returns{sha}or{error}, with git's own stderr in the error (stdiocaptures it instead of discarding it). Still never throws.getConfig()emits a workflow warning whenever the revision ends up asGITHUB_SHAbecause the checkout could not be read, naming the cause and pointing at therevisioninput as the override. So a job that builds a different commit but has no readable checkout is flagged in the run summary, not just in a log line.- Explicit
revisioninput and the pull-request head path are unchanged (no warning: those are deliberate choices, not fallbacks).
Tests updated to assert the error text for a non-git directory and a missing path (the test update landed one commit after the source change; both are on the branch now), npm run all clean, 9/9.
… read
Review (d-dot-one): checkedOutRevision swallowed every git error and returned undefined, so a
failed lookup fell through to GITHUB_SHA with an ordinary log line — the exact wrong-label case
this change exists to fix, hidden. It now returns {sha} or {error} with git's own stderr, and
getConfig() emits a workflow warning naming the cause whenever the revision ends up coming from
GITHUB_SHA because of it, pointing at the `revision` input as the override. Explicit input and
pull-request head are unaffected.
Tests cover the error text for a non-git directory and a missing path.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
sauliusbc
left a comment
There was a problem hiding this comment.
This adds quite a lot of changes, which I cannot verify wouldn't break every existing use of this action if still is shipped with @v1.
I would rather recommend just doing a simple additive behavioral change where:
revisioninput is added (like in this PR)revisionis first value to be considered at line 105, i.e.
revision: getInput("revision")
|| seventPullRequest
? eventPullRequest.head.sha
: process.env["GITHUB_SHA"] || "unknown",
- Savantenvs migrated en-masse to pass-in
revisioninput to mcode-action
Ticket: PE-8976 (assumed: the commit-id half of the pair; PE-8975 is the org stamps)
Problem
The run's
--revisionis taken fromGITHUB_SHA, which is fixed when the workflow run starts. A job that checks out a different ref labels the Mayhem run with a commit it did not build. That happens for every reusable workflow called with a freshly rebased commit, forworkflow_runhandlers, and for any explicitref:onactions/checkout.Concrete case, savantenvs/delta on 2026-09-20 (Actions run 35507899158, a scheduled
sync.yml):GITHUB_SHA(sync cron started from)4b79bc9sync.ymlrebasedmayhemto, and passed asref:6ac2067commit-6ac20676ac2067revision4b79bc9The rlenv gate compares a run's revision with the fork's
mayhemHEAD, so it read this healthy run as stale and demoted the repo. 109 repos in that fleet hit the same thing this week; in a sample of 45, 41 had their latest run started by the sync cron.Change
src/revision.ts:resolveRevision()picks, in order of trust,revisioninput (new, optional),pull_requestevents (unchanged: that checkout is the merge commit, and the run should link to the branch head),package(git rev-parse HEAD, never throws),GITHUB_SHA.The chosen source is logged (
Revision: <sha> (from checked-out HEAD).). Behaviour is identical for plain push events and pull requests, where the checkout andGITHUB_SHAagree.action.ymland the README document the new input.dist/rebuilt withncc.Testing
__tests__/revision.test.ts: 8 cases for the precedence and the git lookup (real checkout, a non-git dir, a missing dir).npm run all(build, format, lint, package, jest): clean; the existingmain.test.tsstill passes (9/9 total).sync.ymlon a fork whose upstream moved and confirm the Mayhem run's revision equals the rebasedmayhemHEAD.Rollout
Every rlenv fork pins
ForAllSecure/mcode-action@v1, so once this ships in a v1.0.x release and thev1tag moves, all forks pick it up on their next run without per-fork changes. Existing runs keep their old label until a new run lands.🤖 Generated with Claude Code