Skip to content

Sign a manifest

A manifest is ed25519-signed over a domain-separated, length-prefixed preimage. The dev_sign example (in crates/manifest-core/examples) mirrors the production CLI field for field, so you can sign without a full ct-agent build:

export CT_MANIFEST_HOLDER_KEY=<64 hex  your ed25519 private key>
export CT_MANIFEST_NAME=hello-world
export CT_MANIFEST_VERSION=1.0.0
export CT_MANIFEST_KIND=compose                # compose | binary | k8s
export CT_MANIFEST_COMPOSE_FILE=docker-compose.yml
export CT_MANIFEST_BUNDLE_URL=https://example/hello-world.tar.gz
export CT_MANIFEST_BUNDLE_SHA256=<sha256 of the bundle tarball>
export CT_MANIFEST_VERIFY_SCRIPT=verify.sh
export CT_MANIFEST_ENV_VARS="HELLO_TEXT:true:text to echo"   # name:required:description, ; separated
cargo run --quiet --example dev_sign > hello-world.manifest.json

The output is the complete signed manifest as JSON. Only the public holder key and the signature are in it; the private key never leaves your shell.

The bundle hash is signed

CT_MANIFEST_BUNDLE_SHA256 is covered by the signature. If the bundle bytes change by even one byte, the registry rejects the upload with 400 — see Read a guardrail verdict and the Registry API.

See the Manifest schema for every field's meaning.