harden(release): isolate npm build from macOS secrets + pin goreleaser

Addresses Codex review findings on PR #278:

MEDIUM — Apple signing secrets were exposed to the npm web build.
The previous `before.hooks` block ran `npm ci && npm run build` inside
the GoReleaser process, which means npm lifecycle scripts and the
SvelteKit build inherited the Developer ID .p12 cert, cert password,
and .p8 notary key from the goreleaser-action's env. Adding a 5-year
signing cert to that environment meaningfully widened the blast radius
of any npm supply-chain compromise.

Fix: move the web build into a dedicated workflow step before the
goreleaser-action invocation. The MACOS_* secrets are scoped only to
the goreleaser env block, so the npm phase no longer sees them.

LOW — GoReleaser binary version was floated as `~> v2`, while every
third-party Action in this workflow is SHA-pinned per the policy at
the top of the file. With Apple signing credentials now in the env, a
compromised or regressed GoReleaser release would carry meaningful
blast radius. Pinned to v2.15.4 (current latest) so bumps go through
explicit review like the rest of the action pins.

No functional change to the signing/notarization itself — same schema,
same gating, same secrets.
This commit is contained in:
xarmian
2026-04-28 23:50:46 +00:00
parent e492265ff4
commit 6f4a52c8e4
2 changed files with 23 additions and 7 deletions
+17 -1
View File
@@ -66,11 +66,27 @@ jobs:
- name: Install syft (for SBOM generation)
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
# Build the SvelteKit web UI before GoReleaser so the static assets
# get embedded into the Go binary. Done as a dedicated step (instead
# of a goreleaser `before:` hook) so the npm install/build does NOT
# inherit the MACOS_* signing secrets — those are scoped only to the
# `Run GoReleaser` step's env block below. This isolates the 5-year
# Developer ID cert from any npm supply-chain compromise during
# dependency install.
- name: Build web UI
run: cd web && npm ci && npm run build
- name: Run GoReleaser
id: goreleaser
# GoReleaser binary is pinned to an exact version (not "~> v2") to
# match the SHA-pinning policy applied to the Actions themselves —
# see the comment at the top of this file. With Apple signing
# credentials now flowing through this step, a compromised or
# regressed GoReleaser release would carry meaningful blast radius;
# pinning forces an explicit, reviewed bump.
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0
with:
version: "~> v2"
version: "v2.15.4"
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+6 -6
View File
@@ -1,11 +1,11 @@
version: 2
before:
hooks:
# Build web UI before Go compilation so it gets embedded.
# v2 accepts simple string hooks only at this level; object-with-cmd
# form (v1 syntax) is rejected with "cannot unmarshal !!map into string".
- bash -c "cd web && npm ci && npm run build"
# NOTE: the SvelteKit web UI is built by a dedicated workflow step in
# .github/workflows/release.yml *before* the goreleaser-action runs, NOT
# by a `before:` hook here. Done deliberately so the npm install/build
# does not inherit the macOS signing secrets (Developer ID .p12, .p8 notary
# key, etc.) that are scoped only to the `Run GoReleaser` step's env.
# Reduces blast radius from any npm supply-chain compromise.
builds:
- main: ./cmd/pad