{"record":{"id":"67c1305622788d63","repo":"astrid-runtime/astrid","slug":"capsule-is-explicit-local-approval-is-req","errorCode":null,"errorMessage":"capsule '{}' is {}; explicit local approval is required","messagePattern":"capsule '(.+?)' is (.+?); explicit local approval is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/astrid-capsule-install/src/authority.rs","lineNumber":803,"sourceCode":"}\n\n/// Convert a bound decision into the receipt persisted by the installer.\n///\n/// # Errors\n///\n/// `Automatic` rejects foreign and unsigned artifacts. Bound decisions reject\n/// a digest mismatch, preventing a changed artifact from reusing an approval.\npub fn authorize_install(\n    inspection: &InstallInspection,\n    decision: &AuthorityDecision,\n) -> anyhow::Result<InstalledAuthority> {\n    let source = match decision {\n        AuthorityDecision::Automatic => {\n            if !matches!(\n                inspection.provenance,\n                ArtifactProvenance::LocalRuntime { .. }\n            ) {\n                bail!(\n                    \"capsule '{}' is {}; explicit local approval is required\",\n                    inspection.capsule_id,\n                    inspection.provenance.label()\n                );\n            }\n            AuthoritySource::LocalRuntimeBuild\n        },\n        AuthorityDecision::ExplicitApproval { content_digest } => {\n            ensure_bound_digest(inspection, content_digest)?;\n            AuthoritySource::ExplicitApproval\n        },\n        AuthorityDecision::OperatorDistribution { content_digest } => {\n            ensure_bound_digest(inspection, content_digest)?;\n            AuthoritySource::OperatorDistribution\n        },\n    };\n    let (signer, signature) = match &inspection.provenance {\n        ArtifactProvenance::LocalRuntime { signer, signature }","sourceCodeStart":785,"sourceCodeEnd":821,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-capsule-install/src/authority.rs#L785-L821","documentation":"authorize_install grants Automatic authority only to artifacts with LocalRuntime provenance (built locally by the runtime). For any other provenance (downloaded, shared, etc.), the library requires the user to explicitly approve the capsule and names its provenance label in the message. This is a supply-chain safeguard: unattended auto-approval is limited to artifacts the user's own runtime produced.","triggerScenarios":"Calling authorize_install (directly or via unpack_and_install_authorized_for_principal_in_workspace and friends) when the resolved AuthorityDecision is Automatic but inspection.provenance is not ArtifactProvenance::LocalRuntime.","commonSituations":"Installing a capsule fetched from a registry or shared by a colleague and expecting silent auto-approval; scripting installs of third-party capsules without an approval step; CI pipelines installing remote capsules unattended.","solutions":["Run the install with the explicit local approval flag/flow to approve the capsule's provenance interactively or via config","Build the capsule locally so its provenance is LocalRuntimeBuild and auto-approval applies","If the capsule is trusted, pre-approve its id/digest in the approval store before calling authorize_install"],"exampleFix":"// before\nunpack_and_install_authorized_for_principal_in_workspace(&home, &url, &principal)?; // remote capsule\n// after\nunpack_and_install_checked_authorized_for_principal_in_workspace(&home, &url, &principal, /* explicit_approval: */ true)?;","handlingStrategy":"try-catch","validationCode":"let inspection = inspect_capsule(&artifact)?;\nif matches!(decision, AuthorityDecision::Automatic) && !matches!(inspection.provenance, ArtifactProvenance::LocalRuntime { .. }) {\n    // plan an explicit approval step before installing\n}","typeGuard":"fn is_local_runtime(p: &ArtifactProvenance) -> bool {\n    matches!(p, ArtifactProvenance::LocalRuntime { .. })\n}","tryCatchPattern":"match authorize_install(&home, &artifact) {\n    Err(e) if e.to_string().contains(\"explicit local approval is required\") => {\n        prompt_user_approval(&inspection)?;\n        authorize_install(&home, &artifact)?\n    }\n    Ok(a) => a,\n    Err(e) => return Err(e),\n}","preventionTips":["Pre-approve trusted remote capsule ids/digests in the approval store","Use explicit-approval install APIs for anything not built locally","Never assume auto-approval for downloaded artifacts in CI; provision approvals ahead of time"],"tags":["capsule","approval","provenance","security","supply-chain"],"backgroundTag":"authentication-required","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"}