{"record":{"id":"b31d2fce72ee76be","repo":"astrid-runtime/astrid","slug":"capsule-capabilities-changed-after-authority-decis","errorCode":null,"errorMessage":"capsule capabilities changed after authority decision","messagePattern":"capsule capabilities changed after authority decision","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-capsule-install/src/authority.rs","lineNumber":940,"sourceCode":"            bail!(\n                \"capsule content changed after authority decision (approved {}, found {})\",\n                approved.content_digest,\n                content_digest\n            );\n        }\n        if approved.signer != signer || approved.signature != signature {\n            bail!(\"capsule provenance changed after authority decision\");\n        }\n        if approved.capsule_id != manifest.package.name\n            || approved.version != manifest.package.version\n        {\n            bail!(\"capsule identity or version changed after authority decision\");\n        }\n        if approved.manifest_digest != manifest_digest {\n            bail!(\"capsule manifest changed after authority decision\");\n        }\n        if approved.approved_capabilities != manifest.capabilities {\n            bail!(\"capsule capabilities changed after authority decision\");\n        }\n        return Ok(approved);\n    }\n\n    // Calling the legacy library install API is itself an operator-authority\n    // action. User-facing CLI and daemon entry points use explicit decisions;\n    // this path preserves the existing trusted embedding API while recording\n    // the same exact content and capability ceiling.\n    Ok(InstalledAuthority {\n        schema_version: 1,\n        source: AuthoritySource::OperatorDistribution,\n        capsule_id: manifest.package.name.clone(),\n        version: manifest.package.version.clone(),\n        content_digest,\n        manifest_digest,\n        signer,\n        signature,\n        approved_capabilities: manifest.capabilities.clone(),","sourceCodeStart":922,"sourceCodeEnd":958,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/authority.rs#L922-L958","documentation":"`authority_for_install_source` compares `approved.approved_capabilities` (the capability ceiling the operator approved) with `manifest.capabilities` (the capabilities the capsule now requests). This error is thrown when the capsule's requested capabilities were expanded after the authority decision — a privilege-escalation guard that stops an unreviewed capability grant from being installed under an old, narrower approval.","triggerScenarios":"Calling `install_from_local_path_internal` with an approved `InstalledAuthority` where `approved.approved_capabilities != manifest.capabilities`, i.e. the `capabilities` section of Capsule.toml changed after approval (added permissions like network, fs access, etc.).","commonSituations":"A developer adds a new permission to Capsule.toml after the operator reviewed it; a dependency update pulls in capability requirements; accidentally editing the capabilities block while changing something else.","solutions":["Re-run the authority approval so the operator reviews and approves the new capability set, then install with the new receipt","Revert the capabilities section of Capsule.toml to the approved set and retry","If the new capabilities are intentional, document and complete a fresh review before installing"],"exampleFix":"// before\nbail!(\"capsule capabilities changed after authority decision\");\n// after: obtain a new decision covering the expanded capabilities\n// let authority = decision::approve_with_capabilities(source_dir, &manifest.capabilities)?;\n// install_from_local_path_internal(source_dir, Some(authority))","handlingStrategy":"validation","validationCode":"// Ensure requested capabilities match the approved ceiling before install\nlet manifest = load_manifest(source_dir.join(\"Capsule.toml\"))?;\nassert_eq!(approved.approved_capabilities, manifest.capabilities,\n          \"capability set changed since approval; re-run operator review\");","typeGuard":"fn capabilities_unchanged(approved: &InstalledAuthority, m: &CapsuleManifest) -> bool {\n    approved.approved_capabilities == m.capabilities\n}","tryCatchPattern":"match authority_for_install_source(source_dir, &manifest, Some(approved)) {\n    Err(e) if e.to_string().contains(\"capabilities changed\") => request_capability_review(&manifest.capabilities),\n    other => other.map(install),\n}","preventionTips":["Treat any capability addition as requiring a fresh security review","Keep the capabilities section frozen between review and install","Review dependency updates for new capability requirements before approving","Log capability diffs in CI to catch accidental edits"],"tags":["security","capabilities","privilege-escalation","install"],"backgroundTag":"permission-denied","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}