Skip to main content
Version: 0.1.0-alpha.5 (alpha)

Bounded OCI registry adapter

latent-oci::HttpOciRegistry transfers exact package bytes through one operator-approved registry origin and repository. It supports package push, tag/digest resolution, manifest/blob pull, complete package pull and native OCI 1.1 referrer discovery. Capsule, browser-assets, SSR and detached-evidence envelopes use the package format.

This Rust library handles registry transport. The packager checks package structure and supplied component semantics; node admission checks publisher, build and SBOM evidence before making a publication eligible. For application delivery, use the static-site or Angular workflow.

The separate publisher verifier can authenticate pulled signature evidence against explicit current policy/revocation snapshots. The builder verifier authenticates provenance through separate builder anchors and source requirements. Neither result admits a catalog release.

Versioned transport profiles​

ADR-0029 and RFC-0003 separate the registry's permanent authority/ownership boundary from transport interoperability choices.

lsf-oci-static-v1 is the supported profile for static credentials and addresses:

  • one explicit HTTPS origin and repository;
  • operator-supplied socket addresses for hostname origins, with no runtime DNS;
  • anonymous, explicit Basic or preissued Bearer credentials;
  • no token-service exchange or refresh;
  • no HTTP redirects; upload locations and pagination continuations remain within the existing origin/repository rules;
  • native OCI 1.1 referrers only; no mutable legacy referrers-tag fallback.

lsf-oci-bearer-v1 has an implemented bounded authentication layer: challenge parsing, coalesced token acquisition/refresh, explicit identity/credential epochs and preauthenticated writes without replay. Its explicit network policy adds bounded DNS, connected-peer checks and authorized credential-free content redirects, with real topology conformance. Static credential callers remain on the static profile; an upgrade does not silently authorize DNS, token services or redirect targets.

The support matrix names the exact demonstrated fixture topologies:

Registry/versionProfileAuthentication/topologyPush/pullNative referrersCurrent status
Zot minimal 2.1.18, pinned sha256:f1ffb7a5bbddc0feea83646e29c587ecf39b3193733b447749d4c9ead111a395lsf-oci-static-v1ephemeral TLS loopback origin, explicit Basic credentialdemonstrateddemonstratedsupported repository fixture
Harbor 2.15.2lsf-oci-bearer-v1private project, approved same-origin token realm, explicit DNS and verified TLS; local storagedemonstrateddemonstratedsupported owned fixture; storage redirects separately tested with controlled TLS peers
Distribution 3.1.1no complete LSF evidence profiledeployment-specificpackage transfer can interoperateunavailable in the currently documented tested surfaceexplicit complete-profile exclusion

The Harbor fixture records exact release/container and source identities, uses disposable TLS, a private project and least-privilege credentials, bounds local container resources, and destroys only resources it owns. It proves exact push, digest-pinned pull, native referrers and denied DNS authority. Its local storage does not prove compatibility with hosted object-storage redirects: see the precise network evidence boundary. No mutable fallback is authorized.

The CLI challenge profile exposes these transport controls to latent package push/pull. The maintained CLI registry qualification workflow exercises the version 2 CLI against the real pinned Harbor fixture using a disposable private project's robot identity, explicit DNS and verified TLS. It pushes exact signed static-package digests and native evidence referrers, pulls them using a separate pull-only profile, and verifies publisher/build evidence against the fixture's approved test policy. Address, certificate, credential, repository-scope and unavailable-endpoint failures are also required. Its sanitized receipt records the source-built CLI digest; it is not released-binary authentication.

Azure Container Registry remains unqualified. Harbor is the maintained local registry for the scoped bearer-authentication and network profile. No actual ACR package/evidence round trip, Azure identity renewal or hosted storage redirect result is claimed.

Permanent rules apply to every profile: server-controlled challenges, DNS replies, redirects, links and manifests cannot grant endpoint or credential authority; all continuations consume one original operation deadline; physical network, buffer, cache and cleanup work stays charged until retirement; uncertain writes are not blindly replayed; and successful transfer/discovery is not publisher trust or catalog admission.

Configure the endpoint​

Static credential variants select lsf-oci-static-v1 behavior. The explicit BearerChallenge variant selects the bounded authentication extension described in its reference. Construct the client inside a Tokio runtime with RegistryConfig. origin is an HTTPS origin, including an optional port, without credentials, a path, query or fragment. repository is one permitted OCI repository. Every OciReference must match that repository and the origin's authority exactly; its registry field omits the scheme. Reference names are valid OCI tags or canonical lowercase SHA-256 digests. Use explicit digests for durable identity.

