How we verify images
Why this page exists
The trust badges on each container card link here so anyone can replicate every check independently. We surface SBOM attestations, Trivy scan results, multi-arch manifests, and upstream dependency tracking — not to ask you to trust a badge, but to give you the exact commands to verify them yourself.
Verifying the SBOM attestation
Each container’s SBOM is signed via Sigstore using actions/attest-sbom. The attestation is anchored to the image digest and recorded in the GitHub attestations API, which is publicly accessible without authentication. To verify locally using the GitHub CLI:
$ gh attestation verify oci://ghcr.io/oorabona/<container>:<tag> --owner oorabona
The SBOM badge in each container card opens the public attestation viewer directly in your browser — no login required. For example, a direct URL looks like https://github.com/oorabona/docker-containers/attestations/<id>. The viewer shows the SBOM payload, the Sigstore bundle, and the signing certificate chain.
Reading Trivy scan results
Trivy scans run on every build in advisory mode: findings do not block the build, but they are surfaced. Results are uploaded to GitHub via github/codeql-action/upload-sarif, which populates the Code Scanning API. Note that the Security tab UI in GitHub requires authentication even for public repos — that is why each container’s detail page embeds the scan summary directly. To query findings programmatically with any authenticated GitHub session (gh auth login is enough; no special scope is required):
$ gh api repos/oorabona/docker-containers/code-scanning/alerts \
--paginate \
-q '.[] | {rule_id: .rule.id, severity: .rule.severity, category: .most_recent_instance.category, package: .most_recent_instance.location.path}'
To filter findings to a single container variant, match on the category field, which encodes the container name and platform:
# Replace the category value with the variant you want to inspect
$ gh api repos/oorabona/docker-containers/code-scanning/alerts --paginate \
-q '.[] | select(.most_recent_instance.category == "container-postgres-18-alpine-linux/amd64")'
Per-severity breakdown
Each container’s detail page surfaces all scanned severities (CRITICAL → INFO). CRITICAL gets the strongest visual emphasis (red ring); HIGH gets a warning emphasis. MEDIUM, LOW, and INFO render as advisory context with neutral styling. Findings tagged UNKNOWN by Trivy (severity not classified upstream) are bucketed into the INFO column. All findings, including non-blocking ones, are uploaded to GitHub Code Scanning under category container-<name>-<tag>-<platform>; query the full advisory list via the gh api command above.
The scan policy runs all severities (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) in advisory mode — full scan chosen for transparency over alert-list cleanliness. continue-on-error: true is permanent policy — no severity level blocks the build. The severity parameter lives in .github/actions/build-container/action.yaml (vulnerability_severity input, default UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) and can be narrowed per-call if alert volume becomes operationally noisy.
Inspecting multi-arch manifests
Multi-arch images publish a manifest list that references per-platform image manifests. To see which CPU architectures are present for any tag:
$ docker manifest inspect ghcr.io/oorabona/<container>:<tag>
Look at the manifests array in the output — each entry’s platform.architecture field reveals the published architectures. Multi-arch images list both amd64 and arm64; single-arch images list one. The architecture badge on each card reflects this inspection at build time.
Auditing dependency monitoring
Daily upstream monitoring runs via .github/workflows/upstream-monitor.yaml. Each container’s config.yaml declares dependency_sources, which lists the upstream packages to watch. When a new upstream version is available, the workflow opens an automatic pull request with the version bump. To audit the monitoring history and open PRs:
- Workflow run history: https://github.com/oorabona/docker-containers/actions/workflows/upstream-monitor.yaml
- The dependency badge on each card shows how many sources are tracked daily and links to that same workflow page.
Nothing in this pipeline is opaque: the version.sh script in each container directory implements the upstream query logic, and the workflow YAML is the complete source of truth for scheduling and automation.
Reproducing builds locally
Every container build is driven by shell scripts with no opaque CI steps. To reproduce a build on your own machine:
$ git clone https://github.com/oorabona/docker-containers.git
$ cd docker-containers
$ ./make build <container> [version]
BuildKit must be enabled (DOCKER_BUILDKIT=1 or Docker 23+). The ./make entry point accepts the same arguments as the CI pipeline. See each container’s README.md and the top-level docs/ directory for full build documentation, including multi-variant matrix builds, extension layers, and SBOM generation.
Frequently asked questions
Why does the dashboard show “Trivy scan results are advisory”?
Trivy runs as continue-on-error in CI. The build does not fail when CVEs are detected; it surfaces the count for the operator to triage. Use the count as input to your image-acceptance policy, not as a blocking gate.
What does the SBOM badge state mean?
The badge has two states. ATTESTED means both attestation_url and attestation_id are present in the published lineage record — the SBOM has been signed via Sigstore and is verifiable with cosign. PENDING covers all other cases (no attestation yet, or partial data) and indicates the image will be re-attested on the next successful build.
How is the SBOM signed?
Each successful build runs anchore/sbom-action to generate an SPDX JSON SBOM, then actions/attest-sbom signs it via Sigstore (keyless, OIDC-based) and uploads the attestation to GHCR. You can verify with gh attestation verify oci://ghcr.io/oorabona/<image>:<tag> --owner oorabona.
Can I trust a container that shows “SBOM PENDING”?
It is not a security flag. PENDING means the build pipeline has not yet re-run since the image was published, or the attestation pipeline encountered a transient failure that will be retried. Pull by digest from a previous attested build if you need verifiable SBOM provenance immediately.
How fresh are the Trivy scan dates shown on the dashboard?
The “SCANNED YYYY-MM-DD” timestamp on each Trivy badge reflects the most recent successful Trivy run for the corresponding image variant. Scans run on every build; if a container has not been rebuilt for an extended period, the date will reflect that staleness.
Four steps that take you from a published image digest to a verified SBOM, scanned CVE inventory, and locally-rebuilt container.
-
Verify the SBOM attestation
Each SBOM is signed via Sigstore (
actions/attest-sbom) and anchored to the image digest. The attestation lives in GitHub's public attestations API — no auth needed.bash$ gh attestation verify oci://ghcr.io/oorabona/<container>:<tag> --owner oorabonaThe SBOM badge on each container card opens the public attestation viewer in your browser — SBOM payload, Sigstore bundle, and signing certificate chain visible without login.
-
Read the Trivy scan results
Trivy scans run on every build in advisory mode. Results land in GitHub's Code Scanning API and are queryable with any authenticated
ghsession — no special scope required.bash$ gh api repos/oorabona/docker-containers/code-scanning/alerts \ --paginate \ -q '.[] | {rule_id: .rule.id, severity: .rule.severity, category: .most_recent_instance.category, package: .most_recent_instance.location.path}'To filter to a single variant, match on the
categoryfield — it encodes the container name and platform (e.g.container-postgres-18-alpine-linux/amd64). The dashboard surfaces all scanned severities (CRITICAL through INFO); CRITICAL and HIGH are visually emphasised, the rest render as advisory context. TrivyUNKNOWNfindings (severity unclassified upstream) are bucketed into the INFO column. -
Inspect the multi-arch manifest
Multi-arch images publish a manifest list referencing per-platform image manifests. To see the published architectures of any tag:
bash$ docker manifest inspect ghcr.io/oorabona/<container>:<tag>Look at the
manifestsarray — each entry'splatform.architecturereveals the published architectures. The architecture badge on each container card reflects this inspection at build time. -
Reproduce the build locally
Every container is built by shell scripts with no opaque CI steps. Clone the repo and run the same entry point the pipeline uses:
bash$ git clone https://github.com/oorabona/docker-containers.git $ cd docker-containers $ ./make build <container> [version]BuildKit must be enabled (
DOCKER_BUILDKIT=1or Docker 23+). Compare the resulting digest against the dashboard's published digest to confirm reproducibility.
Frequently asked questions
Why does the dashboard show "Trivy scan results are advisory"?
Trivy runs as continue-on-error in CI. The build does not fail when CVEs are detected; it surfaces the count for the operator to triage. Use the count as input to your image-acceptance policy, not as a blocking gate.
What does the SBOM badge state mean?
ATTESTED means both attestation_url and attestation_id are present in the published lineage record — the SBOM has been signed via Sigstore and is verifiable. PENDING covers all other cases and indicates the image will be re-attested on the next successful build.
How is the SBOM signed?
Each successful build runs anchore/sbom-action to generate an SPDX JSON SBOM, then actions/attest-sbom signs it via Sigstore (keyless, OIDC-based) and uploads the attestation to GHCR. Verify with gh attestation verify oci://ghcr.io/oorabona/<image>:<tag> --owner oorabona.
Can I trust a container that shows "SBOM PENDING"?
It is not a security flag. PENDING means the build pipeline has not yet re-run since the image was published, or the attestation pipeline hit a transient failure that will be retried. Pull by digest from a previous attested build if you need verifiable SBOM provenance immediately.
How fresh are the Trivy scan dates shown on the dashboard?
The "SCANNED YYYY-MM-DD" timestamp on each Trivy badge reflects the most recent successful Trivy run for the corresponding image variant. Scans run on every build; if a container has not been rebuilt for an extended period, the date will reflect that staleness.