Principles:
- Release from a clean, tagged source of truth (tags/releases)
- Use least privilege and environments for production publishing
- Prefer OIDC + GitHub artifact attestations for provenance
- Make releases reproducible and auditable
Checklist:
- Release trigger model
- Choose one:
on: push: tags: ['v*'](tag-driven releases)on: release: types: [published](GitHub Release as source of truth)workflow_dispatchfor manual/promoted releases
- Ensure tag naming/versioning policy is explicit (SemVer or repo standard)
- Ensure the workflow is deterministic across reruns (same inputs => same outputs)
- Build stages (separate concerns)
- Split into jobs/stages:
- build & test (no publishing permissions)
- package (creates artifacts)
- attest (provenance + SBOM)
- publish (GitHub Release / Packages / external registries)
- Keep publishing credentials isolated to the publish job only
- Artifact production
- Produce release artifacts (zip, container image, NuGet/npm packages, etc.)
- Store as workflow artifacts for attestation + later publishing
- Record checksums (sha256) for key artifacts
- Provenance attestation (GitHub attestations)
- Use
actions/attest-build-provenanceto generate signed provenance for built artifacts - Ensure the attesting job has:
permissions: id-token: writepermissions: attestations: write- minimal
contentspermission as required (oftenread)
- SBOM generation + attestation
- Generate SBOM for artifacts (SPDX JSON or CycloneDX JSON)
- Use tooling appropriate to your ecosystem (.NET, Node, containers)
- Use
actions/attest-sbomto generate signed SBOM attestations - Keep SBOM generation deterministic and tied to the exact built artifact digest
- Publishing & release notes
- Publish artifacts:
- GitHub Release assets (preferred default distribution channel)
- GitHub Packages / external registries only if needed
- Use environments for prod publishing (required reviewers, protected secrets)
- Generate release notes from commits/PRs if repo uses that convention
- Include migration notes (DB/schema), feature flags, and rollback notes
- Guardrails
- Set explicit
permissions:everywhere (no implicit broad permissions) - Pin third-party actions to commit SHA
- Add
concurrencyfor release runs to avoid parallel publishes - Add
timeout-minuteson publish/attest steps - Ensure the pipeline fails if tests fail (no “continue-on-error” on critical steps)
Finish with:
- Release workflow outline (triggers + jobs + permissions per job)
- What is attested (which artifacts + where to find/verifiy attestations)
- What is published (channels + names + versioning)
- Any prerequisites (environments, OIDC, required secrets, branch protection)