Verify a release
Check the cosign signatures, SBOM and provenance of the images, the chart and the CRD bundle before you deploy them.
Every release is built and published on GitHub Actions by
weebo-operator-kit's reusable publish.yml workflow (called by this
repository's), and signed keylessly with
cosign: there is no long-lived key; each
signature carries a certificate that names the workflow and the tag that
produced it, recorded in the public Rekor transparency log.
You need cosign 2.x or later.
The identity to expect
| Field | Value |
|---|---|
| OIDC issuer | https://token.actions.githubusercontent.com |
| Identity | https://github.com/batleforc/weebo-operator-kit/.github/workflows/publish.yml@refs/tags/vA.B.C (the kit's workflow, at the kit release this one uses) |
| Repository | batleforc/weebo-forgejo (the certificate's GitHub Workflow Repository) |
The signing workflow is the kit's, so the identity names the kit; the
repository it ran for is checked separately (--certificate-github-workflow-repository).
export COSIGN_ID='^https://github.com/batleforc/weebo-operator-kit/\.github/workflows/publish\.yml@refs/tags/v.*$'
export COSIGN_ISSUER=https://token.actions.githubusercontent.com
export COSIGN_REPO=batleforc/weebo-forgejoImages
IMAGE=ghcr.io/batleforc/weebo-forgejo-operator:vX.Y.Z # or vX.Y.Z-static
cosign verify "$IMAGE" \
--certificate-identity-regexp "$COSIGN_ID" \
--certificate-github-workflow-repository "$COSIGN_REPO" \
--certificate-oidc-issuer "$COSIGN_ISSUER"Verification succeeds for the multi-arch index and each platform image. Then pin what you verified by digest:
DIGEST=$(docker buildx imagetools inspect "$IMAGE" --format '{{json .Manifest}}' | jq -r .digest)
helm upgrade --install weebo-forgejo oci://ghcr.io/batleforc/charts/weebo-forgejo \
--version X.Y.Z -n weebo-forgejo --set image.digest="$DIGEST"To enforce signatures at admission, use a policy engine (Sigstore
policy-controller, Kyverno verifyImages, …) with the same identity and
issuer.
SBOM and provenance
Both are BuildKit attestations attached to the image index:
# SPDX SBOM of the amd64 image
docker buildx imagetools inspect "$IMAGE" --format '{{json (index .SBOM "linux/amd64").SPDX}}'
# SLSA provenance (mode=max: build args, sources, steps)
docker buildx imagetools inspect "$IMAGE" --format '{{json (index .Provenance "linux/amd64").SLSA}}'Helm chart
The chart is an OCI artifact signed the same way:
cosign verify ghcr.io/batleforc/charts/weebo-forgejo:X.Y.Z \
--certificate-identity-regexp "$COSIGN_ID" \
--certificate-github-workflow-repository "$COSIGN_REPO" \
--certificate-oidc-issuer "$COSIGN_ISSUER"Note the chart tag has no v prefix.
CRD bundle
weebo-forgejo-crds.yaml on the GitHub Release comes with its Sigstore
bundle:
cosign verify-blob weebo-forgejo-crds.yaml \
--bundle weebo-forgejo-crds.yaml.sigstore.json \
--certificate-identity-regexp "$COSIGN_ID" \
--certificate-github-workflow-repository "$COSIGN_REPO" \
--certificate-oidc-issuer "$COSIGN_ISSUER"What the pipeline checks before signing
- The chart version and
appVersion(and the Cargo workspace version) equal the tag. - The kind end-to-end suite passes on the tagged code, both images, including an upgrade from the previous release.
- Each image is scanned by trivy (no HIGH/CRITICAL) and smoke-run, before the push for amd64 and on the pushed digest for every platform.
Only then are the image, the chart and the CRD bundle signed and the GitHub Release created.