Artifact Attestations, SBOMs, Build Provenance, Verification, and SLSA-Oriented Workflows: Concepts, Architecture, and Mental Model
A filename, release tag, or registry location tells you where an artifact was found; it does not prove which bytes were built, which workflow produced them, or whether the consumer is trusting the right builder. This lesson builds a provenance mental model around immutable digests, signed attestations, SBOM predicates, OIDC-backed workflow identity, verification policy, and the limits of SLSA-oriented evidence.
Learning objectives
- Explain artifact identity as a cryptographic digest and distinguish an artifact, an attestation statement, its subject, predicate, signer identity, and verification result.
- Describe how GitHub artifact attestations use Actions identity/OIDC and Sigstore to bind build evidence to repository/workflow context without exposing a signing key to the workflow.
- Distinguish build provenance from SBOM inventory and explain why both can be useful for the same immutable artifact.
- Apply consumer-side trust constraints for repository, workflow, ref, issuer and runner class instead of accepting any cryptographically valid attestation.
- Use SLSA Build levels as a model of provenance/build-system properties without treating a GitHub feature toggle as universal certification or proof that code is secure.
1. The problem: location and version labels are not artifact identity
Chapter 17 separated workflow artifacts from caches, Chapter 19 promoted immutable deployment inputs, Chapter 21 distributed packages by version/digest, and Chapter 24 treated credentials as trust boundaries. Chapter 25 asks the consumer-side question those chapters leave open: what evidence proves that these exact bytes were produced by a workflow I am willing to trust?
A file called atlas-1.0.0.tar, a release tag such as
v1.0.0, or a container tag such as
stable is a human-readable locator. Those names can be
copied or, depending on the system, moved. A cryptographic digest
such as SHA-256 is computed from the bytes themselves. If one byte
changes, the digest changes. Provenance and attestations become
meaningful only when the subject digest identifies the
artifact a consumer actually received.
2. Mental model: bytes → digest → signed claim → policy decision
flowchart TD
S["Source commit + workflow"] -->|build on GitHub Actions| A["Artifact bytes"]
A -->|SHA-256| D["Immutable subject digest"]
O["Actions OIDC identity"] -->|repository/workflow/ref/event claims| T["GitHub / Sigstore attestation"]
D -->|subject| T
P["Provenance predicate"] -->|how/where build ran| T
B["SBOM predicate"] -->|component inventory| T
A -->|received bytes| V["Consumer verifier"]
T -->|signature + certificate + timestamps| V
R["Policy: repo + signer workflow + ref + runner + predicate"] --> V
V -->|all constraints pass| G["Accept / deploy"]
V -->|digest or identity/policy fails| X["Reject + investigate"]
The artifact bytes are first hashed. The digest is the attestation subject: the thing the claim is about. A predicate is the body of a claim—for example SLSA provenance describing the build or an SPDX/CycloneDX SBOM describing software components. The attestation also carries signing/identity evidence. On GitHub Actions, the certificate is derived from GitHub-issued OIDC identity; the workflow does not manage a reusable private signing key.
Verification has two independent questions. First, do the received bytes match the subject digest and does the cryptographic bundle verify against an accepted trust root? Second, does the authenticated builder identity satisfy your policy—right repository, signer workflow, ref, issuer and possibly runner type? Passing question one but skipping question two proves authenticity to an identity you may not actually trust.
3. Vocabulary: subject, predicate, issuer and verifier
| Term | Beginner definition | What to verify |
|---|---|---|
| Artifact | The file/image/package you intend to consume | Hash the actual received bytes or immutable OCI digest. |
| Subject | Artifact name plus digest inside an in-toto statement | Must equal the artifact you are evaluating. |
| Attestation | Cryptographically signed claim about one or more subjects | Signature/timestamp and authenticated identity must validate. |
| Predicate type | Schema that says what kind of claim this is | Build provenance, SPDX SBOM, CycloneDX SBOM, or another vetted/custom predicate. |
| Provenance | Evidence about how/where an artifact was produced | Builder/workflow/source/ref/event and build-definition expectations. |
| SBOM | Software bill of materials: inventory of components/relationships | Does it represent the shipped artifact and the dependency resolution you care about? |
| Issuer / signer identity | Identity system and workflow represented in the certificate | Expected OIDC issuer plus repository/signer workflow constraints. |
| Trust root | Keys/certificates/metadata a verifier accepts as the root of signature validation | GitHub CLI obtains current Sigstore/GitHub trusted-root material online; offline workflows must manage it deliberately. |
4. GitHub artifact attestations and Actions identity
Current GitHub artifact attestations are implemented with Sigstore. For public repositories GitHub uses the Sigstore Public Good Instance; the Sigstore bundle is also recorded in a public transparency log. Private repositories on the eligible Enterprise Cloud path use GitHub’s Sigstore instance, which does not use the public transparency log and federates with GitHub Actions.
The authenticated certificate records identity derived from the
Actions OIDC token, including repository/workflow context. This is
why the workflow needs id-token: write while the
attestation store needs attestations: write. Those
permissions authorize issuance/storage; they do not mean a workflow
can obtain GitHub’s signing private key.
permissions:
contents: read
id-token: write
attestations: write
id-token: write permits the job to request an OIDC
token; attestations: write permits storing the
generated attestation. For a container image pushed to a registry,
publishing may additionally need packages: write. Do
not grant unrelated repository write scopes.
5. Provenance and SBOM answer different questions
| Evidence | Primary question | What it does not prove |
|---|---|---|
| Build provenance | Who/what built these bytes, from which source/workflow context? | That the source is vulnerability-free or that every runtime component is safe. |
| SBOM | Which packages/components/relationships are reported for the subject? | That the build used a trusted workflow, or that the inventory is complete/accurate. |
| Digest | Are these bytes unchanged relative to the recorded subject? | Where the bytes came from or whether their contents are secure. |
| Release/package tag | Which human channel/version label was selected? | Immutability unless the ecosystem enforces it. |
An SBOM can be attested against the same subject digest as provenance. That gives a consumer two independently typed claims: “these bytes came from this build identity” and “this inventory describes these bytes.” The producer is still responsible for generating an inventory that actually reflects the shipped result. An SBOM produced only from source manifests can miss resolved, vendored, generated or post-build components.
6. Read-only inspection before any lab mutation
Start with tooling and repository metadata. These commands neither create an attestation nor request an OIDC token. They prove which repository/host you are about to use and whether your installed GitHub CLI exposes the current attestation verification surface.
gh --version
gh auth status
gh api -H "X-GitHub-Api-Version: 2026-03-10" user --jq '{login,id}'
gh attestation verify --help | sed -n '1,120p'
gh attestation trusted-root --help | sed -n '1,100p'
Important verifier controls currently include
--repo/--owner,
--signer-workflow, --signer-repo,
--source-ref, --source-digest,
--cert-oidc-issuer, and
--deny-self-hosted-runners. More constraints generally
create a stronger statement of what you expected—not a stronger
cryptographic algorithm.
7. SLSA: a broader model, not a GitHub badge
SLSA (Supply-chain Levels for Software Artifacts) is a broader specification maintained outside GitHub. The current SLSA specification is version 1.2 and its Build track still distinguishes Build L1 provenance existence, Build L2 hosted/authentic provenance, and Build L3 a hardened/isolated build platform. GitHub documentation currently describes artifact attestations by themselves as providing SLSA v1.0 Build Level 2 and describes a trusted reusable-workflow pattern as helping achieve Build Level 3.
Treat that GitHub statement as product guidance for a specific GitHub Actions architecture—not permission to label every repository “SLSA L3 certified.” A real claim must be evaluated against the applicable SLSA version/track requirements, the build platform, the producer’s workflow design, and consumer verification. SLSA is about supply-chain properties; it is not a guarantee that application code has no vulnerabilities.
8. Threat model: replay, substitution and wrong-builder trust
| Threat | Why a naive check fails | Policy/control |
|---|---|---|
| Artifact substitution | Filename/tag looks right but bytes differ | Hash actual bytes and verify attestation subject digest. |
| Wrong repository | Attacker has a valid attestation from their own repository |
Require expected --repo or owner/repository
identity.
|
| Wrong workflow/ref | Trusted repo has many workflows/branches | Require signer workflow and source ref/digest appropriate to release policy. |
| Self-hosted runner trust mismatch | Valid workflow identity ran on infrastructure outside your accepted trust zone | Use runner policy; GitHub CLI can reject self-hosted-runner attestations. |
| Replay of old valid artifact | Old bytes remain validly attested | Policy must also constrain release/version/source/ref/time/channel as needed. |
| Unverified evidence | Attestation exists but deployment never evaluates it | Make verification an explicit consumer/deployment gate. |
9. Why this matters in DevOps
CI/CD crosses administrative boundaries: source control builds software, package systems distribute it, and deployment systems consume it. Provenance gives the consumer a machine-verifiable bridge across those boundaries. Instead of trusting a filename or “the pipeline was green,” the deployment can ask whether the bytes have an accepted attestation and whether the authenticated workflow identity matches policy.
The highest-value change is cultural as much as cryptographic: producers publish evidence, but consumers verify it. GitHub itself warns that generating attestations alone provides no security benefit if no consumer verifies them.
Knowledge check
Why is a SHA-256 digest a stronger artifact identifier than a release filename?
The digest is derived from the bytes; a changed byte changes the digest. A filename is a mutable label and can be reused for different bytes.
What is the difference between provenance and an SBOM?
Provenance describes how/where/by whom the artifact was built; an SBOM inventories software components/relationships. They answer different trust questions and can be attested against the same subject.
A cryptographic attestation verifies, but it was signed by an unexpected repository. Should deployment accept it?
No. Cryptographic validity authenticates an identity; policy must also decide whether that repository/workflow/ref is trusted for this artifact.
Why does the workflow need
id-token: write?
GitHub uses an Actions OIDC token to establish workflow identity for the attestation. This is short-lived identity issuance, not access to a long-lived signing key.
Does a valid artifact attestation prove the software has no vulnerabilities?
No. It links exact bytes to authenticated build evidence. Security review, testing, vulnerability management and policy remain separate.
Summary
Artifact identity begins with bytes and digest. An attestation signs a typed claim about that subject; provenance explains the build, an SBOM inventories components, and the verifier validates both cryptography and expected builder identity. GitHub supplies an OIDC/Sigstore-backed implementation, while SLSA remains a broader supply-chain model whose levels must be evaluated carefully. Next you will build, attest, download, and verify a real disposable artifact.
Official references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.