Skip to content

Verifying a release

Every v* release of Data Prism publishes four kinds of evidence, so you can check that what you run is what the project built:

Artifact Where Evidence
Maven jars Maven Central, group io.github.aindriub GPG signature (.asc), CycloneDX SBOM, build provenance
Container images ghcr.io/aindriub/data-prism-server and the four data-prism-quickstart-* images keyless cosign signature, build provenance, SBOM attestation
SBOM files the GitHub Release page and Maven Central (the same files from 0.7.1) build provenance

All commands below use placeholders in angle brackets. Replace <version> with the release version without the leading v (for example 0.7.0).

Maven Central artifacts

GPG signature

Every file Central serves for a module has a detached .asc signature made with the project release key (key ID FC5E68A44A325696). Check a jar:

base=https://repo1.maven.org/maven2/io/github/aindriub/data-prism-core/<version>
curl -fsSLO "$base/data-prism-core-<version>.jar"
curl -fsSLO "$base/data-prism-core-<version>.jar.asc"
gpg --keyserver hkps://keys.openpgp.org --recv-keys FC5E68A44A325696
gpg --verify data-prism-core-<version>.jar.asc data-prism-core-<version>.jar

Expected: Good signature from the project release key. gpg prints using RSA key FC2DB94A7891425639F53AEF697F862CDC47EBF1, which is the signing subkey, and the primary key fingerprint is 7B633FA5CC84CDE87C1701A9FC5E68A44A325696 (its key ID, the last 16 digits, is FC5E68A44A325696). Check that the primary fingerprint matches. A BAD signature or a different key means do not use the file.

SBOM

Each deployed module carries a CycloneDX JSON SBOM with the classifier cyclonedx, itself GPG-signed like any other file in the bundle:

curl -fsSLO "$base/data-prism-core-<version>-cyclonedx.json"
curl -fsSLO "$base/data-prism-core-<version>-cyclonedx.json.asc"
gpg --verify data-prism-core-<version>-cyclonedx.json.asc data-prism-core-<version>-cyclonedx.json
jq '.components | length' data-prism-core-<version>-cyclonedx.json

Build provenance

The jars and SBOMs Central received are attested by the publish-central.yml workflow. Download the jar and verify it against the repository:

gh attestation verify data-prism-core-<version>.jar \
  --repo AindriuB/data-prism \
  --signer-workflow AindriuB/data-prism/.github/workflows/publish-central.yml

Expected identity: the attestation was produced by the publish-central.yml workflow of the AindriuB/data-prism repository, run from the v<version> tag.

Container images

The images are ghcr.io/aindriub/data-prism-server and ghcr.io/aindriub/data-prism-quickstart-{server,fixtures,issuer,certs-init}. Resolve a tag to its digest first, and verify the digest, not the tag. That digest is the manifest list, and the manifest list is the object to verify:

image=ghcr.io/aindriub/data-prism-server
digest=$(docker buildx imagetools inspect "$image:<version>" --format '{{json .Manifest}}' | jq -r .digest)

Signature

Images are signed keylessly with cosign, using the GitHub Actions identity of the publish-image.yml workflow. Cosign v3 or later is required: the signatures are stored only as sigstore bundle v0.3 OCI referrers, with no legacy .sig tags, and cosign v2 will not find them.

Each image's manifest list is signed and attested, and from 0.7.1 so is every per-architecture digest reachable from a published tag. Verify the digest you resolved from the tag (the manifest list), or the digest of any linux/amd64 or linux/arm64 platform manifest in it, with the same command. The list also holds entries with platform unknown/unknown (annotation vnd.docker.reference.type: attestation-manifest). Those are the buildx SBOM and provenance payloads, which the signatures above cover; they are not signed on their own and cosign verify on one fails. The release workflow verifies the list and every real platform manifest, and fails the release if one is unsigned.

