{"record":{"id":"0d5324862ca19811","repo":"JuliusBrussee/caveman","slug":"label-has-unsupported-algorithm-string-info-a","errorCode":null,"errorMessage":"${label} has unsupported algorithm ${String(info.alg)}","messagePattern":"(.+?) has unsupported algorithm (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":17393,"sourceCode":"  let prev: Receipt | undefined;\n  for (const r of sorted) {\n    const decoded = keys.get(r.signature?.key_id);\n    if (!decoded) return `seq ${r.seq}: no trusted public key for key_id ${String(r.signature?.key_id)}`;\n    const err = verifyReceipt(r, decoded.key, decoded.info.key_id);\n    if (err) return err;\n    if (prev) {\n      if (r.seq !== prev.seq + 1) return `seq ${r.seq}: not strictly after ${prev.seq}`;\n      if (r.prev_receipt_hash !== prev.receipt_hash) return `seq ${r.seq}: prev_receipt_hash does not link to seq ${prev.seq}`;\n      if (r.day <= prev.day) return `seq ${r.seq}: day ${r.day} does not follow ${prev.day}`;\n    }\n    prev = r;\n  }\n  return null;\n}\n\nfunction decodeReceiptKey(info: ReceiptPublicKey, label: string): DecodedReceiptKey {\n  if (!info || typeof info.key_id !== \"string\" || !info.key_id.trim()) throw new Error(`${label} key_id is required`);\n  if (info.alg !== \"Ed25519\") throw new Error(`${label} has unsupported algorithm ${String(info.alg)}`);\n  if (typeof info.key !== \"string\" || !info.key.trim()) throw new Error(`${label} key is required`);\n  const raw = Buffer.from(info.key, \"base64\");\n  if (raw.length !== 32 || raw.toString(\"base64\") !== info.key) throw new Error(`${label} must be a canonical base64 Ed25519 public key`);\n  return { info, raw, key: ed25519PublicKey(raw) };\n}\n\nfunction decodeUniqueKeyring(infos: ReceiptPublicKey[], label: string): Map<string, DecodedReceiptKey> {\n  const keys = new Map<string, DecodedReceiptKey>();\n  for (const [index, info] of infos.entries()) {\n    const decoded = decodeReceiptKey(info, `${label}[${index}]`);\n    if (keys.has(decoded.info.key_id)) throw new Error(`${label} contains duplicate key_id ${decoded.info.key_id}`);\n    keys.set(decoded.info.key_id, decoded);\n  }\n  return keys;\n}\n\nfunction embeddedReceiptKeys(bundle: ReceiptBundle): { current: DecodedReceiptKey; keys: Map<string, DecodedReceiptKey> } {\n  if (bundle.schema !== RECEIPT_BUNDLE_V1 && bundle.schema !== RECEIPT_BUNDLE_V2) throw new Error(`unsupported bundle schema ${String(bundle.schema)}`);","sourceCodeStart":17375,"sourceCodeEnd":17411,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/index.ts#L17375-L17411","documentation":"The receipt verifier only supports Ed25519 signatures. A keyring entry whose alg is not exactly the string 'Ed25519' (e.g. 'ES256', 'RSA', or a case variant like 'ed25519') is rejected so verification never silently proceeds with an algorithm it cannot check.","triggerScenarios":"Keyring generated for a different signing scheme; algorithm strings with case differences or trailing whitespace; mixed keyrings where only some entries were migrated to Ed25519.","commonSituations":"Issuers migrating between algorithms; hand-merged keyrings from multiple sources; specs written with lowercase algorithm names.","solutions":["Set alg exactly to \"Ed25519\" — the comparison is case-sensitive","If the issuer signed with another algorithm, request an Ed25519 public key entry from them","Re-download the canonical keyring instead of merging entries manually"],"exampleFix":"// before\n{ \"key_id\": \"k1\", \"alg\": \"ES256\", \"key\": \"MCowBQYDK2VwAyEA...\" }\n// after\n{ \"key_id\": \"k1\", \"alg\": \"Ed25519\", \"key\": \"MCowBQYDK2VwAyEA...\" }","handlingStrategy":"type-guard","validationCode":"const ok = keyring.every((k) => k?.alg === 'Ed25519');\nif (!ok) throw new Error('keyring contains non-Ed25519 entries — fetch the canonical Caveman keyring');","typeGuard":"const isEd25519KeyInfo = (k: unknown): k is ReceiptPublicKey =>\n  typeof k === 'object' && k !== null && (k as ReceiptPublicKey).alg === 'Ed25519';","tryCatchPattern":null,"preventionTips":["Treat alg as an exact-match contract, not a hint","Never hand-merge keyrings across issuers","Alert on any algorithm change in the published keyring — it may signal rotation or compromise"],"tags":["crypto","keyring","algorithm","receipts"],"backgroundTag":"unsupported-key-algorithm","analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}