Expand description
Manifest format, canonicalization, and ed25519 signing for CAR contributed-agent bundles (Parslee-ai/car#182).
§Scope
This crate owns the on-disk shape and crypto primitives shared
between the supervisor (loads + verifies installed agents),
the CLI (publishes + signs new agents), and the registry
(serves signed manifests). It is no-runtime — pure data,
pure functions, no async, no I/O outside read_to_string for
tests. The supervisor and CLI hold the I/O.
§Phase status
- Phase 1 (
car-registry): the manifest format landed inline atcar_registry::manifest. The supervisor dual-reads legacyagents.jsonand the new~/.car/agents/<id>/manifest.tomllayout. Signature verification was stubbed out. - Phase 2 (this crate): types extracted here; ed25519 sign/verify added; manifest-level canonicalization landed. The supervisor wires verification with warn-but-not-reject semantics so existing setups keep working while operators sign their agents.
- Phase 3+: full-bundle canonicalization (multi-file:
identity.md,skills.jsonl,policies.json, …) perdocs/agent-bundle-spec.md §canonicalization. Today’scanonical_manifest_bytescovers only the singlemanifest.tomlfile — sufficient forexternal_processbundles which carry no auxiliary data files.
Structs§
- Agent
Identity [agent]block.- Agent
Manifest manifest.tomltop-level structure. One file per installed agent at~/.car/agents/<id>/manifest.toml.- Capability
Declarations - External
Process Transport - Lifecycle
Policy - Publisher
Info [publisher]block. Thesignaturefield is the base64- encoded ed25519 signature over the canonicalized manifest (i.e., the manifest withpublisher.signaturecleared).key_idis the ed25519 public key, base64-encoded (32 bytes raw → 44 char base64).- Runtime
Requirements
Enums§
- Bundle
Error - Restart
Policy - Restart policy mirrors the supervisor’s surface. Re-declared
here (rather than re-exported from
car-registry) so this crate stays standalone —car-registrydepends oncar-bundle, not the other way around. - Transport
Spec
Functions§
- canonical_
manifest_ bytes - Produce canonical bytes of a manifest for signing / verification.
- manifest_
digest_ hex - SHA-256 hex digest of the canonical manifest bytes. Useful for content-addressed lookups (registry caching, etc.) without requiring signature verification.
- sha256_
hex - SHA-256 hex digest of an arbitrary byte slice. Used by
car installto verify binaries fetched viatransport.binary_urlagainst the manifest’stransport.sha256(Parslee-ai/car#182 phase 5). - sign_
manifest - Sign a manifest in place: writes the public key id into
publisher.key_id, then serializes canonical bytes (which clear the signature but include the key_id), signs them withkey, and writes the base64 signature intopublisher.signature. Replaces any existing signature. - verify_
detached - Verify a detached ed25519 signature over raw
bytesagainst a base64-encoded 32-byte public key and base64-encoded 64-byte signature. Used to authenticate documents that aren’t manifests (e.g. the refreshable model catalog incar-inference): the source signs the exact file bytes, so no canonicalization is needed. - verify_
sha256 - Verify a byte slice matches a hex-encoded SHA-256 digest. Comparison is constant-time-ish (case-insensitive hex equality), and returns an error rather than a bool so the failure message can name the expected + actual digests.
- verify_
signature - Verify a manifest’s signature against the embedded
publisher.key_id. ReturnsOk(())on success,Err(...)on any failure (missing publisher, malformed key, mismatched signature). A manifest with nopublisherblock is treated as unsigned and rejected — callers that want to accept unsigned manifests should not call this function.