Skip to content

ci: fail when a workflow pins a stale copy of an action - #87

Merged
marc0olo merged 5 commits into
mainfrom
chore/check-workflow-self-refs
Sep 17, 2026
Merged

marc0olo merged 5 commits into
mainfrom
chore/check-workflow-self-refs

Conversation

@marc0olo

@marc0olo marc0olo commented Sep 17, 2026

Copy link
Copy Markdown
Member

Workflows here pin this repository's own actions by commit SHA, as a consuming repository does. Those pins do not move when an action changes, so a workflow keeps running the previous copy of the action beside it in the tree — and quietly: a newly added input handed to an action pinned from before it existed is a warning, not an error, so the run stays green while the new behaviour does nothing.

Already true on main: actions/create-pr is a commit behind, so the bundle rebuilt in #79 to clear the undici and brace-expansion advisories is not the one the changelog workflow runs.

Behaviour changes

  • New Check Self References job fails on every push to main when a pin has fallen behind the action it points at. Also available via workflow_dispatch.
  • New script/bump-self-refs reports those pins; --fix repoints them at the default branch tip.
  • The ten existing self references are repointed, which is what makes fix(deps): resolve 7 audit advisories in undici and brace-expansion #79's bundle live.

For the reviewer

It fails rather than opening a bump pull request. Doing that would need BOT_APPROVED_FILES widened to let a bot edit workflow files and the GitHub App granted workflows: write — worth deciding deliberately rather than folding in here. --fix is there if we revisit it.

Do not make it a required status check. It only runs after a merge, so it never reports on a pull request and one gated on it would never be mergeable. The job name is deliberately not suffixed :required.

A bump belongs in its own pull request. --fix pins at the default branch tip, so bundling it with a change to an action pins the commit before that change and the check fails again on merge.

Merge last. It conflicts with #78 in generate-changelog.yaml, and the bump has to be recomputed against whatever main becomes — a rebase plus another --fix.

🤖 Generated with Claude Code

Copilot AI 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.

🟡 Changes recommended

The README example omits the full-history checkout required by the script, which can cause false failures when followed.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a guard against stale self-pinned actions and documents how to repoint them.

Changes:

  • Adds script/bump-self-refs with reporting and --fix modes.
  • Adds a push/manual workflow to detect stale references.
  • Repoints ten workflow references and documents the maintenance process.
File summaries
File Description
script/bump-self-refs Detects and updates stale action pins
README.md Documents self-reference conventions
.github/workflows/self-check-self-refs.yaml Runs the stale-pin check
.github/workflows/generate-changelog.yaml Updates four action pins
.github/workflows/check-pr-title.yaml Updates three action pins
.github/workflows/check-commit-messages.yaml Updates three action pins
.github/CONTRIBUTING.md Documents the bump procedure
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread README.md

Copilot AI 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.

🟡 Changes recommended

Fix mode can skip required rewrites, and pinning fork or PR HEAD commits is unsafe across squash merges.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

script/bump-self-refs:103

  • With --fix, this branch is unreachable when every pin is considered current: the stale_count == 0 path exits before the Perl rewrite. That contradicts the documented --fix behavior (and the comment below) of repointing every self reference, so older pins for unchanged actions cannot be moved to HEAD. Gate this early exit on fix=false so fix mode always reaches the rewrite.
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread script/bump-self-refs Outdated
@marc0olo

Copy link
Copy Markdown
Member Author

Two findings, one taken and one declined. Both in 0be1986.

The squash-merge point is right, and the fix is different from HEAD-validation. --fix resolved git rev-parse HEAD, so running it from a branch wrote a SHA that a squash or rebase merge discards, leaving a reference to a commit that never lands — which this script's own check would then report as an unknown commit.

I first tried refusing to pin when HEAD is not on the default branch, and testing showed that blocks the legitimate case: the rebase this PR itself needs would be rejected, because after rebasing, HEAD is a branch commit by definition. So --fix now pins at the default branch tip, which is the only commit guaranteed to stay reachable, and says so when it differs from HEAD:

x actions/create-pr pinned at 4b4a84c5, 1 commit(s) behind
Pinning at origin/main (4b4a84c5) rather than HEAD, which is not on it.
Repointed every dfinity/ci-tools self reference at 4b4a84c5.

Verified from a branch whose own commit was 40e1be1: the written pin is 4b4a84c5, not the branch commit.

Declined: gating the early exit on fix=false. --fix would then rewrite on every invocation, and since the default branch tip moves constantly it would produce a diff every time it ran, including on a tree with nothing wrong — turning a bump into recurring noise. A pin whose action has not changed since is also functionally correct: the action code at that SHA is identical to the tip's, so moving it gains nothing.

The real defect there was the wording, which promised more than the behaviour: the usage line said --fix repoints every reference at HEAD. It now reads "repoint them when at least one has fallen behind", and the comment above the rewrite says the same. The rewrite still covers every reference rather than only the stale ones, so one SHA describes the whole tree.

Copilot AI 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.

🟢 Approval recommended

The implementation, workflow integration, documentation, and reference updates are consistent and complete.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

lwshang
lwshang previously approved these changes Sep 17, 2026
marc0olo and others added 5 commits September 17, 2026 15:07
Workflows reference this repository's own actions by commit SHA, and
those pins do not move when an action changes, so a workflow keeps
running the previous copy of it. Passing a newly added input to such an
action is reported as a warning rather than an error, so the run stays
green while the new behaviour does nothing.

actions/create-pr was already a commit behind, which meant the bundle
rebuilt in #79 was not the one the changelog workflow ran.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A bump has to be its own pull request, because --fix can only pin to a
commit that already exists. And the check cannot be a required status
check, since it only reports after a merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Pins are resolved against local history, so a shallow checkout made every
one of them report as an unknown commit, which reads as a problem with the
references rather than with the checkout.

The documented example now shows the checkout it needs, and says that the
script covers this repository only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
--fix resolved HEAD, so running it from a branch wrote a SHA that squash
and rebase merges discard, leaving a reference to a commit that never
lands. It now pins at the default branch tip and says so when that
differs from HEAD.

Also corrects the usage text, which claimed --fix repoints every
reference unconditionally when it only does so once one has fallen
behind.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#78 changed the generate-changelog and setup-commitizen actions, which
the workflows still pinned from before, so they would have kept running
the previous copies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@marc0olo
marc0olo force-pushed the chore/check-workflow-self-refs branch from 0be1986 to d90e64c Compare September 17, 2026 13:08
@marc0olo
marc0olo enabled auto-merge (squash) September 17, 2026 13:19
@marc0olo
marc0olo merged commit 28f8eef into main Sep 17, 2026
14 checks passed
@marc0olo
marc0olo deleted the chore/check-workflow-self-refs branch September 17, 2026 13:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants