Skip to content

fix(bump-callers): target the github-workflows pin token and assert both pins moved (BE-4662)#79

Open
mattmillerai wants to merge 2 commits into
matt/groom-max-prs-reusablefrom
matt/be-4662-bump-callers-precise-pin
Open

fix(bump-callers): target the github-workflows pin token and assert both pins moved (BE-4662)#79
mattmillerai wants to merge 2 commits into
matt/groom-max-prs-reusablefrom
matt/be-4662-bump-callers-precise-pin

Conversation

@mattmillerai

Copy link
Copy Markdown
Contributor

STACKED — merging lands on matt/groom-max-prs-reusable (owned by @mattmillerai, PR #77), NOT main. This PR's base is #77's branch because #77 rewrites the same sed block; basing on main would conflict with it and silently drop its # main @ pin-comment rules. GitHub retargets this PR to main once #77 merges. Review the net diff, not the merge button.

ELI-5

When one of this repo's reusable workflows changes, a bot opens a "bump the pin" PR in every repo that uses it. A repo pins us in two places: the uses: line and a workflows_ref: input that loads our prompts/briefs/scripts at run time. Both have to point at the same commit, or the run uses one version's workflow with another version's briefs.

The bot used to find those pins by looking for "any 40-character hex string on a line that mentions github-workflows." That's the wrong thing to look for, and it never checked its own work. So if a repo pinned workflows_ref: v1 (a tag, not 40 hex), the bot bumped the uses: line, left the tag alone, and happily opened a green-looking PR that splits the caller. And if some unrelated 40-hex value happened to sit on a line that mentioned github-workflows, the bot overwrote it.

Now the bot looks for the pin tokenComfy-Org/github-workflows…@ and the workflows_ref: key — and takes whatever comes right after it, whatever shape it is. Then, before it stages anything, it re-reads the file and checks that every pin really did move. If one didn't, it says so out loud and fails that repo instead of opening a half-bumped PR.

What changed

  • The rewrite targets the pin token, not 40-hex-ness. Two patterns matched by position: Comfy-Org/github-workflows[^@\s]*@<ref> and workflows_ref: <ref> (optionally quoted). Whatever sits right after the token is the ref, so a full sha, a short sha, or a tag all move — and an unrelated SHA sharing the line is unreachable.
  • The workflows_ref rule is ^-anchored to a block-mapping key, so a prose comment mentioning the input (# workflows_ref: keep in sync with uses:) is not rewritten into a sentence with a SHA spliced through it.
  • A post-rewrite assertion gates staging. The file is re-read with a deliberately broader reader (any non-whitespace value sitting where a ref belongs, comments excluded); if anything but the new SHA is still there, it emits a ::warning:: naming the file and the stale value and fails that repo. Same posture line 203 already takes for a transient fetch error — a partial bump is worse than no bump (BE-3896). Nothing is written to the caller repo before this point (all API writes are in Pass 2), so the failure is genuinely all-or-nothing.
  • A dedicated rule for the full-sha # main @ <40hex> pin comment. That comment used to be corrected as collateral of the old line-scoped 40-hex substitution. With the substitution now precise, it needs its own rule or it would be left naming the old commit — a regression against feat(groom): own the max_prs dispatch override in the reusable + add the groom caller fleet (BE-4346) #77's intent. Verified by deleting the rule and watching feat(groom): own the max_prs dispatch override in the reusable + add the groom caller fleet (BE-4346) #77's groom case go red (2 failures).
  • Doc sync: .github/bump-callers/README.md gains a "How the pin rewrite is scoped" section; bump-groom-callers.yml's header no longer describes the old line-keying.

Tests

.github/bump-callers/tests/test_bump_callers.sh99 → 130 cases, all green, plus shellcheck -x clean on the script and the suite. Five new cases:

Case Asserts
reftag a workflows_ref: v1 moves in lock-step with uses:
refshort a quoted short sha '2222222' moves, and the closing quote survives
coloc an unrelated 40-hex on a github-workflows line and one on a workflows_ref line are both untouched; exactly one pin is rewritten
assertfire a workflows_ref: ${{ inputs.workflows_ref }} fails the repo — no blob, no commit, no PR, bump failed for 1 repo, and the warning names both the file and the stale value
prosecomment a # workflows_ref: … prose note neither trips the assertion nor gets mangled, while the real pin below it still bumps

Ran: shellcheck -x .github/bump-callers/bump-callers.sh .github/bump-callers/tests/test_bump_callers.sh and bash .github/bump-callers/tests/test_bump_callers.sh.

Judgment calls

  1. Stacked on feat(groom): own the max_prs dispatch override in the reusable + add the groom caller fleet (BE-4346) #77 rather than main. feat(groom): own the max_prs dispatch override in the reusable + add the groom caller fleet (BE-4346) #77 is open and rewrites this exact sed block (it added the # main @ comment rules). Building on main would have conflicted and effectively reverted them. Banner at the top; base is matt/groom-max-prs-reusable.
  2. A uses: pin at a tag is now rewritten to the SHA too. The ticket specified shape-agnostic matching for workflows_ref only, but applying it to uses: as well is what makes the pair coherent — and it is required, because the assertion demands every uses: pin equal the new SHA, so a @v1 pin would otherwise fail the repo forever. It also matches the repo standard ("pin everything by full commit SHA"; bare @v1 fails consumers' pinact/zizmor).
  3. The assertion is intentionally broader than the rewrite, and that asymmetry is the design. Anything the rewrite cannot move surfaces as a loud per-repo failure rather than a silent half-bump. The known consequence: a caller whose workflows_ref is a ${{ … }} expression, or in flow style (with: {workflows_ref: v1}), will fail its repo on every run until a human fixes the config. That is deliberate — there is no literal ref for the bumper to move in those shapes, and rewriting them would break the caller. Comments are stripped before the assertion scans, so prose can never cause that failure.
  4. Falsification of the new deny path. The only outcome this diff denies is "bump a caller whose pin the rewrite cannot move." I checked every workflows_ref usage in the repo: the ${{ inputs.workflows_ref }} forms all live inside the reusable workflows themselves (never in a caller list), and every documented caller pattern (workflows_ref: <sha>, workflows_ref: main, workflows_ref: <same-sha>) is a literal the new rewrite moves. So no caller shape that works today is newly denied — the shapes that fail are the ones that previously produced a silently half-bumped PR.

Risk

The change is confined to one script that backs all five bump fleets, so blast radius is "every fleet" — but every write to a caller repo happens in Pass 2, after the assertion, and the suite covers each fleet's fixture shape. The riskiest line is the workflows_ref substitution, which replaces whatever token follows the key; that is safe because workflows_ref is this repo's own input and its only meaning is "the github-workflows ref to load assets from."

Closes BE-4662.

…oth pins moved (BE-4662)

The caller pin rewrite keyed on "any 40-hex on a line that mentions
github-workflows or workflows_ref" and never checked its own outcome, which
failed silently in both directions:

* Under-rewrite. A caller pins this repo TWICE — the `uses:` sha and the
  `workflows_ref:` input that loads the briefs/prompts/scripts at run time. A
  `workflows_ref` pinned to a tag (`v1`) or a short sha is not 40 hex, so it was
  left behind while `uses:` moved. The content-equality check still saw a
  difference, so the file was staged and a green-looking bump PR opened on a
  caller now running one version's workflow against another version's assets —
  the exact split this fleet exists to prevent.
* Over-rewrite. An unrelated 40-hex value sharing such a line was clobbered.

Anchor the substitution to the pin TOKEN instead — `Comfy-Org/github-workflows…@`
and the `workflows_ref:` key — and take whatever ref follows by position, so any
literal shape (full sha, short sha, tag) moves and a co-located SHA is
unreachable. The `workflows_ref` rule is `^`-anchored to a block-mapping key so
prose that merely mentions the input is left alone.

Precision cuts both ways, so add the guard it needs: before a rewritten file can
be staged, re-read it with a deliberately broader reader and assert every
github-workflows pin now equals the new SHA. If one does not (today: a
`workflows_ref` fed by a `${{ … }}` expression, which is never rewritten), warn
with the file + the stale value and fail that repo — the same posture a transient
fetch error already takes, because a partial bump is worse than no bump (BE-3896).

The full-sha `# main @ <40hex>` comment form gets its own rule now that rule 1 no
longer sprays every 40-hex on the line; it used to be corrected as collateral.

Tests: +31 cases (130 total) — tag-pinned and short-sha `workflows_ref`, an
unrelated 40-hex sharing a github-workflows line, the assertion firing (no
commit, no PR, non-zero for that repo), and a prose comment not tripping it.
shellcheck -x clean.
@mattmillerai mattmillerai added cursor-review Multi-model cursor review agent-coded Authored by the agent-work loop labels Jul 26, 2026
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 66b0d56b-43c1-4440-81b0-24d5a23d1be1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-4662-bump-callers-precise-pin
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-4662-bump-callers-precise-pin

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

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 9 finding(s).

Severity Count
🟠 High 1
🟡 Medium 4
🟢 Low 3
⚪ Nit 1

Panel: 8/8 reviewers contributed findings.

Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
…case, key boundary (BE-4662)

Review follow-ups on the pin-token rewrite + assertion. All five are edges of
the same idea: the token has to end where the ref begins, and the assertion has
to read exactly what the rewrite writes.

* the `uses:` pattern now requires a DELIMITER after the repo name (`/` or `@`),
  so a sibling repo whose name merely starts the same
  (`Comfy-Org/github-workflows-tools/action@v1`) is no longer swallowed and
  repinned to this repo's SHA — and, because the assertion reuses the pattern,
  no longer read back as NEW_SHA and staged silently;
* the owner/repo is matched case-INSENSITIVELY, because GitHub resolves `uses:`
  that way. A `comfy-org/…` caller previously had its (repo-agnostic)
  `workflows_ref` half bumped while `uses:` stayed stale, and the assertion —
  reading `uses:` with the same pattern — missed the stale half too: precisely
  the split half-bump this guard exists to prevent;
* the assertion's `workflows_ref` reader gained a left boundary, so a longer key
  like `upstream_workflows_ref: v1` (which the rewrite correctly leaves alone) is
  no longer read as an un-bumped pin and no longer hard-fails a clean caller's
  bump on every run;
* comments are dropped by YAML's own rule (a `#` preceded by whitespace) instead
  of at the first `#`, so a `#` INSIDE a ref cannot fake its way past: REF_RE
  half-moves `'feature#1'` to `'<NEW_SHA>#1'`, which now compares unequal and
  fails the repo rather than being read back as a clean NEW_SHA;
* an empty pin (`workflows_ref: ""`) is named `(empty)` rather than filtered out
  as a blank — the rewrite cannot move it either, so dropping it let a silent
  half-bump through.

The failure warning is also sanitized before it reaches this public repo's run
logs (carriage return stripped, `::` neutralized) so a caller-supplied value
cannot inject a workflow command, and the value/prose spacing is now explicit
rather than relying on the here-string's trailing newline.

Five regression cases added; each fails against the pre-fix script (16 checks).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded Authored by the agent-work loop cursor-review Multi-model cursor review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant