SLSA Level 3 Release and Verification Workflows

February 16, 2026 · View on GitHub

SLSA 3 OpenSSF Scorecard OpenSSF Best Practices Release

Complete SLSA Level 3 release workflows with consumer verification tooling and Level 4 reproducibility preparation.


Why This Project?

The SLSA ecosystem provides excellent tools for producing secure releases: slsa-github-generator creates provenance, cosign signs artifacts, slsa-verifier validates them. But then this happens:

"I see you have .intoto.jsonl files. How do I verify your release?"

— Every second GitHub issue after you ship provenance

The gap: You've secured the build, but your users still need to learn four CLI tools, figure out which files to check and in what order, construct verification commands from scattered docs, and provide their own audit trails for compliance teams.

This project closes the loop with complete SLSA Build Track Level 3 workflows that include:

  • Consumer verification tooling — One hardened script (verify-release.sh) that checks everything, so your users can actually use the security you deployed.
  • Verification Summary Attestations — Signed proof of verification for audit trails
  • Reproducibility checks — Hermetic container rebuilds to validate determinism
  • Level 4 preparation — Evidence collection before the spec finalizes

All built on the standard SLSA stack (provenance from slsa-github-generator, signatures via Cosign/Rekor, SBOM in CycloneDX format, GitHub attestations).

SLSA v1.2 Note: This project implements SLSA Build Track Level 3 requirements. The SLSA v1.2 specification defines separate Build Track and Source Track levels. While this workflow operates on GitHub and benefits from GitHub's source control features, it focuses on Build Track compliance and does not explicitly claim Source Track levels.

When to Use This

Use CaseThis ProjectAlternatives
Binary releases (CLI tools, compiled artifacts)✅ Ideal — full provenance + user verification script (your ecosystem may already provide ad-hoc tools)slsa-github-generator alone (no consumer tooling)
Container images⚠️ Partial — use for source verification; container signing needs additional setupsigstore/cosign directly
Go module libraries⚠️ Consider — Go's checksum database provides integrity; this adds provenance + SBOMgo.sum + proxy may suffice
Multi-language monorepos✅ Works — language-agnostic source packagingManual integration of multiple tools
Compliance requirements✅ Ideal — generates audit artifacts (VSA, SBOM, provenance)Manual assembly of evidence

What Makes This Different

Capabilityslsa-github-generatorGoReleaser + cosignThis Project
SLSA provenance✅ (via plugin)✅ (uses slsa-github-generator)
Consumer verification scriptverify-release.sh
Verification Summary Attestation✅ Signed VSA generation
Reproducibility verification✅ Container-based rebuild
SBOM generation✅ CycloneDX with attestation
Single workflow setup❌ (building block)
Level 4 preparation✅ Evidence collection

Overview

This project provides a set of tools to help software producers build and publish SLSA Level 3-compliant releases, and for consumers to verify them. They also gather reproducibility evidence to ease adoption of the upcoming SLSA Level 4 guidance once that level is formally published.

  • Reusable GitHub Actions Workflows for packaging and verifying releases
  • The verify-release.sh shell script helper for local verification and reproducibility checks (the same as used in the GitHub Actions verifier), including VSA generation

Building on the SLSA generator and verifier, and the Sigstore ecosystem, these integrated workflows combine full producer and consumer flows with minimal setup.


Table of Contents


Quick Start

jobs:
  release:
    uses: bytemare/slsa/.github/workflows/slsa.yaml@<pinned-sha>
    with:
      workflow_ref: <pinned-sha>
    permissions:
      contents: write
      id-token: write
      attestations: write
      actions: read

For detailed configuration options, see Release - How to Use the Workflow.


Features

For Software Producers

  • 🔒 SLSA Level 3 Compliance — Provenance via the official slsa-github-generator, plus deterministic packaging and hermetic reproducible builds
  • 🧭 Level 4 Preparation — Additional reproducibility materials ready for when the Level 4 definition solidifies
  • 📦 SBOM GenerationCycloneDX Software Bill of Materials with GitHub attestation
  • ✍️ Keyless SigningCosign signatures with Rekor transparency logs
  • 🛠️ Easy Integration — Single reusable workflow with sensible defaults

For Software Consumers

  • Verification Script — Download and run verify-release.sh to independently verify any release
  • 🔍 Multiple Verification Modes — Quick (checksums), Full (provenance + SBOM), Reproduce (hermetic container rebuild with network isolation)
  • 🔒 Defense-in-Depth Security — Reproduce mode uses network-isolated containers with read-only mounts, non-root execution, and cross-verification
  • 🏷️ Verification Summary Attestation (VSA) — Signed proof that verification passed, for your own audit trail
  • 📋 Clear Output — One-line pass/fail with detailed logs available

For Compliance Teams

  • 📜 Complete Audit Trail — All artifacts attached to GitHub releases (provenance, SBOM, signatures, verification reports)
  • ⚓️ Native GitHub Attestations — SBOM and build provenance in GitHub's attestation store
  • 🗂️ Rich Metadata — Commit info, environment snapshots, checksums, manifests
  • 📊 Policy Documentation — VSA documents which policies were evaluated and their results

Prerequisites

For release workflow: None required — tools are installed at runtime with SHA256 hash verification.

For local verification (verify-release.sh):

ToolRequired ForInstallation
curl, jq, sha256sumAll modesUsually pre-installed
cosignSignature verificationInstall guide
ghGitHub API access (outside Actions)Install guide
slsa-verifier--mode fullInstall guide
docker--mode reproduce (runs hermetically with --network none)Install guide
# Show all options
./verify-release.sh --help

Supported Languages

Source packaging works for any repo. Go modules receive extra metadata (like go env) and use a Go-specific SBOM generator.


Release - How to Use the Workflow

Configuration:

Replace [pinned commit SHA] to ensure stability. workflow_ref is required and must match the same pinned ref so helper scripts are fetched from the same commit.

---

name: Release

on:
  push:
    tags: # Adapt to your needs
      - '*.*.*'      # Semantic versioning tags
      - 'v*.*.*'     # Tags starting with 'v'
  workflow_dispatch:  # Manual trigger
  pull_request:       # Dry-run on PRs

permissions: {}

jobs:
  release:
    uses: bytemare/slsa/.github/workflows/slsa.yaml@[pinned commit SHA]
    with:
      workflow_ref: [pinned commit SHA] # required, ensures stable helper scripts
      dry_run: ${{ github.event_name == 'pull_request' }} # optional, default: false
      create_release: ${{ github.event_name != 'pull_request' }} # optional, default: true
      extended_metadata: false  # optional, default: false. Set to true for forensics mode.
      # see .github/workflows/slsa.yaml for all options
    permissions:
      contents: write           # Create releases
      id-token: write          # OIDC for signing
      attestations: write      # GitHub attestations
      actions: read            # Read workflow data
      security-events: write   # Upload SARIF (optional)

packaging_language=auto detects go.mod in the tagged commit and enables Go-specific metadata only when present. sbom_language=auto uses the Go SBOM generator when go.mod exists, otherwise it runs cdxgen via container (pin cdxgen_version for deterministic output).

Inform your users

You can use the following snippet in your repo to inform your consumers of the release integrity properties:

Release Integrity (SLSA Level 3)

Releases are built with the reusable bytemare/slsa workflow and ship the evidence required for SLSA Level 3 compliance:

  • 📦 Artifacts are uploaded to the release page, and include the deterministic source archive, subjects.sha256, signed SBOM (sbom.cdx.json), GitHub provenance (*.intoto.jsonl), a reproducibility report (verification.json), and a signed Verification Summary Attestation (verification-summary.attestation.json[.bundle]).
  • ✍️ All artifacts are signed using Sigstore with transparency via Rekor.
  • ✅ Verification (or see the latest docs at bytemare/slsa):
curl -sSL https://raw.githubusercontent.com/bytemare/slsa/main/verify-release.sh -o verify-release.sh
chmod +x verify-release.sh
./verify-release.sh --repo <owner>/<repo> --tag <tag> --mode full --signer-repo bytemare/slsa

Run again with --mode reproduce to build in a container, or --mode vsa to validate just the verification summary.


Verify

Quick verification using the helper script:

<workflow-repo> should match the reusable workflow repo that produced the attestations (for example, bytemare/slsa or your fork).

# Download the verification script
curl -sSL https://raw.githubusercontent.com/bytemare/slsa/main/verify-release.sh -o verify-release.sh
chmod +x verify-release.sh

# Run quick verification (checksums + signatures)
./verify-release.sh --repo <owner>/<repo> --tag <tag>

# Run full verification (all artifacts)
./verify-release.sh --repo <owner>/<repo> --tag <tag> --mode full --signer-repo <workflow-repo>

# Run containerized reproducibility check (requires Docker and rebuilds inside a container)
./verify-release.sh --repo <owner>/<repo> --tag <tag> --mode reproduce

