Skip to content

Add optional immutable image preparation for Verified app delivery - #3

Open
joshhalley wants to merge 1 commit into
mainfrom
pr/johalley/verified-image-preparation-20261107
Open

joshhalley wants to merge 1 commit into
mainfrom
pr/johalley/verified-image-preparation-20261107

Conversation

@joshhalley

@joshhalley joshhalley commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Problem and resulting behavior

CVK needs a reliable way to replace externally sourced application images when a newer release fixes a defect or vulnerability. An on-demand download identified only by a mutable tag is not a retained release artifact with a stable package identity.

This PR adds an optional prepare command that acquires an image by immutable SHA-256 digest and explicit platform, validates its content, and retains a deterministic Docker-save package with identity/provenance metadata. Running the binary without arguments still starts the existing HTTP service.

Standard remains the default workflow. Verified preparation is opt-in. Governed lifecycle policy is deferred. This producer does not gain device-control or deployment-approval authority.

Changes

Immutable acquisition and conversion

  • Add docker-http-passthrough prepare --repository … --digest sha256:… --platform linux/ARCH[/VARIANT] --output-dir ….
  • Support direct manifests and one-level OCI/Docker image indexes with exactly one matching platform.
  • Verify raw index/manifest/configuration/layer digests, descriptor sizes, the image configuration's platform, layer count and each expanded layer's uncompressed diff_id.
  • Generate deterministic Docker-save bytes for identical immutable inputs and converter build, using normalized tar metadata and a digest-derived internal tag.
  • Identify the actual running converter executable and the exact conversion recipe by digest.

Retained artifact contract

Output Meaning
package.tar The converted Docker-save archive
descriptor.json Draft apphosting.cisco.com/v1alpha1 artifact identity: source, platform, package SHA-256/size, producer and evidence references
provenance.json Unsigned in-toto conversion statement
recipe.json Exact conversion recipe bytes
checksums.json Package and metadata SHA-256 values, including final JSON newlines

The vendored artifact schema is byte-identical to the companion CVK schema. Source-image identity and converted-package identity are separate: the latter identifies the exact tar intended for delivery.

Network, resource and publication boundaries

  • Use a dedicated HTTPS preparation client, with an optional private registry CA while preserving certificate and hostname validation.
  • Restrict token endpoints and pull scope; require explicit authorization for additional blob redirect origins and strip registry credentials from redirect requests.
  • Reject manifest/token redirects and unsupported or ambiguous input rather than weakening verification.
  • Bound metadata, index entries, layer count, compressed/expanded/final package bytes and deadlines. The default byte budget is 2 GiB, with a 64 GiB ceiling; the whole-command timeout defaults to 1,800 seconds.
  • Publish the completed output directory atomically without replacing an existing directory on Linux/macOS. Preserve successful output for publication retries.
  • Document behavior, integration, limits and failure handling in the README.

The preparation-specific guarantees do not automatically apply to the existing HTTP download routes. The earlier authentication/registry-route work is already on main and is not introduced by this PR.

How this fits with CVK

flowchart LR
    Registry["Registry digest and platform"] --> Prepare["Optional prepare command"]
    Prepare --> Output["Unsigned package and metadata"]
    Output --> Pipeline["External pipeline: chosen scans, signing and publication"]
    Pipeline --> Store["Immutable HTTPS artifact store"]
    Store --> CVK["Opt-in CVK Verified delivery"]
Loading

A separate trusted producer pipeline signs the exact descriptor bytes and publishes unchanged objects. CVK then verifies the signature, package identity and staged device bytes before installation. Standard users can continue using ordinary package URLs without this infrastructure.

Companion PR: cisco-open/cisco-virtual-kubelet#213. The producer and device runtime remain separate projects with a shared artifact contract.

Validation

Check Result
cargo fmt --all -- --check Passed before publication
cargo test --locked 38 passed, 0 failed, before publication
Shared schema comparison Byte-identical to the CVK artifact schema
Staged publication audit Committed blobs checked against audited source bytes; clean local tree and remote head verified

The suite covers existing HTTP route/authentication behavior as well as deterministic preparation, direct/indexed manifests, plain/gzip layers, corruption rejection, unsupported sources, platform selection, byte/decompression/deadline limits, atomic non-overwrite publication, restricted token realms/scopes, redirect credential stripping and private-CA input validation.

These are the recorded pre-publication checks for commit cec5128cf556a7eb91589e9188fc898f1983df94; they are not a claim that this PR's GitHub CI has already passed. Formatting-only changes were applied to the new preparation code before those checks.

Remaining limitations and explicit non-goals

  • Output is unsigned and unapproved. This command does not sign, remotely publish, scan, generate an SBOM, authorize a deployment or install on a device. The descriptor can reference an externally produced SBOM.
  • No Governed engine, automatic CVE discovery/remediation, scoped deployment grants, revocation policy or fleet campaign controller is implemented.
  • Supported layer encodings are plain/gzip tar. Nested indexes, ambiguous/missing platforms, tags as preparation input, foreign layers and zstd layers are rejected.
  • Successful conversion does not prove device compatibility, native IOx package-signature acceptance, application health or that a specific CVE was fixed.
  • Hard termination can leave an abandoned hidden staging directory. A durability error after publication can leave a complete destination; inspect and reuse it rather than overwrite it.
  • Peak scratch storage can approach three times the byte budget plus bounded metadata. Operators still need to bound parallel jobs and disk capacity.
  • Production registry/CDN and device combinations need their own qualification. The companion C9K results are bounded hardware/firmware/package qualifications.
  • GitHub reported existing default-branch dependency alerts during publication; this feature PR does not claim to triage or remediate them, nor does it establish that acquired images are vulnerability-free.

Review pointers

Start with src/prepare.rs, src/registry/verified.rs, their tests, and schemas/app-hosting-artifact-v1alpha1.schema.json. The changes to main.rs only select command mode when arguments are present; no-argument server startup remains the default.

Add digest/platform-specific image preparation, content verification, deterministic Docker-save output, provenance and the shared artifact schema. Bound registry authentication, redirects, bytes and deadlines, and publish local outputs atomically without replacing existing directories.

Keep no-argument HTTP server operation unchanged; signing, scanning and deployment approval remain external.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant