astrid-runtime/astrid · error

distro signature verification failed

Error message

distro signature verification failed

What it means

verify_lock signs the distro lock over a canonical digest (lock_signing_digest) and checks the ed25519-style signature from Distro.sig against the distro's declared public key. This error is the blanket rejection from pubkey.verify: the signature bytes parsed fine (they were valid 64-byte hex) but do not match the digest under that key. It deliberately returns no cryptographic detail to avoid oracle leaks.

Solutions

  1. Re-sign the lock with the private key matching the manifest pubkey and redeploy Distro.sig.
  2. Verify you have the exact lock the sig was produced from (diff lock contents/hashes; re-fetch the distro).
  3. Check the manifest's [distro.signing].pubkey matches the key that produced the sig (key rotation?).
  4. Inspect Distro.sig for corruption (must be 64-byte hex, no wrapping/encoding changes); re-download it.

Example fix

// before: lock edited after signing
$ astrid distro sign --lock Distro.lock  # regenerate Distro.sig from the edited lock
// after
$ astrid distro apply --distro my-distro  # verify now passes
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check before trusting: hex decode length only; actual verify needs the key.
let sig_bytes = hex::decode(sig_hex.trim())?;
if sig_bytes.len() != 64 { return Err(anyhow!("Distro.sig must be 64-byte hex")); }

Type guard

fn is_wellformed_sig(sig_hex: &str) -> bool {
    hex::decode(sig_hex.trim()).map(|b| b.len() == 64).unwrap_or(false)
}

Try / catch

match sign::verify_lock(&lock, sig_hex, &pubkey) {
    Ok(()) => install(),
    Err(e) if e.to_string().contains("verification failed") => {
        eprintln!("signature mismatch: re-sign the lock or re-fetch the artifact");
    },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: verify_lock(lock, sig_hex, pubkey) when: the Distro.sig was made over a different lock file/revision; the lock was edited after signing; the sig was generated with a different private key than the manifest's [distro.signing].pubkey; or the sig hex was corrupted/transcoded (e.g. re-saved via a tool that altered whitespace-to-content).

Common situations: Distro maintainers re-signing after a lock edit but shipping the old .sig; shipping a sig from a stale branch; CI building a lock deterministically but signing a different serialization; malicious tampering with the artifact in transit.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/c90c46d16c7ae5e8. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-cli/src/commands/distro/sign.rs:105

}

/// Verify a hex `Distro.sig` against a lock and a public key.
///
/// # Errors
///
/// Returns an error if the signature is malformed (not 64 hex bytes) or
/// does not verify against the lock's signing digest under `pubkey`.
pub(crate) fn verify_lock(
    lock: &DistroLock,
    sig_hex: &str,
    pubkey: &PublicKey,
) -> anyhow::Result<()> {
    let sig = Signature::from_hex(sig_hex.trim())
        .map_err(|e| anyhow::anyhow!("malformed Distro.sig (expected 64-byte hex): {e}"))?;
    let digest = lock_signing_digest(lock)?;
    pubkey
        .verify(&digest, &sig)
        .map_err(|_| anyhow::anyhow!("distro signature verification failed"))
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::commands::distro::lock::{DistroLock, DistroLockMeta, LockedCapsule};

    fn sample_lock() -> DistroLock {
        DistroLock {
            schema_version: 1,
            distro: DistroLockMeta {
                id: "test".into(),
                version: "0.1.0".into(),
                resolved_at: "2026-01-01T00:00:00Z".into(),
            },
            capsules: vec![LockedCapsule {
                name: "astrid-capsule-cli".into(),
                version: "0.1.0".into(),

View on GitHub (pinned to affd8760f4)