How-to guide
Verify the image and SBOM
Confirm the Workbench container image you pulled is the one Elevarq published, before you run it. Verification uses public inputs only — no Elevarq-issued credentials are needed. Do this once per release tag you deploy.
This page covers how to verify the Workbench container image you pulled is the one Elevarq published, and how to retrieve its Software Bill of Materials. Verification uses public inputs only — no Elevarq-issued credentials are needed. Anyone who can pull the image can complete every step here; no access to the (private) Workbench source repository is required.
Tools
cosignv2.4+ or v3.x — install per the sigstore project's installation guide.jq— required, both to extract the SBOM from its attestation and to inspect it.docker(or any OCI client) to resolve the image tag to a digest.
Verify the image signature
Every release-tagged image is signed by the Workbench release workflow using Cosign keyless OIDC. The signing identity is the workflow itself, recorded in the public Rekor transparency log.
Resolve the image digest, then verify:
TAG=v0.3.0
DIGEST=$(docker buildx imagetools inspect \
"ghcr.io/elevarq/workbench:${TAG}" \
--format '{{json .}}' | jq -r '.manifest.digest')
cosign verify "ghcr.io/elevarq/workbench@${DIGEST}" \
--certificate-identity-regexp '^https://github.com/Elevarq/Workbench/\.github/workflows/release\.yml@.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com'
A successful verification prints:
Verification for ghcr.io/elevarq/workbench@sha256:...
The following checks were performed on each of these signatures:
- The cosign claims were validated
- Existence of the claims in the transparency log was verified offline
- The code-signing certificate was verified using trusted certificate authority certificates
A failure aborts with a non-zero exit. Do not run an image whose signature does not verify.
What verification proves
- The image was built and signed by the published Workbench release
workflow running on
Elevarq/Workbenchat the named tag. - The signing event was recorded in the public Rekor transparency log at the timestamp the certificate shows.
What verification does NOT prove
- That the image is free of bugs or security defects. Combine signature verification with the SBOM and your own scanning.
- That a particular license artefact loaded into Workbench is authentic — license verification is a separate path, performed by Workbench itself at activation time against the embedded public key ring.
- That the host running Workbench is hardened. Host-OS posture is your responsibility.
Retrieve and inspect the SBOM
The image's SPDX Software Bill of Materials is published as a Cosign
attestation on the image itself (predicate type spdxjson), signed by
the same keyless release identity as the image signature and recorded in
the public Rekor transparency log.
It is not a GitHub release asset, and it is not the deprecated
Cosign SBOM attachment — so cosign download sbom does not
retrieve it. Use cosign verify-attestation and extract the predicate:
DIGEST=... # the sha256:... resolved above
cosign verify-attestation \
--type spdxjson \
--certificate-identity-regexp '^https://github.com/Elevarq/Workbench/\.github/workflows/release\.yml@.*' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"ghcr.io/elevarq/workbench@${DIGEST}" \
| jq -r 'if type=="array" then .[0] else . end
| .payload | @base64d | fromjson | .predicate' \
> workbench.spdx.json
verify-attestation exits non-zero unless the attestation was signed by
the Elevarq release workflow and its transparency-log entry checks
out — so a successful extraction is itself the integrity guarantee. There
is no separate hash to download and compare.
Two portability details are already folded into the command:
- cosign's output shape differs by version — cosign v2 prints a JSON
array, cosign v3 prints a single JSON object.
if type=="array" then .[0] else . endhandles both. @base64ddecodes inside jq — so you do not depend on the non-portablebase64decode flag (GNU-d/--decodevs. BSD/macOS-D).
Inspect the extracted SBOM:
# Count packages.
jq '.packages | length' workbench.spdx.json
# List Go modules.
jq -r '.packages[] | select(.SPDXID | startswith("SPDXRef-Package-go-module-")) | .name + "@" + .versionInfo' \
workbench.spdx.json
# List Node.js packages.
jq -r '.packages[] | select(.SPDXID | startswith("SPDXRef-Package-npm-")) | .name + "@" + .versionInfo' \
workbench.spdx.json
The SBOM is produced from the registry image (not the source tree)
by syft, and enumerates every package in the released image — base OS
packages, Go modules, Node.js packages.
Air-gapped or offline verification
The attestation is an OCI referrer of the image, not part of the
image itself. A normal docker pull or docker save does not
necessarily include it. Offline verification is possible, but only when
the image, its signature, its SBOM attestation, and the trust material
cosign needs (the Fulcio root and Rekor public key, or an equivalent
offline bundle) are deliberately mirrored or exported together —
for example with cosign save / cosign load, or by copying the
referrers with an OCI tool that preserves them. Once all of those are
present in the offline registry or bundle, the same verify-attestation
command runs with no outbound network.
End-to-end verification script
A complete verification flow for a release digest:
#!/usr/bin/env bash
set -euo pipefail
TAG="${1:-v0.3.0}"
REPO="ghcr.io/elevarq/workbench"
ID_RE='^https://github.com/Elevarq/Workbench/\.github/workflows/release\.yml@.*'
ISSUER='https://token.actions.githubusercontent.com'
# 1. Resolve the tag to a digest.
DIGEST=$(docker buildx imagetools inspect "${REPO}:${TAG}" \
--format '{{json .}}' | jq -r '.manifest.digest')
echo "image: ${REPO}@${DIGEST}"
# 2. Verify the image signature.
cosign verify "${REPO}@${DIGEST}" \
--certificate-identity-regexp "${ID_RE}" \
--certificate-oidc-issuer "${ISSUER}" > /dev/null
echo "signature: verified"
# 3. Verify the SBOM attestation and extract it to a file.
cosign verify-attestation --type spdxjson "${REPO}@${DIGEST}" \
--certificate-identity-regexp "${ID_RE}" \
--certificate-oidc-issuer "${ISSUER}" \
| jq -r 'if type=="array" then .[0] else . end | .payload | @base64d | fromjson | .predicate' \
> "workbench-${TAG}.spdx.json"
jq -e '.spdxVersion and (.packages | type == "array")' "workbench-${TAG}.spdx.json" > /dev/null
echo "sbom: workbench-${TAG}.spdx.json ($(jq '.packages | length' "workbench-${TAG}.spdx.json") packages)"
Run that against a release digest before promoting an image to production.
Next
- Security posture.
- Operating Workbench — day-to-day operation.