{"record":{"id":"67093604285778d4","repo":"Hmbown/CodeWhale","slug":"signing-key-exceeds-size-limit","errorCode":null,"errorMessage":"signing key exceeds size limit","messagePattern":"signing key exceeds size limit","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/scripts/facts-publish.mjs","lineNumber":367,"sourceCode":"    const bytes = Buffer.alloc(maxBytes + 1);\n    let size = 0;\n    while (size <= maxBytes) {\n      const count = readSync(fd, bytes, size, maxBytes + 1 - size, null);\n      if (!count) break;\n      size += count;\n    }\n    if (size > maxBytes) throw new Error(\"file exceeds size limit\");\n    return bytes.subarray(0, size);\n  } finally { closeSync(fd); }\n}\n\nfunction loadPrivateKeyFromEnv() {\n  refuseUnderCi();\n  let pem = process.env.CODEWHALE_FACTS_SIGNING_KEY;\n  const file = process.env.CODEWHALE_FACTS_SIGNING_KEY_FILE;\n  if (!pem && file) pem = readBoundedFile(file, 16 * 1024).toString(\"utf8\");\n  if (!pem) throw new Error(\"set CODEWHALE_FACTS_SIGNING_KEY (PEM) or CODEWHALE_FACTS_SIGNING_KEY_FILE\");\n  if (Buffer.byteLength(pem) > 16 * 1024) throw new Error(\"signing key exceeds size limit\");\n  const key = createPrivateKey({ key: pem, format: \"pem\" });\n  if (key.asymmetricKeyType !== \"ed25519\") throw new Error(\"signing key must be Ed25519\");\n  return key;\n}\n\nexport function validateTrustedKeys(keys) {\n  const seen = new Set();\n  for (const key of keys) {\n    if (!KEY_ID_RE.test(key.keyId) || seen.has(key.keyId) || ![\"active\", \"retired\"].includes(key.status) || strictBase64(key.publicKey, 32).length !== 32) throw new Error(\"invalid or duplicated pinned key\");\n    seen.add(key.keyId);\n  }\n  return keys;\n}\n\n/** Deliberately narrow syntax: a changed/unparseable table must fail the gate. */\nexport function parseTsKeys(text) {\n  const source = text.replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\").replace(/^\\s*\\/\\/.*$/gm, \"\");\n  const tables = [...source.matchAll(/^\\s*export\\s+const\\s+TRUSTED_KEYS\\s*:\\s*readonly\\s+TrustedKey\\[\\]\\s*=\\s*\\[([\\s\\S]*?)\\]\\s*;/gm)];","sourceCodeStart":349,"sourceCodeEnd":385,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/web/scripts/facts-publish.mjs#L349-L385","documentation":"After loading the PEM (from env or via readBoundedFile capped at 16 KiB), loadPrivateKeyFromEnv re-checks the byte length and throws if it exceeds 16 KiB. The bound is a defensive limit so an accidentally huge or hostile env value cannot be parsed as a key.","triggerScenarios":"loadPrivateKeyFromEnv when Buffer.byteLength(pem) > 16384 — e.g. CODEWHALE_FACTS_SIGNING_KEY containing a multi-key bundle, embedded newlines/whitespace bloat, or pasted extra content.","commonSituations":"Exporting the whole ~/.ssh output or a concatenated authority bundle into the env var; shell quoting duplicating content; a secrets template expanding to multiple keys.","solutions":["Trim the env value to a single PEM block (one BEGIN/END PRIVATE KEY section)","Check size: printenv CODEWHALE_FACTS_SIGNING_KEY | wc -c — keep it well under 16384","If using the file path variant, ensure the file holds only one key","Regenerate a fresh Ed25519 key if yours was wrapped with unusual armor padding"],"exampleFix":"// before\nexport CODEWHALE_FACTS_SIGNING_KEY=\"$(cat bundle.pem)\"   # several keys\n// after\nawk '/BEGIN/{f=1} f{print} /END/{exit}' bundle.pem > one.pem\nexport CODEWHALE_FACTS_SIGNING_KEY=\"$(cat one.pem)\"","handlingStrategy":"validation","validationCode":"const pem = process.env.CODEWHALE_FACTS_SIGNING_KEY ?? '';\nif (Buffer.byteLength(pem) > 16 * 1024) throw new Error(`signing key is ${Buffer.byteLength(pem)}B; must be under 16384B`);","typeGuard":"const isBoundedPem = (s) => typeof s === 'string' && s.length > 0 && Buffer.byteLength(s) <= 16 * 1024;","tryCatchPattern":"try { key = loadPrivateKeyFromEnv(); } catch (e) { if (e.message === 'signing key exceeds size limit') { console.error('Trim the PEM to a single key block under 16 KiB'); process.exit(2); } throw e; }","preventionTips":["Export exactly one PEM block — never whole bundles","Check `printenv ... | wc -c` after setting the variable","Watch for shell template expansion duplicating content","Regenerate keys with standard armor if the PEM is unusually padded"],"tags":["configuration","size-limit","signing"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}