# Generate and sign a Verification Summary Attestation locally
./verify-release.sh --repo <owner>/<repo> --tag <tag> --mode full --signer-repo <workflow-repo> \
  --emit-vsa my-release.vsa.json --verifier-id https://example.com/verifier

# Verify the published Verification Summary Attestation only
./verify-release.sh --repo <owner>/<repo> --tag <tag> --mode vsa

Verification Modes:

  • quick (default) - Basic checksum and signature verification (fast, recommended for most users).
  • full - Complete verification of all release artifacts including SBOM and provenance. This mode uses the official slsa-verifier to verify the provenance and additionally provides a holistic verification of the entire release, ensuring that all the pieces of the puzzle (artifacts, signatures, attestations, provenance, and SBOM) fit together correctly, providing a much higher level of confidence in the integrity and authenticity of the release.
  • reproduce - Hermetic rebuild in a network-isolated container (--network none) using the SLSA_BUILDER_IMAGE recorded in build.env (defaults to golang:1.25-bookworm@sha256:...). All downloads and validation happen on the host before files are mounted read-only into the container, ensuring zero network access during rebuild. This provides independent reproducibility evidence matching SLSA Build Track Level 3+ requirements.

The script automatically:

  • Checks for required tools (curl, jq, cosign, sha256sum, gh for attestations, slsa-verifier for full mode, docker for reproduce mode)
  • Downloads all necessary artifacts
  • Verifies checksums and signatures
  • Validates SLSA provenance and SBOM (in full mode)
  • Tests reproducibility (in reproduce mode)
  • Provides concise one-line output with clear success/failure indicators

Need a signed verification summary?

Combine --mode full with --emit-vsa <file> --verifier-id <uri> (plus optional policy metadata) to generate a Verification Summary Attestation.

Policy as Executable Code

Unlike declarative policy languages (OPA Rego, CEL), this project uses the verification script itself as the policy. When emitting VSAs, the policy.uri field points to verify-release.sh and includes its SHA-256 digest. This approach offers several advantages:

  • No implementation gap — The policy document is the implementation that was executed
  • Maximum transparency — Auditors can read the exact checks performed without abstraction layers
  • Reproducible verification — Same script + same inputs = same results
  • Self-documenting — The code documents what "SLSA Build Track Level 3" means for this project

The SLSA VSA specification is intentionally flexible about policy format. Executable verification scripts are a common pattern in supply chain security (see also: in-toto layouts, TUF threshold signing) and are particularly well-suited for sequential verification workflows.

Run in GitHub Actions

Reuse the bundled verification workflow to automate checks in CI:

jobs:
  verify-release:
    uses: bytemare/slsa/.github/workflows/verify.yaml@<pinned-commit>
    with:
      workflow_ref: <pinned-commit> # use the same as in 'uses:...'
      tag: <tag>
      mode: full,reproduce    # run multiple modes sequentially
      emit_vsa: true          # optional – generate a signed Verification Summary Attestation (requires mode: full)
      upload_to_release: true # optional – upload VSA to GitHub release (requires contents: write)
    permissions:
      contents: read          # use contents: write if upload_to_release is true
      id-token: write

Automatic Verifier Identity: When emit_vsa: true, the workflow automatically computes a verifier_id pointing to the exact commit SHA of the verification workflow:

https://github.com/{workflow_repo}/blob/{commit_sha}/.github/workflows/verify.yaml

This ensures immutability and traceability. You can override by explicitly providing verifier_id if needed.

