astrid-runtime/astrid · error
capsule content digest does not match its signed provenance
Error message
capsule content digest does not match its signed provenance
What it means
Fired by verify_records when the BLAKE3 content digest recomputed from archive entries differs from the digest covered by the envelope's signature. The capsule's contents were modified after signing (or the signature is invalid/corrupt).
Solutions
- Re-download the capsule from the trusted publisher; do not install this copy
- Rebuild and re-sign the capsule if you are the author
- Check for transmission corruption or tampering
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/astrid-build/src/artifact.rs:372 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/08a7dfa0b1fea1c5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-build/src/artifact.rs:372
fn verify_records(
records: Vec<ContentRecord>,
envelope: Option<&[u8]>,
) -> anyhow::Result<ArtifactVerification> {
let content_digest = digest_records(records)?;
let Some(bytes) = envelope else {
return Ok(ArtifactVerification::Unsigned { content_digest });
};
let envelope: ProvenanceEnvelope =
serde_json::from_slice(bytes).context("invalid capsule provenance envelope")?;
if envelope.schema_version != SCHEMA_VERSION || envelope.algorithm != ALGORITHM {
bail!(
"unsupported capsule provenance schema {} / algorithm '{}'",
envelope.schema_version,
envelope.algorithm
);
}
if envelope.content_digest != content_digest {
bail!("capsule content digest does not match its signed provenance");
}
envelope
.signer
.verify(
&signature_message(&envelope.content_digest),
&envelope.signature,
)
.context("capsule provenance signature verification failed")?;
Ok(ArtifactVerification::Signed(VerifiedProvenance {
content_digest,
signer: envelope.signer,
signature: envelope.signature,
}))
}
fn rewrite_with_provenance(archive_path: &Path, envelope: &[u8]) -> anyhow::Result<()> {
let parent = archive_path.parent().unwrap_or_else(|| Path::new("."));
let mut staged = tempfile::NamedTempFile::new_in(parent)View on GitHub (pinned to affd8760f4)