Skip to content

fix(release): rebuilds must run at the tag ref — keyless identity integrity - #429

Merged
LukasWodka merged 3 commits into
developfrom
fix/rebuild-at-tag-ref
Jul 30, 2026
Merged

fix(release): rebuilds must run at the tag ref — keyless identity integrity#429
LukasWodka merged 3 commits into
developfrom
fix/rebuild-at-tag-ref

Conversation

@LukasWodka

@LukasWodka LukasWodka commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Both Bugbot findings on promotion #428, confirmed real as one defect: workflow_dispatch accepted inputs.ref so a tag could be rebuilt from a branch run — cosign embeds the run's ref in the keyless identity, producing @refs/heads/... signatures that the tag-anchored installers (correctly) reject on every customer machine.

Fix: inputs.ref removed; dispatch runs hard-fail unless started at a v* tag ref; supported rebuild paths are gh run rerun of the tag run or dispatching at the tag (Actions → Run workflow → select the tag). Installers stay untouched — their anchor is right.

Release note: this fix lands on develop → rides the next cycle (v0.10.2). Shipping v0.10.1 with the hazard is internal-only (it bites release-managers doing branch-dispatched rebuilds, never normal installs) — ops rule until then: rebuild only via rerun/tag-ref dispatch.

🤖 Generated with Claude Code


Note

Medium Risk
Changes only CI release plumbing but directly affects how signed artifacts are published; misconfiguration could still block rebuilds until ops use tag-ref dispatch or rerun.

Overview
Fixes release rebuilds that produced cosign identities installers reject. Manual workflow_dispatch no longer accepts an inputs.ref tag string, so a run started on a branch cannot rebuild a release while embedding @refs/heads/... in keyless signatures. Rebuilds must be triggered at the v* tag (Actions → Run workflow on the tag) or via gh run rerun on an existing tag run; checkouts and version/tag resolution now use github.ref only.

Adds a lightweight guard job that fails branch dispatches before the build matrix starts, with docs in the workflow header explaining why cosign’s run ref must match @refs/tags/v.*.

Hardens runner scripts (R8): version and publish tag steps pass github.ref_name through REF_NAME env instead of interpolating ref strings into shell, avoiding command injection from malicious tag names.

Reviewed by Cursor Bugbot for commit b201c11. Bugbot is set up for automated code reviews on this repo. Configure here.

)

Cosign's keyless identity embeds the RUN's ref. workflow_dispatch took an
inputs.ref and could build a tag from a branch run, publishing signatures
(@refs/heads/...) that the tag-anchored installers reject on every customer
machine. inputs.ref removed; dispatch runs now hard-fail unless started at
a v* tag ref; rebuild paths = rerun the tag run or dispatch at the tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka LukasWodka self-assigned this Jul 29, 2026
@LukasWodka

Copy link
Copy Markdown
Contributor Author

👋 Heads-up — Code review queue is at 45 / 30

Above the WIP limit. The team convention is to review existing PRs before opening new work.

Open PRs currently in Code review (oldest first):

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@saadqbal
saadqbal self-requested a review July 29, 2026 10:25

@saadqbal saadqbal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice, tight fix 👍 The tag-ref guard lines up with the installers' @refs/tags/v.* anchor, and needs: release means publish can't run when a branch dispatch trips the guard — so all signing runs stay at a tag ref. One non-blocking hardening nit inline. Minor thought: a job-level if: (or a tiny pre-flight job that release needs) would reject a misdirected branch dispatch once, instead of spinning up all 8 matrix legs to each fail the guard.

Comment thread .github/workflows/release.yml Outdated
saadqbal
saadqbal previously approved these changes Jul 29, 2026

@saadqbal saadqbal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice, careful fix — constrains the dispatch ref at the root instead of band-aiding the installers, and the comments make the keyless-identity reasoning easy to follow 👍 Verified the premise holds against develop (installers + header verify block both trust @refs/tags/v.*). One optional non-blocker inline.

Comment thread .github/workflows/release.yml Outdated
Guard moved out of the 8-way matrix into a tiny job that release needs:
a branch-misdispatch now fails once in seconds instead of burning eight
runners' setup. Refs passed via env, never interpolated -- git permits
$/backticks in tag names, so a crafted v* tag would otherwise execute on
the runner (R8, same rule as the client installer workflows).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@LukasWodka

Copy link
Copy Markdown
Contributor Author

@saadqbal both nits implemented (pre-flight guard job + env-passed refs, in-matrix guard removed) — the new commit dismissed your approval per stale-review policy; quick re-tick when you have a second and Lukas lands it.

Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
The one step this PR's hardening missed: it still did REF="${{ github.ref_name }}",
interpolating an attacker-controllable tag name straight into the shell, so a
crafted v* tag with backticks or $() would execute on the publish runner
before the release is created. Now passed as env REF_NAME and read as $REF_NAME,
matching the guard and version steps.
@LukasWodka

Copy link
Copy Markdown
Contributor Author

@saadqbal you're right — that step was the one the earlier hardening pass missed, and Bugbot flagged the same line. Fixed in b201c11.

Determine release tag now does exactly what the guard and version steps do:

      - name: Determine release tag
        id: tag
        env:
          REF_NAME: ${{ github.ref_name }}
        run: |
          REF="$REF_NAME"

So the tag ref is passed through the environment, never interpolated into the script — a crafted v* tag carrying backticks or $() can no longer execute on the publish runner before the release is created. Swept the rest of the file to be sure this was the last one: there are now zero ${{ github.* }} expansions inside any run: block. actionlint + shellcheck clean at the pinned versions (1.7.12 / 0.11.0).

Both threads resolved.

@LukasWodka

Copy link
Copy Markdown
Contributor Author

bugbot run

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b201c11. Configure here.

@LukasWodka
LukasWodka merged commit 19f9189 into develop Jul 30, 2026
26 checks passed
@LukasWodka
LukasWodka deleted the fix/rebuild-at-tag-ref branch July 30, 2026 08:59
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