Summary
Follow-up to #995 / #991. Implement the install-time capability-approval gate: a capsule's manifest-declared [capabilities] (untrusted author input) must not become effective at load without an operator-recorded approval. A manually-installed capsule loads inert (zero host-fn capabilities) until an operator approves it; operator-driven flows auto-approve so onboarding does not regress and nothing bricks on upgrade.
This is the permission-required half of #995's model. The cryptographic distro-blessed exemption (OFFICIAL_KEYS) remains tracked on #995 itself.
Design
- Fingerprint — a serde-transparent
CapabilityFingerprint newtype = BLAKE3 over the canonical security-relevant declared set (full CapabilitiesDef + sorted effective IPC publish/subscribe patterns). Any escalation changes it → re-approval required.
- Store — per principal at
<principal_home>/.config/approvals/<capsule_id>.json (atomic write), operator-owned and capsule-unreachable (under .config/, not the copyable/guest-reachable capsule dir). Every failure mode (missing/unreadable/unparseable/mismatch) is fail-secure → unapproved.
- Load consult — the engine consults the store immediately before constructing
ManifestSecurityGate; unapproved → manifest.capabilities zeroed in place so the gate, capability_names, has_uplink, and the net_bind listener all see the empty set. Audit-tagged warning emitted.
- Writes — manual
astrid capsule install prompts (default NO); astrid init/offline distro (batch), admin/gateway install, and furniture seeding auto-approve; a one-time grandfather migration approves pre-existing capsules at first boot (marker-guarded).
astrid capsule approve <id> activates an installed-but-inert capsule.
Acceptance
- Manually-installed capsule with declared caps loads inert until approved; approve activates it.
- Distro / admin / furniture / pre-existing installs are unaffected (auto-approved); no brick on upgrade.
- Approval store is not forgeable, relocatable, or carried across principals by furniture copy.
Out of scope (tracked separately)
Summary
Follow-up to #995 / #991. Implement the install-time capability-approval gate: a capsule's manifest-declared
[capabilities](untrusted author input) must not become effective at load without an operator-recorded approval. A manually-installed capsule loads inert (zero host-fn capabilities) until an operator approves it; operator-driven flows auto-approve so onboarding does not regress and nothing bricks on upgrade.This is the permission-required half of #995's model. The cryptographic distro-blessed exemption (
OFFICIAL_KEYS) remains tracked on #995 itself.Design
CapabilityFingerprintnewtype = BLAKE3 over the canonical security-relevant declared set (fullCapabilitiesDef+ sorted effective IPC publish/subscribe patterns). Any escalation changes it → re-approval required.<principal_home>/.config/approvals/<capsule_id>.json(atomic write), operator-owned and capsule-unreachable (under.config/, not the copyable/guest-reachable capsule dir). Every failure mode (missing/unreadable/unparseable/mismatch) is fail-secure → unapproved.ManifestSecurityGate; unapproved →manifest.capabilitieszeroed in place so the gate,capability_names,has_uplink, and the net_bind listener all see the empty set. Audit-tagged warning emitted.astrid capsule installprompts (default NO);astrid init/offline distro (batch), admin/gateway install, and furniture seeding auto-approve; a one-time grandfather migration approves pre-existing capsules at first boot (marker-guarded).astrid capsule approve <id>activates an installed-but-inert capsule.Acceptance
Out of scope (tracked separately)
OFFICIAL_KEYS— Install-time trust model: distro-blessed vs permission-required manual installs (blocked on signing) #995.