---
title: "Verify a Release"
date: 2026-05-17
---

# Verifying a Release

Every release of the framework ships four independent attestations.
Verify any of them, they're orthogonal and each rules out a
different class of attack.

| Artefact | Format | Tool | Threat covered |
|----------|--------|------|----------------|
| **SBOM** (`dotfiles-sbom.spdx.json`) | SPDX 2.3 JSON | any SBOM viewer | "what's in the release?", full component inventory |
| **Cosign signature** (`.sig` + `.pem`) | sigstore keyless | `cosign verify-blob` | "did our CI actually produce this SBOM?", short-lived Fulcio cert + Rekor transparency-log entry |
| **SLSA provenance** (`.intoto.jsonl`) | in-toto v1 / SLSA L3 | `slsa-verifier` | "what build process produced this?", workflow ID, source ref, builder identity |
| **Unified manifest** (`ALL_SHA256SUMS` + `.sig` + `.pem`) | text + sigstore keyless | `cosign verify-blob` then `sha256sum -c` | "is every other asset on this release the one our CI produced?", one signed line per asset |

All four are attached to every GitHub Release as assets, from v0.2.503 forward.
Releases v0.2.500 through v0.2.502 carry the SBOM bundle only: the unified
manifest landed in v0.2.503 and is forward-only (re-tagging earlier releases
would break consumer pins on existing SHAs).

---

## TL;DR — verify v0.2.503+ end-to-end

```sh
# 0. Pick the release to verify
TAG=v0.2.503
REPO=sebastienrousseau/dotfiles

# 1. Download every attestation artefact
gh release download "$TAG" --repo "$REPO" \
  --pattern dotfiles-sbom.spdx.json \
  --pattern dotfiles-sbom.spdx.json.sig \
  --pattern dotfiles-sbom.spdx.json.pem \
  --pattern dotfiles-sbom.spdx.json.intoto.jsonl \
  --pattern ALL_SHA256SUMS \
  --pattern ALL_SHA256SUMS.sig \
  --pattern ALL_SHA256SUMS.pem

# 2. Verify Cosign signature on the SBOM (binds SBOM to CI workflow identity)
cosign verify-blob \
  --certificate dotfiles-sbom.spdx.json.pem \
  --signature  dotfiles-sbom.spdx.json.sig \
  --certificate-identity-regexp "^https://github.com/$REPO/" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  dotfiles-sbom.spdx.json

# 3. Verify SLSA provenance (binds SBOM to exact source tag + builder)
slsa-verifier verify-artifact dotfiles-sbom.spdx.json \
  --provenance-path dotfiles-sbom.spdx.json.intoto.jsonl \
  --source-uri "github.com/$REPO" \
  --source-tag "$TAG"

# 4. Verify the unified manifest, then verify every other asset against it.
#    One signed file covers all release artefacts in one shot.
cosign verify-blob \
  --certificate ALL_SHA256SUMS.pem \
  --signature  ALL_SHA256SUMS.sig \
  --certificate-identity-regexp "^https://github.com/$REPO/" \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ALL_SHA256SUMS

gh release download "$TAG" --repo "$REPO" --dir .  # pull every other asset
sha256sum -c ALL_SHA256SUMS                        # one line per asset
```

All four commands should print "Verified" / "PASSED" / "OK" and
exit 0. If any fails, **the release was tampered with**: open
an issue at <https://github.com/sebastienrousseau/dotfiles/issues>
and do **not** install.

---

## Tool installation

