{"record":{"id":"c9730a26ab5e86cb","repo":"astrid-runtime/astrid","slug":"malformed-distro-sig-expected-64-byte-hex-e","errorCode":null,"errorMessage":"malformed Distro.sig (expected 64-byte hex): {e}","messagePattern":"malformed Distro\\.sig \\(expected 64-byte hex\\): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-cli/src/commands/distro/sign.rs","lineNumber":101,"sourceCode":"\n/// Render a [`PublicKey`] as `ed25519:<base64>`.\npub(crate) fn pubkey_to_wire(pk: &PublicKey) -> String {\n    format!(\"ed25519:{}\", pk.to_base64())\n}\n\n/// Verify a hex `Distro.sig` against a lock and a public key.\n///\n/// # Errors\n///\n/// Returns an error if the signature is malformed (not 64 hex bytes) or\n/// does not verify against the lock's signing digest under `pubkey`.\npub(crate) fn verify_lock(\n    lock: &DistroLock,\n    sig_hex: &str,\n    pubkey: &PublicKey,\n) -> anyhow::Result<()> {\n    let sig = Signature::from_hex(sig_hex.trim())\n        .map_err(|e| anyhow::anyhow!(\"malformed Distro.sig (expected 64-byte hex): {e}\"))?;\n    let digest = lock_signing_digest(lock)?;\n    pubkey\n        .verify(&digest, &sig)\n        .map_err(|_| anyhow::anyhow!(\"distro signature verification failed\"))\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::commands::distro::lock::{DistroLock, DistroLockMeta, LockedCapsule};\n\n    fn sample_lock() -> DistroLock {\n        DistroLock {\n            schema_version: 1,\n            distro: DistroLockMeta {\n                id: \"test\".into(),\n                version: \"0.1.0\".into(),\n                resolved_at: \"2026-01-01T00:00:00Z\".into(),","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/sign.rs#L83-L119","documentation":"verify_lock parses the Distro.sig file contents as a 64-byte hex-encoded ed25519 signature before verifying it against the lock's signing digest. If Signature::from_hex rejects the string (wrong length, non-hex characters, whitespace issues beyond trim), this error reports the malformed signature. The signature never reaches cryptographic verification; it fails at parse time.","triggerScenarios":"Calling verify_lock with a sig_hex string that is not exactly 128 hex characters: an empty Distro.sig, a base64-encoded signature pasted instead of hex, a truncated or multi-line signature file, or a file containing extra content after the hex (beyond leading/trailing whitespace, which is trimmed).","commonSituations":"Signing with an external tool that emits base64 signatures while distro tooling expects hex; a partially written or corrupted Distro.sig transferred between machines; manually editing the sig file and dropping characters.","solutions":["Re-generate the signature with the distro signing command so Distro.sig contains 128 lowercase hex characters (64 bytes).","If your signer outputs base64, convert to hex before writing Distro.sig (e.g. `base64 -d sig.b64 | xxd -p -c 128`).","Check the file length: `wc -c Distro.sig` should be 128 bytes plus optional trailing newline; re-transfer if truncated.","Verify you are reading the signature file, not a key or manifest, into verify_lock."],"exampleFix":"// before\nlet sig_hex = std::fs::read_to_string(\"Distro.sig\")?; // base64 from external signer\nverify_lock(&lock, &sig_hex, &pk)?;   // malformed: not hex\n// after\nlet raw = base64::decode(sig_hex.trim())?;\nlet sig_hex = hex::encode(&raw);\nverify_lock(&lock, &sig_hex, &pk)?;","handlingStrategy":"validation","validationCode":"let sig = sig_hex.trim();\nanyhow::ensure!(!sig.is_empty(), \"Distro.sig is empty\");\nanyhow::ensure!(sig.len() == 128 && sig.bytes().all(|b| b.is_ascii_hexdigit()),\n    \"Distro.sig must be 128 hex chars (64 bytes), got {} chars\", sig.len());","typeGuard":"fn is_hex_sig(s: &str) -> bool {\n    let s = s.trim();\n    s.len() == 128 && s.bytes().all(|b| b.is_ascii_hexdigit())\n}","tryCatchPattern":"match verify_lock(&lock, &sig_hex, &pk) {\n    Err(e) if e.to_string().contains(\"malformed Distro.sig\") => {\n        eprintln!(\"signature file is not 64-byte hex — re-sign or convert from base64\");\n    }\n    other => other?,\n}","preventionTips":["Always generate Distro.sig with the distro signing command (hex output).","Convert base64 signatures from external tools to hex before writing the file.","Check file size (128 bytes + optional newline) after any transfer of Distro.sig."],"tags":["crypto","signature","hex","format-validation"],"backgroundTag":"invalid-signature-format","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}