Resource and Policy URIs: The VSA includes:

  • resource_uri (default: https://github.com/{repo}/releases/tag/{tag}) – identifies the artifact being verified
  • policy_uri (default: https://github.com/{workflow_repo}/blob/{workflow_ref}/verify-release.sh) – points to the verification policy

Both support custom values via workflow inputs.

Verifier Metadata: The workflow automatically embeds workflow_ref and script_sha in the VSA for traceability. You can optionally add custom metadata for compliance tracking:

      verifier_metadata: |
        environment=production
        compliance_framework=SOC2
        auditor_id=security-team
        policy_version=2026.1

The verification workflow also supports manual triggering via workflow_dispatch for interactive runs. A convenience wrapper .github/workflows/wf-verify.yaml provides a simple example of manual dispatch usage.

For the complete manual verification and reproducibility walkthrough, see VERIFICATION_AND_REPRODUCIBILITY_GUIDE.md.


SLSA Alignment

Note: This workflow implements SLSA Build Track Level 3 requirements as defined in the SLSA v1.2 specification (Build Track requirements are unchanged from v1.1). The SLSA v1.2 specification also introduced a Source Track for securing source code development practices. While this workflow operates on GitHub and benefits from GitHub's source controls, formal Source Track compliance is not explicitly claimed. Level 4 remains a work in progress; this workflow collects additional reproducibility evidence to prepare for Level 4 requirements once formally published.

The following table maps the current SLSA v1.2 Build Track requirements to how this workflow addresses each safeguard.

⚠️ Disclaimer: While this workflow implements the controls listed below, achieving SLSA compliance also depends on organizational policies and practices beyond the scope of this automation, like mandatory reviews from at least one other person. Users should ensure that their overall processes align with these SLSA requirements.

SLSA v1.2 Build Track RequirementSub-requirementCompliantEvidence
Source
Version ControlAll source code is version controlled.YesThe project is hosted on GitHub.
Verified HistoryCommits are signed.YesThe project enforces signed commits.
Retained IndefinitelySource is retained indefinitely.YesThe project is hosted on GitHub.
Build
Scripted BuildThe build process is fully scripted.YesThe build is scripted in .github/workflows/slsa.yaml and scripts/package-source.sh.
Build ServiceThe build is performed by a build service.YesThe build is performed by GitHub Actions.
Build as CodeThe build definition is stored in version control.YesThe build definition is in .github/workflows/slsa.yaml.
Ephemeral EnvironmentThe build runs in an ephemeral environment.YesThe build runs in a container on GitHub Actions.
Isolated BuildThe build is isolated from other builds.YesThe package_source job in .github/workflows/slsa.yaml uses step-security/harden-runner to isolate the build.
Parameterless BuildThe build is parameterless.YesThe build is triggered by a git tag and does not require any parameters.
Hermetic BuildThe build is hermetic.YesThe package_source job in .github/workflows/slsa.yaml only pulls from GitHub and blocks with egress-policy: block, and the package-source.sh script ensures a clean worktree and no network access.
Reproducible BuildThe build is reproducible.YesThe rebuild_verify job in .github/workflows/slsa.yaml verifies that the build is reproducible. The verify-release.sh script also provides a way to reproduce the build.
Provenance
AvailableProvenance is available.YesThe *.intoto.jsonl file is the provenance.
AuthenticatedProvenance is authenticated.YesThe provenance is signed using Sigstore and can be verified with cosign.
Service GeneratedProvenance is generated by the build service.YesThe provenance is generated by GitHub Actions using the slsa-framework/slsa-github-generator.
Non-FalsifiableProvenance is non-falsifiable.YesThe provenance is signed and stored in a transparency log (Rekor).
Dependencies CompleteProvenance includes all dependencies.YesThe SBOM (sbom.cdx.json) is generated and attested, listing all dependencies.
Common
SecurityThe build service meets security requirements.YesGitHub Actions is a hardened build service.
AccessThe build service has limited access to secrets.YesThe workflow uses minimal permissions.
SuperusersThe number of superusers is minimized.YesAccess to the repository and secrets is restricted.

Supply Chain Security

This project implements multiple layers of supply chain hardening:

Tool Version and Hash Pinning

All external tools used in CI/CD workflows (cosign, gh, jq, slsa-verifier) are pinned to specific versions and verified against SHA256 checksums before execution. This defends against:

  • Version tag manipulation — Even if an attacker compromises a release tag, the hash verification will fail
  • Binary substitution attacks — Downloaded binaries are verified against known-good hashes before use
  • Supply chain injection — No tool can execute without matching its recorded fingerprint

Tool versions and hashes are maintained in a single source of truth: .github/tool-versions.json.

Automated Hash Updates

When Renovate detects a new tool version, it opens a PR updating the version in tool-versions.json. A companion workflow automatically:

  1. Downloads the new binary
  2. Computes its SHA256 hash
  3. Updates tool-versions.json with the new hash
  4. Commits the change to the PR

This keeps hashes synchronized with versions while maintaining full auditability—all hash changes are visible in PR diffs.

Industry Alignment

This approach follows patterns used by security-focused projects:

PracticeThis Projectkubernetes/kubernetesgoogle/oss-fuzzslsa-framework
Version pinning
SHA256 hash verification✅ (Docker images)✅ (runtime)
Central version configtool-versions.jsonVERSION filesENV in DockerfileWorkflow outputs
Automated updates✅ Renovate + hash workflowManualManualRenovate

Versioning and Compatibility

Even though releases follow Semantic Versioning, you should use the latest available commit hash from main and pass it as workflow_ref to keep helper scripts pinned.


Additional Resources


License

This project is licensed under the MIT License - see the LICENSE file for details.