Skip to content

ci: pin GitHub Actions to commit SHAs, move Slack notifications to v4 - #59

Merged
ysibirski merged 1 commit into
mainfrom
ci/pin-gha-actions-to-sha
Aug 20, 2026
Merged

ci: pin GitHub Actions to commit SHAs, move Slack notifications to v4#59
ysibirski merged 1 commit into
mainfrom
ci/pin-gha-actions-to-sha

Conversation

@ysibirski

@ysibirski ysibirski commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Description

Pins every GitHub Actions reference to a commit SHA, replaces an archived action, and moves the Slack notifications off an unmaintained major version.

A tag like @v4 is mutable: whoever controls the upstream repo can repoint it at any commit, and CI picks that up on the next run with no change here. A SHA cannot be repointed.

Jira Ticket

N/A

Changes

Pinning

44 references across 16 files. Every SHA below is the commit its existing ref resolves to today, so those actions run byte-identically after this merge.

action was now
actions/checkout ×18 @v4 11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
actions/upload-artifact ×10 @v4 ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
actions/download-artifact ×5 @v4 d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
softprops/action-gh-release ×2 @v2 3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2
WarpBuilds/cache ×2 @v1 40f3443ae7b70e568d6e2070ea897f3df94d7553 # v1.4.13
WarpBuilds/cache/restore ×1 @v1 40f3443ae7b70e568d6e2070ea897f3df94d7553 # v1.4.13
WarpBuilds/cache/save ×1 @v1 40f3443ae7b70e568d6e2070ea897f3df94d7553 # v1.4.13
Swatinem/rust-cache ×1 @v2.5.0 2656b87321093db1cb55fbd73183d195214fdfd1 # v2.5.0
actions-rs/toolchain ×1 @v1 dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
slackapi/slack-github-action ×3 @v1.25.0 dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0

Ten of these live in the composite actions under .github/actions/, not in .github/workflows/.

The archived action

actions-rs/toolchain is archived and read-only upstream, so pinning it would freeze CI onto an action that receives no fixes. Replaced with dtolnay/rust-toolchain, its de facto successor. The inputs are not identical, so the with: block in global.yml changes with it:

      - name: Rust Setup
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772 # v1
        with:
          toolchain: stable
          targets: wasm32-unknown-unknown
          components: rustfmt, clippy, rust-src

profile: minimal and override: true are gone because dtolnay/rust-toolchain declares neither input: it hardcodes --profile minimal in its rustup invocation, and runs rustup default (process-wide, broader than the old directory-scoped rustup override set). target becomes targets. Read off the action's own action.yml at the pinned commit, which declares exactly toolchain, targets, target (an alias) and components.

Slack action v1.25.0 → v4.0.0

v1.25.0 is from January 2024 and the v1 line ended that November, so it no longer receives fixes. The interface changed in v2, so the env: block becomes inputs:

        uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0
        with:
          webhook: ${{ secrets.RELEASES_PROD_SLACK_WEBHOOK_URL }}
          webhook-type: incoming-webhook
          errors: true

errors: true is load-bearing. v2 onward defaults it to false, which swallows a failed post entirely — the only trace is a core.debug call, invisible without ACTIONS_STEP_DEBUG, and the step exits 0. v1.25.0 always called core.setFailed. Without this line the bump would be a silent downgrade, turning a visible failure into a green job with no Slack message.

One behaviour change to be aware of: v4 retries a failed post five times over about five minutes before giving up, where v1 posted once.

Slack failure semantics, split by purpose

errors: true is set on all six steps, but the two release notifiers also get continue-on-error: true:

step errors continue-on-error rationale
CI-audit failure notification true the job exists only to notify; a delivery failure must still fail
release notifiers true true the release already published; keep the failure visible without redding the job

Without the second column, a Slack outage retroactively reds a successful release. In this repo that also skipped the rustdoc deploy, since rustdoc-job declares needs: [release] — exactly what happened on 2026-08-07. continue-on-error covers both failure modes, including payload parse errors, which errors does not govern.

Audit alert webhook and header

The audit notification moves from QA_SLACK_WEBHOOK_URL to SLACK_WEBHOOK_ALERTS_ZKVERIFY, and its header gains a repo prefix:

🚨 zkVerify ALERT - Audit Job Failed! 🚨
🚨 VFlow ALERT - Audit Job Failed! 🚨

${{ github.workflow }} renders as Audit in both repos, so before this the two headers were byte-identical — unusable once both alert into the same channel.

Before merging: SLACK_WEBHOOK_ALERTS_ZKVERIFY must exist. If it is missing when a scheduled audit fails, the step posts to an empty webhook and errors: true reds the job.

QA_SLACK_WEBHOOK_URL must not be deleted — it is still referenced by zkVerify-qa, zkverifyjs, attestation-bot, both *_ci_testing mirrors, and HorizenLabs/NH-core-ci_testing.

Breaking Changes

None expected. Apart from the Slack steps and the four with: lines in global.yml, every changed line is a uses: line.

The toolchain step is the one to watch on the first run: it installs the same stable toolchain, the same wasm32-unknown-unknown target and the same components, but through a different action.