Releases up to and including 0.7.0 are different. Assembling their manifest list flattened the signed per-architecture build indexes into plain platform manifests, so the platform digests found from the tag carry no cosign signature, attestation or SBOM of their own, and cosign verify on one fails. The signed build indexes exist, and their digests are recorded in the log of the publish-image run. For those releases, verify the manifest list; do not treat a failure on a platform digest as a sign of tampering.

cosign verify \
  --certificate-identity-regexp '^https://github\.com/AindriuB/data-prism/\.github/workflows/publish-image\.yml@refs/tags/v.+$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  "$image@$digest"

To verify one platform manifest (from 0.7.1), take its digest from the list and use the same command:

platform=$(docker manifest inspect "$image:<version>" \
  | jq -r '.manifests[] | select(.platform.architecture == "arm64") | .digest')
cosign verify \
  --certificate-identity-regexp '^https://github\.com/AindriuB/data-prism/\.github/workflows/publish-image\.yml@refs/tags/v.+$' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  "$image@$platform"

Expected identity: the workflow AindriuB/data-prism/.github/workflows/publish-image.yml at a v* tag, issued by https://token.actions.githubusercontent.com. The signature is also recorded in the public Rekor transparency log, which names the repository and workflow. Tighten the regexp to @refs/tags/v<version>$ to pin one release.

Build provenance

gh attestation verify "oci://$image@$digest" \
  --repo AindriuB/data-prism \
  --signer-workflow AindriuB/data-prism/.github/workflows/publish-image.yml

Expected: the attestation names the publish-image.yml workflow of AindriuB/data-prism at the v<version> tag. The images additionally carry the BuildKit provenance attestation (SLSA, mode=max) described below.

SBOM

The build attaches an SBOM attestation to every image. For a multi-platform image, .SBOM is keyed by platform, so index it by platform; run this against the manifest list digest to show both:

for platform in linux/amd64 linux/arm64; do
  count=$(docker buildx imagetools inspect "$image@$digest" \
    --format "{{json (index .SBOM \"$platform\")}}" | jq -e '.SPDX.packages | length') \
    || { echo "no SBOM for $platform"; exit 1; }
  echo "$platform: $count packages"
done

Expected: a non-zero package count for each platform; a missing platform key fails loudly. For the provenance use .Provenance the same way.

On a per-architecture build index (for 0.7.0 and earlier, its digest is in the publish-image run log; an index holding one platform plus its attestation manifest), buildx prints .SBOM and .Provenance unkeyed, so drop the index. The plain platform digests found from the tag do not carry these:

docker buildx imagetools inspect "$image@<per-arch-digest>" \
  --format '{{json .SBOM}}' | jq -e '.SPDX.packages | length'
docker buildx imagetools inspect "$image@<per-arch-digest>" \
  --format '{{json .Provenance}}'

Both are attestation manifests stored in the registry next to the image, and the manifest list's signature covers them.

GitHub Release assets

From 0.7.1 the SBOM files attached to the GitHub Release are the very files in the Central bundle: the publish-central.yml workflow copies them from the bundle it uploaded and asserts the SHA-256 of each matches. They carry the build provenance of that workflow:

gh release download v<version> --repo AindriuB/data-prism --pattern '*-cyclonedx.json'
gh attestation verify data-prism-core-<version>-cyclonedx.json \
  --repo AindriuB/data-prism \
  --signer-workflow AindriuB/data-prism/.github/workflows/publish-central.yml

Expected identity: the publish-central.yml workflow of AindriuB/data-prism, run from the v<version> tag. For 0.7.0 and earlier the release assets came from a second build in release.yml and differ byte for byte from Central's; verify them with --signer-workflow AindriuB/data-prism/.github/workflows/release.yml.

What this does and does not prove

A valid signature and attestation show the artifact was built by the named workflow in the named repository from the tagged commit. They do not show the code is free of defects, and an SBOM lists components, not their vulnerabilities. Report a security problem as described in SECURITY.md.