Skip to content

Exact OCI vulnerability scanning

The exact release train scans the three independently built OCI subjects with Trivy 0.72.0 before release assembly. The gate is fail closed: only a signed, digest-pinned scanner, fresh digest-pinned databases, checked OCI archives, and zero HIGH or CRITICAL findings can produce passing evidence. This is the first and current contract; there is no compatibility or legacy scan path.

The retained document conforms to deploy/release/oci-vulnerability-scan-evidence.schema.json. It contains only cryptographic identities, timestamps, aggregate severity counts, fixed policy and execution assertions, privacy-safe scanner/database attestation digests, and one external signature over the whole document. It names exactly epistemic-graph, agent-utilities, and langfuse-agent as subjects.

Scanner and database acquisition

Acquire the Trivy 0.72.0 release asset by immutable identity in a connected, controlled staging step. Check its official release signature with a separately pinned verifier before the binary can enter the private scan bundle. The signed attestation binds the binary, release asset, release signature bundle, platform, and TLS-profile-reference digests. Mutable package aliases, install-to-shell mechanisms, unverified containers, and a scanner version other than 0.72.0 are rejected.

The fixed scanner release is intentional. A previously compromised Trivy release demonstrated why an unpinned latest binary or image is not an acceptable trust boundary. Consult the Trivy 0.72.0 release, official signature verification guide, and upstream security advisory when refreshing the controlled bundle.

Acquire both the vulnerability database and Java database from their official OCI artifacts by immutable manifest digest. Those database OCI subjects do not carry upstream cosign signatures, so the release contract does not claim or simulate an upstream signature. Instead, the controlled acquisition service checks TLS, the immutable OCI manifest digest, and the selected layer-archive digest before issuing a deployment-owned purpose: deployment-acquisition attestation. The policy-pinned external verifier accepts only that deployment acquisition authority. Its signature binds the manifest, layer archive, metadata, database-file, and opaque TLS-profile-reference digests.

The materialized vulnerability cache must contain exactly metadata.json and trivy.db; the Java cache must contain exactly metadata.json and trivy-java.db. Both metadata documents must parse at the trust boundary, use the expected schema version, match the attested updatedAt and nextUpdate values, and be fresh when the scan starts. A missing, extra, stale, malformed, redirected, or digest-mismatched database rejects the whole campaign; the scanner must not fall back to an embedded or network-fetched database.

Producing acquisition attestations

generate-oci-acquisition-attestation is the single current producer for the scanner attestation and both database attestations. It never fetches, resolves a registry, extracts an archive, or changes external trust. Run it only after the deployment acquisition boundary has checked TLS, the immutable upstream identities, and, for the scanner release, the official signature. Every input is then supplied as an owner-only regular file plus its expected sha256: digest. The producer re-hashes the opened descriptors, rejects aliases and mutation, and invokes deployment-controlled signer and verifier commands supplied as JSON argv arrays in OCI_SCAN_ATTESTATION_SIGNER_COMMAND and OCI_SCAN_ATTESTATION_VERIFIER_COMMAND. No shell command is constructed.

The scanner subcommand accepts the executable, release asset, official signature bundle, and pinned release-signature verifier. Its releaseBundleDigest is the SHA-256 digest of this canonical, ASCII JSON with no trailing newline:

{"releaseAssetDigest":"sha256:<64 lowercase hex>","releaseSignatureBundleDigest":"sha256:<64 lowercase hex>"}

The database subcommand accepts one exact OCI manifest, its one selected layer archive, and one already materialized private database directory. Choose --database-kind vulnerability for schema 2 and --database-kind java for schema 1. The manifest, layer descriptor, media type, title, database filenames, metadata keys, schema, timestamps, and freshness window are exact and fail closed. DownloadedAt must fall between UpdatedAt and attestation generation; generation must fall after UpdatedAt and no later than NextUpdate. Example invocation shapes are:

generate-oci-acquisition-attestation scanner \
  --scanner-binary "$SCANNER_BINARY" \
  --scanner-binary-sha256 "$SCANNER_BINARY_DIGEST" \
  --release-asset "$SCANNER_RELEASE_ASSET" \
  --release-asset-sha256 "$SCANNER_RELEASE_ASSET_DIGEST" \
  --release-signature-bundle "$SCANNER_RELEASE_SIGNATURE" \
  --release-signature-bundle-sha256 "$SCANNER_RELEASE_SIGNATURE_DIGEST" \
  --signature-verifier "$SCANNER_RELEASE_VERIFIER" \
  --signature-verifier-sha256 "$SCANNER_RELEASE_VERIFIER_DIGEST" \
  --tls-profile-ref "$RELEASE_TLS_PROFILE_REFERENCE" \
  --output "$SCANNER_ATTESTATION"

