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:
- 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 mode0700. Source inputs must be bounded, regular, unaliased, and immutable while opened; writable-by-group/world locations fail closed. - 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.
- 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.
- Scan
epistemic-graph, thenagent-utilities, thenlangfuse-agentin 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. - 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.
- 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.
- 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.