Skip to content

release.yml: pass the tag through env instead of interpolating it into shell - #5

Merged
Bogzx merged 1 commit into
mainfrom
improve/2026-10-01-release-env
Oct 1, 2026
Merged

Bogzx merged 1 commit into
mainfrom
improve/2026-10-01-release-env

Conversation

@Bogzx

@Bogzx Bogzx commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Follow-up to #3, from review: release.yml expanded event data straight into shell scripts.

Why

release.yml:25 and release.yml:53 put ${{ github.event.release.tag_name }}, and on line 53 ${{ github.repository }}, directly into run: scripts. GitHub substitutes the expression into the script text before the shell runs, so a tag named, for example, v1$(curl …) would execute as code in a job that has contents: write.

What changed

  • Both steps now receive the values through env: (TAG, REPO) and use "$TAG" / "$REPO". No ${{ }} expression is left in any run: line in either workflow.
  • The build job's actions/checkout sets persist-credentials: false. That job only builds and uploads dist/, so it never needs the token in .git/config.

Verification

  • actionlint 1.7.7: clean on both workflows.
  • zizmor 1.30.1 on release.yml:
    • on main: 2 × template-injection (lines 25 and 53), 1 × artipacked, 8 × unpinned-uses;
    • on this branch: only the 8 × unpinned-uses remain (see below).
  • Simulated with the same quoting the step uses:
    • TAG='v0.2.0$(echo INJECTED)' python scripts/check_release.py "$TAG" prints error: tag v0.2.0$(echo INJECTED) does not match __version__ 0.2.0 and exits 1: the tag is treated as data;
    • TAG=v0.2.0 prints ok: 0.2.0 is ready to release.

Not done here

  • zizmor's remaining unpinned-uses findings: actions are referenced by tag (@v4, @release/v1), as in the rest of the repo. Pinning them to commit SHAs, plus Dependabot to keep the pins current, is worth doing for this workflow because its publish jobs hold id-token: write. It is a separate, repo-wide change.

🤖 Generated with Claude Code

Two run steps expanded ${{ github.event.release.tag_name }} (and the repo
name) directly into the script text, so a crafted tag name would execute as
shell. They now read $TAG / $REPO from env. The build job's checkout also
stops persisting the token (persist-credentials: false); it never pushes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Bogzx
Bogzx merged commit 8350b1a into main Oct 1, 2026
6 checks passed
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.

1 participant