generate-oci-acquisition-attestation database \
  --database-kind vulnerability \
  --oci-manifest "$DATABASE_OCI_MANIFEST" \
  --oci-manifest-sha256 "$DATABASE_OCI_MANIFEST_DIGEST" \
  --layer-archive "$DATABASE_LAYER_ARCHIVE" \
  --layer-archive-sha256 "$DATABASE_LAYER_ARCHIVE_DIGEST" \
  --materialized-directory "$MATERIALIZED_DATABASE" \
  --metadata-sha256 "$DATABASE_METADATA_DIGEST" \
  --database-sha256 "$DATABASE_FILE_DIGEST" \
  --tls-profile-ref "$RELEASE_TLS_PROFILE_REFERENCE" \
  --output "$DATABASE_ATTESTATION"

Signing always receives canonical JSON bytes without a newline. Verification is mandatory before no-overwrite publication. The retained documents conform to deploy/release/oci-scanner-attestation.schema.json and deploy/release/oci-vulnerability-database-attestation.schema.json; they contain only cryptographic identities, bounded timestamps, fixed contract metadata, the opaque TLS-profile digest, and the external signature. Input locations, endpoint references, credentials, certificate material, command argv, and human or machine identities are never retained.

External trust and TLS

Network access exists only during the controlled scanner and database acquisition step. A tlsProfileRef selects externally managed trust material through AgentConfig and doctor. The adapter retains only its SHA-256 digest and requires the scanner and both database attestations to bind that same digest; the reference, resolved location, and certificate contents never enter release evidence or diagnostics.

Certificate verification is mandatory. The acquisition adapter must reject an empty, unresolved, inaccessible, aliased, or non-private trust profile. Options that disable TLS verification, permit plain HTTP, accept an insecure registry, or silently fall back to the platform trust store are forbidden. Endpoints, credentials, certificate identities, user identities, and filesystem locations remain external configuration and are never committed to the codebase.

Offline private-layout flow

After acquisition, disconnect network access and run this sequence:

  1. Create a new owner-only work directory on a Linux-native filesystem. Every transient layout, database copy, report, and evidence candidate is mode 0600; transient directories are mode 0700. Source inputs must be bounded, regular, unaliased, and immutable while opened; writable-by-group/world locations fail closed.
  2. Validate each no-overwrite OCI-layout archive with the canonical archive validator. Bind both its root descriptor digest and archive digest before any scanner invocation.
  3. Materialize one archive into one bounded private OCI layout without loading it into a daemon, shared image store, or long-running service. Reject links, special files, duplicate paths, traversal, descriptor mismatch, unexpected content, and resource-limit violations.
  4. Scan epistemic-graph, then agent-utilities, then langfuse-agent in that exact order. Maximum parallelism is one. The scanner runs in vulnerability mode against OS and language packages, uses complete detection, includes unfixed findings, emits all five severity aggregates, performs no database, Java database, check, VEX, or version update, makes no network request, and disables telemetry and progress output.
  5. Treat any scanner error, timeout, nonzero process status, malformed or oversized report, target mismatch, database freshness failure, archive change, or HIGH/CRITICAL count above zero as a campaign failure. Partial evidence and a passing status are not published.
  6. Hash the private raw report, reduce it immediately to severity counts, and build one canonical JSON document containing all three subjects. Independently check the scanner attestation and both deployment acquisition attestations, retain only their digests and successful verification assertions, externally sign and check the whole aggregate, then let the signed release manifest bind that certification-document digest.
  7. Remove every materialized layout, raw report, transient cache, expanded scanner bundle, and temporary trust file. Preserve only the immutable approved acquisition bundle under release policy and the signed aggregate evidence.

The invocation adapter must build an argument array and run it without a shell. It supplies the pinned binary, private cache, immutable databases, one validated OCI layout, fixed offline/update/telemetry controls, the fixed policy, and a private JSON output descriptor. Environment inheritance is an allowlist; stdout and stderr are bounded and discarded after conversion to stable error codes. Arguments from configuration cannot add scanner flags or override policy.

Evidence and privacy contract

Each subject binds its component name, OCI root digest, source archive digest, raw report digest, severity aggregates, and passing result. Top-level timestamps bound database freshness. Scanner fields attest the exact binary and checked release asset. Database fields attest deployment-checked immutable manifests and layer archives, payloads, metadata, schema versions, and freshness; they do not assert an upstream database signature. The exact policy object records the scanner mode, package classes, complete detection, all offline/update-suppression flags, severity set, sequential execution, and zero HIGH/CRITICAL limits.

The evidence deliberately excludes package names and versions, vulnerability IDs, individual findings, image names, raw scanner output, endpoints, filesystem locations, credentials, certificate material, and human or machine identities. The privacy object makes those omissions schema-enforced. The standard external signature binds the canonical aggregate. Release compatibility re-checks that signature and cross-binds each subject's OCI root and archive-input digests to component source evidence in the same signed release; a valid signature over a different artifact or trust profile is insufficient.

For controlled mirrors and air-gapped acquisition semantics, follow the self-hosting database guidance and air-gap guidance without weakening the immutable digest, signature, freshness, or TLS requirements.