Slack failure semantics change deliberately for the release notifiers: an undeliverable notification is now a red step rather than a red job. The audit notifier keeps v1 semantics exactly.

Checks

  • Project Builds
  • Project passes tests and checks
  • Updated documentation accordingly
  • Breaking changes have been correctly tagged and notified

Additional information

Rather than hand-editing, .github/ was reset to HEAD and the pinning regenerated from a pin table, so no stray edit could survive. Each pin was then verified against the GitHub API: resolve the ref that was in the file before this PR, dereference the annotated tag to its commit, assert it equals the SHA written. All report identical. No uses: reference anywhere under .github/ is left on a non-SHA ref, no actions-rs/* reference remains, and all 23 YAML files parse.

The v1 → v4 Slack jump was verified against the action's own source at the pinned commit rather than its release notes:

  • webhook, webhook-type and errors are the correct v4 input names, and the validator accepts only the literal incoming-webhookINCOMING_WEBHOOK throws. There is no reference to SLACK_WEBHOOK_TYPE anywhere in the v4 bundle, so moving the type to with: was mandatory.
  • errors governs network and Slack-response failures only; a payload parse error throws from the config constructor outside that path and fails the step regardless.
  • The two v2 breaking changes do not apply. v1 applied ${{{{ templating only to payload-file-path, never to an inline payload, and flattened only for WORKFLOW_TRIGGER; these steps use an incoming webhook. GitHub Actions expands ${{ }} before the action sees the input, so payload-templated is irrelevant.
  • v3 requires a Node 24 runtime. The runners report 2.336.0; actions/runner shipped Node 24 support in 2.327.0.
  • v4's only breaking change is stricter YAML multiline indentation. These payloads are JSON on single physical lines, and the action falls back to JSON.parse regardless.
  • v4's known duplicate-delivery bug (#654) is webhook-trigger-only; the incoming-webhook path is not affected.

All six payloads across this repo and the sibling zkVerify repo were machine-validated — JSON parse after expression substitution, plus Block Kit shape checks. This repo's three are all valid; the one defective payload was in zkVerify's CI-release.yml and is fixed in the companion PR.

One follow-up deliberately out of scope: continue-on-error: true on the release-notify steps would let a Slack outage annotate the run without redding the release. That is a policy change and belongs in its own PR; as written, this PR preserves the v1 contract exactly.

@ysibirski
ysibirski requested a review from a team as a code owner August 19, 2026 03:41
@ysibirski
ysibirski force-pushed the ci/pin-gha-actions-to-sha branch 3 times, most recently from e7e7e5d to 5aaab3d Compare August 19, 2026 15:40
@ysibirski ysibirski changed the title ci: pin GitHub Actions to commit SHAs ci: pin GitHub Actions to commit SHAs, move Slack notifications to v4 Aug 19, 2026
Every `uses:` reference moves from a mutable tag to the exact commit that tag
resolves to today, so a tag repointed upstream cannot silently change what runs
in CI. Each SHA was resolved from the ref already present in the workflow and
checked against the GitHub API, including dereferencing annotated tags.

Two references are not pure pins.

actions-rs/toolchain is archived and read-only upstream, so it is replaced by
dtolnay/rust-toolchain. The inputs differ, so the `with:` block changes with it:
dtolnay declares neither `profile` nor `override` (it hardcodes
`--profile minimal` and runs `rustup default`), and spells `target` as
`targets`.

slackapi/slack-github-action moves from v1.25.0 (Jan 2024, and the v1 line ended
that November) to v4.0.0. v2 moved the webhook URL and type from env vars to
`webhook`/`webhook-type` inputs, and made a failed post non-fatal by default, so
`errors: true` is set on all three steps to keep the v1 behaviour of failing the
step. v4 also retries a failed post five times over about five minutes before
giving up, where v1 posted once. Payloads are JSON and use only GitHub `${{ }}`
expressions, so neither `payload-templated` nor the v4 YAML parsing change
applies. The runners report 2.336.0, which satisfies the Node 24 runtime v3
introduced.

The two release notifiers additionally get `continue-on-error: true`. They run
after the release and images have already published, so a notification problem
should stay visible as a red step without taking the release job down with it.
The audit notifier deliberately does not get it: that job exists only to notify,
so a delivery failure there must still fail.

The audit notification also moves to the SLACK_WEBHOOK_ALERTS_ZKVERIFY secret
and gains a repo prefix in its header. Both repos alert into the same channel
and `github.workflow` renders as "Audit" in each, so the two headers were
previously indistinguishable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ysibirski
ysibirski force-pushed the ci/pin-gha-actions-to-sha branch from 5aaab3d to 1154265 Compare August 19, 2026 17:06
@ysibirski
ysibirski requested a review from drgora August 19, 2026 17:10
@ysibirski ysibirski closed this Aug 19, 2026
@ysibirski ysibirski reopened this Aug 19, 2026
@ysibirski
ysibirski removed the request for review from drgora August 19, 2026 17:24

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

LGTM

@drgora drgora left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. CI fixed in #60

@ysibirski
ysibirski merged commit ee7cedb into main Aug 20, 2026
11 of 13 checks passed
@ysibirski
ysibirski deleted the ci/pin-gha-actions-to-sha branch August 20, 2026 14:08
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