tempusbuild/runner-images is a public image that executes customer code for tempus.build.
Its trust posture rests on two things: verifiable provenance and a transparent CVE policy.
This document explains how a consumer can verify all of it independently, and how to report a
vulnerability.
Image: ghcr.io/tempusbuild/runner-ubuntu-24.04
Tags: vYYYYMMDD and sha-<commit> (no floating :latest — consumers pin tag@sha256:...).
All images from main are signed with cosign keyless (Sigstore / Fulcio + Rekor, GitHub Actions
OIDC) and carry SLSA provenance and an SBOM attestation. The signature is applied only after a
green trivy scan of the published-by-digest artifact, so a valid signature means the image passed the
CVE gate. The SBOM predicate is too large for a transparency-log entry, so it is timestamped by the
Sigstore TSA (RFC3161) instead of logged to Rekor; the image signature and provenance are in Rekor.
Requires cosign (steps 1, 3) and the gh CLI (step 2).
Everywhere below, work against the immutable @sha256: digest rather than a floating tag.
IMAGE=ghcr.io/tempusbuild/runner-ubuntu-24.04
# Pin the digest of a specific image:
DIGEST=$(docker buildx imagetools inspect "${IMAGE}:vYYYYMMDD" --format '{{.Manifest.Digest}}')cosign verify \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"--certificate-identity-regexp binds the signature to the build.yml workflow on refs/heads/main
of this repository; --certificate-oidc-issuer binds it to GitHub OIDC. Any other identity/issuer is
not our build.
Build provenance is a Sigstore-signed attestation (actions/attest-build-provenance) pushed to the
registry next to the digest. Verify with the gh CLI:
gh attestation verify "oci://${IMAGE}@${DIGEST}" --owner tempusbuildA package-level CycloneDX SBOM is a cosign keyless attestation attached to the digest. Being too large for Rekor, it is TSA-timestamped instead of logged — so verification ignores the transparency log and checks the RFC3161 timestamp:
cosign verify-attestation \
--type cyclonedx \
--insecure-ignore-tlog \
--use-signed-timestamps \
--certificate-identity-regexp '^https://github\.com/tempusbuild/runner-images/\.github/workflows/build\.yml@refs/heads/main$' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
"${IMAGE}@${DIGEST}"--insecure-ignore-tlog only waives the Rekor lookup; identity, signature and the TSA timestamp are
still verified (the TSA cert chain comes from the Sigstore TUF root). The image signature in step 1 is
the cryptographic anchor; provenance and SBOM bind to the same digest.
- Build gate: every push to
mainis scanned bytrivyagainst the published digest with--severity HIGH,CRITICAL. An unhandled fixable HIGH/CRITICAL fails the build, which means the image is not signed and is not admitted to run by the consumer's admission policy. - Scope: the blocking gate is OS-scoped (
--scanners vuln --pkg-types os) — the apt/base layer this project patches directly (apt security updates + base-digest bump on the weekly rebuild). The image is a toolbox of pinned third-party tools (Node/Go/.NET/Ruby/Python CLIs, browsers, CodeQL, Selenium, …); CVEs inside those tools' bundled dependencies are addressed by keeping the tool versions current (Renovate proposes bumps as upstream ships fixes), not by an unmaintainable per-dependency ignore list — the same posture GitHub-hosted runner images take. Image secrets are covered bygitleaks(source) and Dockle (image), so trivy's secret scanner is not run. --ignore-unfixed: enabled. CVEs with no available fix do not block the build (nothing to fix), but are picked up automatically once upstream ships a patch — that is what the weekly rebuild (weekly-rebuild.yml) is for.- Documented exceptions live in
.trivyignore.yaml. Silent suppression and widening the severity filter are not allowed. Each exception carries:id— the CVE identifier;statement— the rationale (why the fix is unavailable/inapplicable for now);expired_at— the date after which trivy stops ignoring the CVE → forced re-triage.
- Review: exceptions and unfixed CVEs are re-checked on every weekly rebuild. An expired
expired_atfails the gate again until the decision is updated (a fix or an extended rationale).
The base image is pinned by sha256: digest; the bundled toolset (runner, language runtimes and
toolcaches, CLIs, build tools, browsers and drivers) by exact versions with SHA256/512-verified
downloads or key-verified vendor apt repositories; and all GitHub Actions by commit SHA. Pin
currency is maintained by:
weekly-rebuild.yml— a weekly rebuild with the same digest/pins (pulls apt package patches into the layers, refreshes attestations);- Renovate (
renovate.json) — proposes PRs to bump the base digest, action SHAs, and toolchain versions.
If you find a vulnerability in the image or the supply-chain pipeline:
- Preferably — privately via GitHub Security Advisories: "Report a vulnerability" on the
Security tab of this repository
(
https://github.com/tempusbuild/runner-images/security/advisories/new). - Do not open a public issue for an unpatched vulnerability.
We will acknowledge receipt and keep you posted on triage and the fix. Since the image is public and executes customer code, supply-chain reports are high priority.