For hostname origins, supply up to 16 approved SocketAddr values in addresses, using the origin's port. The static profile performs no runtime DNS lookup. Literal IP origins can leave this list empty. Certificate chain and hostname checks remain enabled. Trust roots are the pinned Mozilla root set plus up to eight explicit DER roots, each at most 64 KiB. It does not install roots globally or consult network certificate services.

Choose RegistryCredentials::Anonymous, explicit Basic credentials, or a preissued Bearer token. Credentials are scoped to this client and redacted from its diagnostic representations. The static profile has no automatic token-service exchange, credential refresh, credential helper or implicit environment-proxy support. Obtain or refresh tokens outside this adapter and construct a new configured client when needed. Authentication failures remain errors.

The Bearer extension never makes a registry-supplied realm authoritative. Its configuration separately approves the token authority, service/audience, repository/actions, tenant, principal and credential epoch. Hostname destinations require explicit addresses with the ordinary constructors. Only the separate new_with_network policy enables bounded DNS and approved content redirects; unknown or unavailable behavior does not gain network authority.

HTTPS is the normal transport. allow_insecure_loopback permits HTTP only for a numeric loopback address when explicitly enabled for local tests. It cannot disable HTTPS certificate validation. The integration fixture uses verified HTTPS and leaves this option disabled.

Identity and ownership​

pull_package fetches a tag's manifest once, calculates its exact immutable digest, then follows the associated config and layers. Moving the tag cannot substitute another package during that pull. Descriptor sizes, hashes and envelope media types are checked before the complete request is exposed. Content hashing uses received bytes without JSON reserialization.

The returned OciPulledPackage exposes a borrowed request() and keeps its package slot and raw-byte lease until dropped. Copying application data out of that borrow creates caller-owned retention. Low-level pull_manifest, pull_blob, resolve and list_referrers likewise transfer their returned buffers/metadata to the caller; a caller retaining many results must impose its own aggregate budget. These limits are not a process-RSS guarantee.

push consumes a fully associated OciPushRequest, checks existing blobs, uploads missing config/layers and publishes the original manifest last. The returned digest must equal the supplied manifest's exact digest. Repeating a completed push is idempotent. There are no automatic transport retries; callers must decide whether and when to retry within their own larger operation budget. An uncertain final response may require checking the immutable digest before repeating publication.

The shared upload worker retains initiation and cleanup ownership when a caller cancels. Known abandoned sessions receive a bounded cleanup attempt; capacity remains charged while that work is owned. If the connection fails before the registry returns its session URL, the adapter cannot identify that remote session, and registry-side expiry must reclaim it. Shutdown closes admission and waits for owned work until the supplied deadline; a deadline error does not claim that remote cleanup completed.

Token acquisition, DNS, redirects and upload continuations consume the same original absolute operation deadline. connect_timeout and request_timeout are inner ceilings, not fresh budgets after each continuation. An abandoned known session transfers to the previously reserved cleanup owner, whose DELETE has the separate bounded cleanup_timeout; this cannot resume the upload or replay an uncertain mutation. Resolver work, token cache entries, sockets, redirect metadata and cleanup remain charged until actual retirement or that explicitly bounded ownership transfer.

Optional raw download cache​

HttpOciRegistry::new_with_cache accepts a shared RawArtifactCache. Complete package pulls can reuse verified blob payloads while retaining their ordinary manifest, descriptor and output-budget checks. The manifest is still fetched remotely on every pull, and each cached blob requires an authorized HEAD with the exact advertised length and a matching digest header when present. 405/501 fall back to ordinary authenticated GET; an authorization failure remains an error. Low-level reads and referrer discovery keep their existing behavior.

Reclaimable entry/disk/metadata pressure receives one reclamation pass of at most 16 examined entries and one reservation retry, then remains an explicit error. Non-reclaimable limits or contention do not evict data. Cache reservations and split OCI buffer permits move into blocking file work together, so caller cancellation cannot refund capacity before that work ends. cache_usage() reports the configured cache's aggregate storage and ownership counters. Catalog admission and execution eligibility remain separate from download caching. Disk results received after the absolute operation deadline are rejected even when the job has already completed. A timeout does not forcibly stop kernel I/O or refund its still-owned reservations.

Supported discovery profile​

Referrer listing is bounded and filtered locally by artifactType, even when a registry ignores the requested filter. Descriptors remain untrusted discovery metadata. Fetch each evidence manifest by its digest, verify its exact bytes and its subject association, then apply the separate required trust policy.

The delivered static profile requires the native OCI 1.1 referrers API. An unsupported API fails explicitly; it is not reported as a successful empty evidence list. Legacy referrers-tag fallback is not implemented, so this is a documented restricted distribution profile rather than a full OCI legacy-fallback client. The OCI specification defines that fallback and its concurrent-writer caveat.

