docs/verify-release.md
Rama main · réplica de lectura del repositorio original.
# Verifying a Crux release
Every Crux release (tag `v*`) ships with a verifiable supply chain — threat
ref **T.5** in [THREAT_MODEL.md](THREAT_MODEL.md):
| Artifact | What proves it |
|---|---|
| Native release binaries (`corecruxd-*`, `crux-*`, `corecruxctl-*`, `crux-hook-*` for `linux-amd64` and both Darwin targets) | cosign keyless signature (`.sig` + `.pem` per file) + SLSA v1.0 provenance |
| Cross Linux release binaries (the same four prefixes for `linux-musl-amd64` and `linux-arm64`) | cosign keyless signature; not yet included as SLSA subjects |
| `RELEASE-MANIFEST-<target>.txt` | signed sha256 list covering every file in the release package (licences, docs, content) |
| `install.sh` | cosign keyless signature (`install.sh.sig` + `install.sh.pem`) and coverage by `RELEASE-MANIFEST-linux-amd64.txt` |
| `crux-daemon-<target>.cdx.json` | signed CycloneDX 1.6 SBOM of the workspace, per target |
| `multiple.intoto.jsonl` | SLSA provenance for native-target binaries, SBOMs, and manifests, generated by the SLSA L3 builder |
| Container image `ghcr.io/cuecrux/crux-daemon` | cosign keyless signature + CycloneDX SBOM attestation, both digest-addressed |
All signatures are **keyless** (Sigstore): short-lived certificates bound to
the GitHub Actions workflow identity, logged in the Rekor transparency log.
There is no long-lived signing key that can leak — what you verify is "this
exact artifact was built by the release workflow of `CueCrux/Crux` at this
tag".
Tooling: [`cosign`](https://docs.sigstore.dev/cosign/system_config/installation/)
and [`slsa-verifier`](https://github.com/slsa-framework/slsa-verifier#installation).
Set the tag you are verifying once:
```bash
TAG=v0.5.0 # the release you downloaded
REPO=CueCrux/Crux
```
## 1. Verify a release binary
Download the binary, its `.sig` and `.pem` from the GitHub Release, then:
```bash
cosign verify-blob \
--certificate corecruxd-linux-amd64.pem \
--signature corecruxd-linux-amd64.sig \
--certificate-identity "https://github.com/${REPO}/.github/workflows/release.yml@refs/tags/${TAG}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
corecruxd-linux-amd64
```
Expected output: `Verified OK`. Repeat for `crux-<target>`,
`corecruxctl-<target>`, `crux-hook-<target>`, the SBOM and the manifest (same
flags, different filenames).
Before running the installer, verify `install.sh` with the same command and
workflow identity, using `install.sh.pem` and `install.sh.sig`.
## 2. Verify the whole package via the signed manifest
The licence/docs/content files are not individually signed; they are covered
by the signed manifest:
```bash
cosign verify-blob \
--certificate RELEASE-MANIFEST-linux-amd64.txt.pem \
--signature RELEASE-MANIFEST-linux-amd64.txt.sig \
--certificate-identity "https://github.com/${REPO}/.github/workflows/release.yml@refs/tags/${TAG}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
RELEASE-MANIFEST-linux-amd64.txt
sha256sum --check --ignore-missing RELEASE-MANIFEST-linux-amd64.txt
```
Manifest entries use the flat public release-asset filenames. Download the
assets you want to verify into the same directory as the manifest; nested
repository staging paths do not need to be recreated. The release workflow
rejects duplicate basenames before publishing, so every checksum maps to one
unambiguous public asset.
The linux-amd64 manifest includes `install.sh`; the checksum command therefore
provides a second, manifest-rooted check when both files are present.
## 3. Verify SLSA provenance
`multiple.intoto.jsonl` (a release asset) attests that each native-target
binary was built from this repository at this tag by the SLSA L3 trusted
builder:
```bash
slsa-verifier verify-artifact corecruxd-linux-amd64 \
--provenance-path multiple.intoto.jsonl \
--source-uri "github.com/${REPO}" \
--source-tag "${TAG}"
```
Expected output ends with `PASSED: SLSA verification passed`.
The `linux-musl-amd64` and `linux-arm64` cross-build legs are cosign-signed but
are not yet subjects in `multiple.intoto.jsonl`; do not claim a SLSA pass for
those files. Their signatures and signed release manifests remain verifiable
with steps 1 and 2.
## 4. Verify the container image
Always verify by digest, never by floating tag:
```bash
IMAGE=ghcr.io/cuecrux/crux-daemon:${TAG#v}
DIGEST_REF=$(cosign triangulate --type digest "${IMAGE}" 2>/dev/null || docker buildx imagetools inspect "${IMAGE}" --format '{{json .Manifest.Digest}}' | xargs -I{} echo "ghcr.io/cuecrux/crux-daemon@{}")
cosign verify \
--certificate-identity "https://github.com/${REPO}/.github/workflows/docker.yml@refs/tags/${TAG}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${DIGEST_REF}"
```
And the SBOM attestation attached to the image:
```bash
cosign verify-attestation \
--type cyclonedx \
--certificate-identity "https://github.com/${REPO}/.github/workflows/docker.yml@refs/tags/${TAG}" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${DIGEST_REF}" \
| jq -r '.payload' | base64 -d | jq '.predicate.metadata'
```
Note: images built from `main` merges (the `edge` tag) are signed with
identity `…/docker.yml@refs/heads/main` instead of the tag ref.
## 5. Inspect the SBOM
```bash
jq '.components | length' crux-daemon-linux-amd64.cdx.json # dependency count
jq -r '.components[] | "\(.name) \(.version)"' crux-daemon-linux-amd64.cdx.json | sort
```
Feed it to any CycloneDX-aware scanner (`trivy sbom crux-daemon-linux-amd64.cdx.json`,
Dependency-Track, etc.) to re-scan the exact dependency set that shipped.
## What failure looks like
- A tampered binary fails step 1 with `Error: searching log query matched zero entries` or a hash mismatch.
- A binary rebuilt outside CI fails step 3 (`FAILED: SLSA verification failed`) because no provenance exists for its hash.
- An image re-pushed by an attacker with `packages: write` fails step 4 — they cannot mint a certificate for the `docker.yml` workflow identity.
If any verification fails, do not run the artifact; report it via
[SECURITY.md](../SECURITY.md).