| Tool | macOS | Linux | Windows |
|------|-------|-------|---------|
| `gh` (GitHub CLI) | `brew install gh` | `apt install gh` / [release page](https://github.com/cli/cli/releases) | `scoop install gh` |
| `cosign` | `brew install cosign` | `curl -sSfL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o /usr/local/bin/cosign && chmod +x /usr/local/bin/cosign` | `scoop install cosign` |
| `slsa-verifier` | `brew install slsa-verifier` | `go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest` | `scoop install slsa-verifier` |

If you don't have Go installed, fetch the pre-built `slsa-verifier`
binary from <https://github.com/slsa-framework/slsa-verifier/releases>
(SHA256-verify per their release notes).

---

## What each verification actually proves

### `cosign verify-blob` succeeds

- The SBOM was signed by a workflow run **on this repository** (the
  `--certificate-identity-regexp` enforces it).
- The signing OIDC token was issued by **GitHub Actions** (the
  `--certificate-oidc-issuer` enforces it).
- The signature is recorded in the **Rekor public transparency log**
  (cosign queries this automatically) — anyone can audit it.
- The Cosign cert was issued by **Fulcio** (the sigstore CA) and
  was valid at the time of signing.

This **does not** prove what the build process did — only that
"the file you have is the file CI produced." For "what did CI do",
see SLSA verification below.

### `slsa-verifier verify-artifact` succeeds

- The SBOM digest matches a provenance statement.
- The provenance was generated by the **SLSA-Generator** running on
  **GitHub-hosted runners** for **this exact repository**.
- The build was triggered by the named tag (`--source-tag $TAG`).
- The provenance is anchored in Rekor (immutable, third-party-auditable).

SLSA Level 3 is achieved because: (a) the provenance is generated
by a *trusted, isolated* builder (slsa-github-generator), not by
us; (b) the builder runs with hermetic, non-falsifiable inputs;
(c) the provenance is signed by the builder's own identity, not
ours.

### What none of this proves

The framework's source code is **not formally verified**. SBOM +
SLSA + Cosign protect the *supply chain* (you got what we shipped)
— not the *correctness* (what we shipped does what we claim).

For correctness review:

- Code is open under MIT — read it. Start at `bin/dot`.
- CI runs ~75 checks per PR (shellcheck, shfmt, CodeQL, Semgrep, Codacy, etc.).
- Pre-commit hooks reject typos, unsigned commits, raw secrets.
- See `docs/security/SCORECARD.md` for the OpenSSF score posture.

---

## In-shell one-liner for ongoing verification

If you intend to install or update from a release tag, add this to
your shell startup (already in `dot_config/shell/*` for users who
run `chezmoi apply`):

```sh
verify-dot-release() {
  local tag="${1:-$(gh release view --json tagName --jq .tagName \
    --repo sebastienrousseau/dotfiles)}"
  local tmp
  tmp="$(mktemp -d)"
  ( cd "$tmp" \
    && gh release download "$tag" --repo sebastienrousseau/dotfiles \
      --pattern 'dotfiles-sbom.*' \
    && cosign verify-blob \
      --certificate dotfiles-sbom.spdx.json.pem \
      --signature  dotfiles-sbom.spdx.json.sig \
      --certificate-identity-regexp '^https://github.com/sebastienrousseau/dotfiles/' \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      dotfiles-sbom.spdx.json \
    && slsa-verifier verify-artifact dotfiles-sbom.spdx.json \
      --provenance-path dotfiles-sbom.spdx.json.intoto.jsonl \
      --source-uri github.com/sebastienrousseau/dotfiles \
      --source-tag "$tag"
  )
  local rc=$?
  rm -rf "$tmp"
  return $rc
}
```

Usage:

```sh
verify-dot-release             # verify latest
verify-dot-release v0.2.502    # verify specific tag
```

---

## If verification fails

1. **Don't install.** Stop the bootstrap script. `^C` any in-flight
   `chezmoi apply`.
2. **Compare assets**. The release page shows file sizes — if
   yours don't match what's on
   <https://github.com/sebastienrousseau/dotfiles/releases>, you
   downloaded from a man-in-the-middle.
3. **Report**: open an issue and email
   `security@sebastienrousseau.com` (encrypted to the WKD-published
   GPG key — fingerprint
   `55AFAD364FD9DB3819E61F0C8D688FAFA9144693`). Acknowledgement
   SLA: 72 hours per `.github/SECURITY.md`.

---

## See also

- `.github/SECURITY.md` — coordinated disclosure policy.
- `docs/security/KEY_ROTATION.md` — disclosure-key rotation procedure.
- `docs/security/SCORECARD.md` — OpenSSF Scorecard posture.
- `docs/operations/HARD_AUDIT_2026.md` Part 7 — the GPG key generation + WKD publication record.
- [Sigstore Cosign docs](https://docs.sigstore.dev/cosign/signing/overview/)
- [SLSA verifier docs](https://github.com/slsa-framework/slsa-verifier)
