astrid-runtime/astrid · critical
capsule provenance changed after authority decision
Error message
capsule provenance changed after authority decision
What it means
`authority_for_install_source` compares the signer identity and signature of the freshly verified source against those recorded in the approved authority decision. This error is thrown when provenance changed — the capsule is now signed by a different signer or carries a different signature than what was approved — so the library refuses to reuse the old authority decision for content from a different origin.
Source
Thrown at crates/astrid-capsule-install/src/authority.rs:929
source_dir: &Path,
manifest: &CapsuleManifest,
approved: Option<InstalledAuthority>,
) -> anyhow::Result<InstalledAuthority> {
let verification = artifact::verify_directory(source_dir)?;
let content_digest = verification.content_digest().to_string();
let manifest_digest = digest_manifest(&std::fs::read(source_dir.join("Capsule.toml"))?);
let (signer, signature) = verification_provenance(&verification);
if let Some(approved) = approved {
if approved.content_digest != content_digest {
bail!(
"capsule content changed after authority decision (approved {}, found {})",
approved.content_digest,
content_digest
);
}
if approved.signer != signer || approved.signature != signature {
bail!("capsule provenance changed after authority decision");
}
if approved.capsule_id != manifest.package.name
|| approved.version != manifest.package.version
{
bail!("capsule identity or version changed after authority decision");
}
if approved.manifest_digest != manifest_digest {
bail!("capsule manifest changed after authority decision");
}
if approved.approved_capabilities != manifest.capabilities {
bail!("capsule capabilities changed after authority decision");
}
return Ok(approved);
}
// Calling the legacy library install API is itself an operator-authority
// action. User-facing CLI and daemon entry points use explicit decisions;
// this path preserves the existing trusted embedding API while recordingView on GitHub (pinned to affd8760f4)
Solutions
- Re-run the authority approval against the current signing identity so the receipt records the new signer/signature
- Restore the capsule to the exact signed artifact that was originally approved (same signer key and signature)
- Verify the signing key was not unexpectedly rotated; if rotation is legitimate, publish and approve the re-signed release
Example fix
// before
bail!("capsule provenance changed after authority decision");
// after: re-approve with the new signer
// let authority = decision::approve(source_dir)?;
// install_from_local_path_internal(source_dir, Some(authority)) Defensive patterns
Strategy: validation
Validate before calling
// Verify provenance matches the approved decision before install let verification = artifact::verify_directory(source_dir)?; let (signer, signature) = verification_provenance(&verification); assert_eq!(approved.signer.as_deref(), signer.as_deref()); assert_eq!(approved.signature.as_deref(), signature.as_deref());
Type guard
fn provenance_unchanged(approved: &InstalledAuthority, signer: &Option<String>, signature: &Option<String>) -> bool {
approved.signer == *signer && approved.signature == *signature
} Try / catch
match authority_for_install_source(source_dir, &manifest, Some(approved)) {
Err(e) if e.to_string().contains("provenance changed") => reapprove_with_new_signer(),
other => other.map(install),
} Prevention
- Sign with a stable, pinned release key; avoid ad-hoc key rotation between review and install
- Never swap signed/unsigned builds in a reviewed directory
- Re-run approval after any re-signing event
- Record signer identity in CI so installs use the reviewed key
When it happens
Trigger: Calling `install_from_local_path_internal` with an approved `InstalledAuthority` where `approved.signer != current signer` or `approved.signature != current signature`, as recomputed by `verification_provenance(&verification)` over the re-verified source directory.
Common situations: Re-signing the capsule with a new key after approval; switching between signed and unsigned builds (or vice versa) in the source directory; pulling content from a different publisher into the reviewed directory.
Related errors
- durable capsule {id} provenance differs from authority recei
- durable capsule {id} authority claims provenance absent from
- capsule '{}' is {}; explicit local approval is required
- installed authority receipt does not match capsule '{capsule
- capsule content changed after authority decision (approved {
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/9c82f117bfd1ccba.
Report an issue: GitHub.