Skip to content

Harden CI: read the ref from the runner env instead of expanding it into run: blocks - #5295

Merged
vivekchand merged 1 commit into
mainfrom
harden/desktop-artifacts-ref-name-env-binding
Aug 28, 2026
Merged

Harden CI: read the ref from the runner env instead of expanding it into run: blocks#5295
vivekchand merged 1 commit into
mainfrom
harden/desktop-artifacts-ref-name-env-binding

Conversation

@vivekchand

Copy link
Copy Markdown
Owner

What

A ${{ ... }} expression inside a run: block is substituted into the script before the shell parses it, so whatever it holds becomes shell source text rather than a value. desktop-artifacts.yml had four such expansions of github.ref_name / github.ref_type, across three steps. All four now read the value from the runner environment instead.

Job Step Was Now
macOS Require signing on release tags ${{ github.ref_name }} ${GITHUB_REF_NAME}
Windows Require signing on release tags ${{ github.ref_name }} ${GITHUB_REF_NAME}
Windows Stamp bundle version (pwsh) ${{ github.ref_name }} $Env:GITHUB_REF_NAME
Windows Stamp bundle version (pwsh) ${{ github.ref_type }} $Env:GITHUB_REF_TYPE

Why this shape

This file had already established the right pattern — it just wasn't applied consistently. The macOS and Linux Stamp bundle version steps read ${GITHUB_REF_TYPE} and ${GITHUB_REF_NAME} straight from the runner environment, with no template expansion at all. The Windows job and the two signing gates were the outliers, so this PR converges them on the convention already in the file rather than introducing new env: bindings.

GITHUB_REF_NAME and GITHUB_REF_TYPE are default GitHub Actions environment variables, set on every runner including Windows. So no env: block is required, and the resolved values are identical to what the expansions produced.

The if: conditions at lines 49, 276 and 679 use github.ref in a conditional, not a run: block. Those are evaluated by the Actions expression engine and never reach a shell, so they are correct as-is and are untouched.

Verification

  • zizmor 1.29.0 (the version this repo's tooling uses) over .github/workflows/, main vs branch, same binary and invocation:
    • High-severity template-injection: 4 → 0
    • Every other rule count unchanged: unpinned-uses 30, artipacked 48 Medium / 13 Low, informational template-injection 29, adhoc-packages 5, misfeature 3, dangerous-triggers 2, excessive-permissions 2, cache-poisoning 1, Medium template-injection 1. Total 140 → 136.
  • actionlint 1.7.7 (which runs shellcheck over every run: block): exit 0 on both main and this branch.
  • All 34 workflow files re-parsed with yaml.safe_load after the edit.
  • python3 scripts/check_action_refs.py passes (23 distinct action references).

Scope / safety

  • Diff is 6 lines, every one inside a run: block.
  • No permissions: block is touched. desktop-artifacts is one of the workflows that needs write scopes to publish release assets, and it keeps exactly the scopes it has today — this PR is expression-binding only, one concern.
  • No trigger, step, job or action version changed.

Coordination

No overlap with open hardening PR #5294, which pins actions across 11 other workflow files and does not touch desktop-artifacts.yml. This file's uses: references are already SHA-pinned from an earlier batch.

Not in this PR

Left for their own batches, one concern per PR:

  • unpinned-uses (30) — covered by Harden CI: pin the remaining first-party actions to commit SHAs #5294, currently open and green.
  • artipacked (61) — actions/checkout without persist-credentials: false.
  • Informational template-injection (29) — these expand steps.*.outputs.*, an internally-derived value, and are a separate concern from ref-derived input.
  • excessive-permissions (2), dangerous-triggers (2), cache-poisoning (1).

.github/ is exempt from the product-record gate, so no Factory record is cited.


Generated by Claude Code

A `${{ ... }}` expression inside a `run:` block is substituted into the
script before the shell parses it, so the value becomes shell source text
rather than data. desktop-artifacts.yml had four such expansions of
`github.ref_name` / `github.ref_type` across three steps.

This file already established the right pattern: the macOS and Linux
"Stamp bundle version" steps read `${GITHUB_REF_TYPE}` and
`${GITHUB_REF_NAME}` straight from the runner environment, with no
template expansion at all. The Windows job and the two signing gates were
the outliers. They now follow the same convention:

- macOS "Require signing on release tags": ${GITHUB_REF_NAME} in the
  ::error:: message.
- Windows "Require signing on release tags": likewise.
- Windows "Stamp bundle version" (pwsh): $Env:GITHUB_REF_NAME and
  $Env:GITHUB_REF_TYPE, matching what its macOS and Linux siblings do.

GITHUB_REF_NAME and GITHUB_REF_TYPE are default Actions environment
variables present on every runner, so no `env:` block is needed and the
resolved values are identical.

Verified: zizmor 1.29.0 over .github/workflows/, main vs branch --
High-severity template-injection 4 -> 0, every other rule count unchanged
(unpinned-uses 30, artipacked 48/13, informational template-injection 29,
adhoc-packages 5, misfeature 3, dangerous-triggers 2, excessive-permissions
2, cache-poisoning 1). actionlint 1.7.7 exits 0 on both. All 34 workflow
files re-parsed as YAML; scripts/check_action_refs.py passes.

Six lines, all inside `run:` blocks. No permission, trigger, step or
action version changed -- desktop-artifacts keeps the write scopes it
needs to publish releases.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UYeD7Hs9edpH86kLibimqS
@8090-software-factory

Copy link
Copy Markdown

✅ Drift Bot (ClawMetry): no drift detected

Drift Bot analyzed the changed files against this project's blueprints and requirements and found no drift.

@vivekchand
vivekchand merged commit e4fbbfb into main Aug 28, 2026
36 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.

2 participants