Skip to content
GuidesVerify Your Install

Verify Your Drydock Install

Verify Drydock container images and release archives with cosign and GitHub attestations before deploying.

Every Drydock release is signed with cosign (keyless, via the Sigstore public-good infrastructure) and ships with SLSA build provenance attestations generated inside GitHub Actions. You can — and should — verify both before running the image or extracting the archive.

The examples on this page use v1.5.2 as a placeholder. Replace it with the tag you're verifying.

Starting with the release after v1.5.0-rc.10, the signing workflow changed from release-from-tag.yml@refs/tags/… to release-cut.yml@refs/heads/main as part of the tag-last release pipeline. The default identity regex below matches the new identity; older tags need the legacy regex shown at the bottom of this page.

What you need

ToolInstallUsed for
cosignsigstore/cosign releases or brew install cosignSignature verification
ghcli.github.com or brew install ghSLSA attestation verification (recommended)
slsa-verifierslsa-framework/slsa-verifierAlternate attestation verifier
sha256sumStandard on Linux; shasum -a 256 on macOSChecksum check

Everything is keyless — you do NOT need a Drydock-specific public key. Sigstore and GitHub's attestation framework use short-lived certificates tied to the release workflow's OIDC identity.

Verify container images

The release workflow signs every pushed tag (ghcr.io, docker.io, quay.io) with the same identity. Use this policy to verify:

TAG="v1.5.2"
VERSION="${TAG#v}"
IMAGE="ghcr.io/codeswhat/drydock:${VERSION}"
IDENTITY_REGEX='^https://github.com/CodesWhat/drydock/.github/workflows/release-cut.yml@refs/heads/main$'
OIDC_ISSUER='https://token.actions.githubusercontent.com'

cosign verify \
  --certificate-identity-regexp "${IDENTITY_REGEX}" \
  --certificate-oidc-issuer "${OIDC_ISSUER}" \
  "${IMAGE}"

Swap IMAGE for any of the three registries we publish to:

IMAGE="ghcr.io/codeswhat/drydock:1.5.2"
IMAGE="docker.io/codeswhat/drydock:1.5.2"
IMAGE="quay.io/codeswhat/drydock:1.5.2"

A successful verification prints the signature payload and exits 0. Any other outcome — failure, missing signature, identity mismatch — means do not run the image.

Verify image provenance (SLSA)

The container image also carries a signed SLSA provenance attestation published to the registry. Verify it with the GitHub CLI:

gh attestation verify \
  oci://ghcr.io/codeswhat/drydock:1.5.2 \
  --repo CodesWhat/drydock \
  --signer-workflow CodesWhat/drydock/.github/workflows/release-cut.yml

gh confirms that the image digest has a valid attestation from CodesWhat/drydock's release-cut.yml workflow. This command does not bind the image to the release tag; the tarball provenance check below performs the tag-bound verification.

Verify the release tarball

Each GitHub release includes six files for the source archive:

FilePurpose
drydock-${TAG}.tar.gzThe archive
drydock-${TAG}.tar.gz.sha256SHA-256 checksum
drydock-${TAG}.tar.gz.sigCosign detached signature
drydock-${TAG}.tar.gz.pemSigning certificate
drydock-${TAG}.tar.gz.bundleCosign bundle (sig + cert + Rekor proof)
drydock-${TAG}.tar.gz.intoto.jsonlSLSA provenance attestation

1. Download

TAG="v1.5.2"
BASE_URL="https://github.com/CodesWhat/drydock/releases/download/${TAG}"
ARCHIVE="drydock-${TAG}.tar.gz"

curl -fsSLO "${BASE_URL}/${ARCHIVE}"
curl -fsSLO "${BASE_URL}/${ARCHIVE}.sha256"
curl -fsSLO "${BASE_URL}/${ARCHIVE}.sig"
curl -fsSLO "${BASE_URL}/${ARCHIVE}.pem"
curl -fsSLO "${BASE_URL}/${ARCHIVE}.bundle"
curl -fsSLO "${BASE_URL}/${ARCHIVE}.intoto.jsonl"

2. Check the SHA-256

Fast integrity check. Doesn't prove authenticity — only that the bytes match what's on the release page.

sha256sum --check "${ARCHIVE}.sha256"
# drydock-v1.5.2.tar.gz: OK

On macOS, use shasum -a 256 -c "${ARCHIVE}.sha256".

3. Verify the cosign signature

This proves the tarball was signed by the Drydock release workflow at this tag.

IDENTITY_REGEX='^https://github.com/CodesWhat/drydock/.github/workflows/release-cut.yml@refs/heads/main$'
OIDC_ISSUER='https://token.actions.githubusercontent.com'

cosign verify-blob \
  --signature "${ARCHIVE}.sig" \
  --certificate "${ARCHIVE}.pem" \
  --certificate-identity-regexp "${IDENTITY_REGEX}" \
  --certificate-oidc-issuer "${OIDC_ISSUER}" \
  "${ARCHIVE}"
# Verified OK

4. Verify the SLSA provenance

The .intoto.jsonl file is a signed in-toto attestation describing how, when, and where the tarball was built. Two ways to verify:

gh attestation verify "${ARCHIVE}" \
  --repo CodesWhat/drydock \
  --signer-workflow CodesWhat/drydock/.github/workflows/release-cut.yml

gh downloads the attestation from GitHub, confirms the signing identity matches release-cut.yml, and verifies the subject digest matches your local file.

slsa-verifier verify-artifact \
  --provenance-path "${ARCHIVE}.intoto.jsonl" \
  --source-uri github.com/CodesWhat/drydock \
  --source-tag "${TAG}" \
  "${ARCHIVE}"

slsa-verifier reads the downloaded .intoto.jsonl file directly instead of fetching the attestation from GitHub. Verification is not fully offline: the verifier initializes Sigstore's trusted root through TUF, so it may still need network access to Sigstore trust material.

Passing both the cosign signature and the SLSA attestation confirms the tarball came from the release workflow, on this tag, and has not been modified.

Why some older tags look different

The Drydock release pipeline has been reshaped twice. Signatures embed the workflow file + ref that produced them, so the identity regex depends on which version of the pipeline signed the tag you're verifying:

# v1.5.0-rc.11 and newer (tag-last pipeline, signed by release-cut.yml on main):
IDENTITY_REGEX='^https://github.com/CodesWhat/drydock/.github/workflows/release-cut.yml@refs/heads/main$'

# v1.5.0-rc.1 through v1.5.0-rc.10 (tag-triggered pipeline, signed by release-from-tag.yml on the tag):
IDENTITY_REGEX='^https://github.com/CodesWhat/drydock/.github/workflows/release-from-tag.yml@refs/tags/.+$'

# v1.4.x and older (signed by release.yml):
IDENTITY_REGEX='^https://github.com/CodesWhat/drydock/.github/workflows/release.yml@refs/(heads/main|tags/.+)$'

The v1.5.0-rc.11 switchover moved image and artifact signing to happen before the git tag is pushed, so that a published tag always corresponds to a live, signed image. The old tag-triggered pipeline could produce a visible git tag without a corresponding signed image if the registry push failed mid-flight (see discussion #306).

Some older image tags also expose legacy sha256-<digest>.sig tags in registries. Newer releases store signatures via OCI referrers instead, so you may not see a .sig tag in the registry even though cosign verify succeeds.

If any verification step fails, do not run the image or extract the archive. Open a security advisory with the tag and the exact failure output — a verification failure on a published release is always worth investigating.

See also