Distribution 3.1.1 does not expose that native API and therefore does not support this adapter's complete evidence-discovery profile. Package transfer alone can work, but that must not be mistaken for complete supply-chain registry compatibility. The real static-profile integration fixture uses Zot minimal 2.1.18 for the complete profile.

Redirects are disabled in lsf-oci-static-v1. Upload Location and pagination Link URLs must remain within the approved origin/repository and the relevant operation path. Opaque upload query parameters are preserved. Registries that require object-store redirects or a separate automatic token origin require the explicit lsf-oci-bearer-v1 configuration described in the authentication and network references. Support remains limited to the demonstrated topologies in the matrix above. A challenge or redirect URL alone never grants authority to forward credentials.

Default limits​

RegistryLimits permits bounded configuration, while the v1 package ceilings can only be lowered. Admission fails promptly when a shared budget is exhausted.

BudgetDefault
Concurrent operations4
Retained complete packages2
Adapter-owned raw bytes512 MiB
Referrer pages / descriptors8 / 256
Aggregate referrer response bytes1 MiB
Connect / request / whole operation5 s / 30 s / 300 s
Upload cleanup attempt5 s
Package JSON document256 KiB
Package layers / single layer / total layers256 / 64 MiB / 256 MiB

URLs are capped at 4096 bytes; retained response headers are capped at 100 entries and 16 KiB. The pinned HTTP/1 implementation also has finite parser scratch limits, separate from the retained-body accounting. Compression and automatic retries are disabled; the static profile also disables redirects. usage() reports active operations, retained package leases, charged raw bytes and whether admission is closed.

The Bearer profile also bounds resolver jobs and cached answers, token acquisitions and retained token bytes, redirect hops and metadata, and connection ownership. The authentication and network references give those ceilings. Clones share these resources rather than allocating an independent pool for every deployment.

Run the real registry check​

Run the maintained qualification runner on Linux x86_64 with Docker, OpenSSL and the pinned Python/Rust toolchain. Preflight checks the environment before compilation. Prepare the exact test executable and pass Cargo's resulting inventory to the execution-only runner:

set -euo pipefail
docker pull ghcr.io/project-zot/zot-minimal-linux-amd64@sha256:f1ffb7a5bbddc0feea83646e29c587ecf39b3193733b447749d4c9ead111a395
python3 tools/run_oci_registry_tests.py --preflight
mkdir -p target/oci-review
cargo test -p latent-oci --test registry --locked --no-run \
--message-format=json,json-render-diagnostics > target/oci-review/registry-tests.jsonl
python3 tools/run_oci_registry_tests.py \
--test-manifest target/oci-review/registry-tests.jsonl

The runner uses the pinned Linux/amd64 Zot minimal 2.1.18 image, with no scanner or other optional registry extensions. It generates a fresh short-lived test CA/server certificate, mounts a precreated public test-only bcrypt credential, and uses one ephemeral IPv4 loopback port. The container has 256 MiB memory, 64 PIDs, one CPU and 128 MiB temporary registry storage, with no persistent data volume. Readiness and test execution have finite deadlines. Normal exit/failure removes only the verified container owned by that run, then removes its temporary files. CI also retains a small ownership recovery record until an unconditional cleanup step completes; an unavailable Docker daemon is reported as a cleanup failure.

The ignored Rust integration target exercises all three package kinds, exact manifest/config/layer round trips, repeated push, movement of a tag after digest resolution, native detached-evidence discovery/filtering, missing/wrong credentials and rejection of an untrusted TLS root. It also generates an ephemeral signing key, signs a package, attaches/discovers/pulls the exact evidence and verifies it against an independently supplied publisher policy. No private key is retained. The original tiny format corpus makes no runnable-guest or trusted-evidence claim. Scripted HTTP unit tests cover hostile responses and cancellation separately. The runner records bounded execution and cleanup diagnostics. The maintained process owner requires Linux; parser/library tests on another host do not replace this qualification. The cold/warm/reopened raw-cache roundtrip exercises directory durability inside the same primary integration test and uses the tiny browser package; it builds or invokes no guest.

The optional --test-binary argument must match the executable selected by --test-manifest; it cannot replace the inventory. Without --provenance-input, the separate observed-build provenance test is skipped. The Python fixture runner and test process must share access to the fixture's loopback endpoint and CA file; a Linux test binary in a separate container does not share the Windows host's loopback automatically.

The separate Harbor 2.15.2 workflow exercises the Bearer profile with a private project and native referrers. Use the owned Harbor workflow and its DNS variant for those checks. Its results do not qualify an untested hosted-storage topology.