package escrow // Controller-driven ceremony contract (v0.88.0, TASK 2026-07-13; mechanics validated by // felhom.eu/documentation/audits/SPIKE-controller-escrow-2026-07-13.md). The agent's local API // re-invokes the agent binary as root via `sudo -n` with ONE fixed argument vector; sudoers // matches that vector byte-for-byte (spike §2.2: any alteration — value, extra flag, order, // config path — is refused), so the argv below is the SINGLE SOURCE OF TRUTH shared by the // exec (localapi), the capability manifest entry, and (byte-identically) the FELHOM_ESCROW // sudoers line. Never build it with flag helpers and never normalize `--` to `-` — Go's flag // package would accept either spelling, sudoers only the literal one. // CeremonyBinary is the installed agent binary path the sudoers line pins. const CeremonyBinary = "/usr/local/bin/felhom-agent" // ceremonyArgv is the fixed vector. --config is pinned explicitly: `sudo -n` env_reset strips // FELHOM_AGENT_CONFIG, and the pin closes env-injection of an alternate config (spike probe (e)). var ceremonyArgv = []string{ "--config", "/etc/felhom-agent/agent.json", "--selftest=escrow-create", "--upload", "--output=json", } // CeremonyArgs returns a fresh copy of the fixed argv (callers must not be able to mutate the // shared source). func CeremonyArgs() []string { out := make([]string, len(ceremonyArgv)) copy(out, ceremonyArgv) return out } // CeremonyOutput is the --output=json wire contract (version 1): the ONE JSON object json mode // emits on stdout — nothing else lands there; every human/info line goes to stderr. RecoveryCode // is the only secret field: the consumer must extract it, hand it to the one-shot claim holder, // and zero both the parsed struct and the raw stdout buffer. (Best-effort — Go's GC may hold // stale copies; the discipline still shrinks the exposure window.) type CeremonyOutput struct { Version int `json:"version"` RecoveryCode string `json:"recovery_code"` KeyFingerprint string `json:"key_fingerprint"` EntropyBits float64 `json:"entropy_bits"` BlobBytes int `json:"blob_bytes"` IdentityBlobBytes int `json:"identity_blob_bytes"` ResticPwSealed bool `json:"restic_pw_sealed"` Uploaded bool `json:"uploaded"` } // CeremonyOutputVersion is the current CeremonyOutput.Version value. const CeremonyOutputVersion = 1