{"record":{"id":"40bc967821413021","repo":"Hmbown/CodeWhale","slug":"the-app-signature-did-not-verify-result-stderr-trim-codesign","errorCode":null,"errorMessage":"The app signature did not verify: ${result.stderr?.trim() ?? \"codesign unavailable\"}","messagePattern":"The app signature did not verify: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"crates/tui/plugins/computer-use/app/install-macos.mjs","lineNumber":33,"sourceCode":"  try {\n    fs.cpSync(source, next, { recursive: true });\n    prepare(next);\n    verify(next);\n    if (fs.existsSync(destination)) {\n      const backups = path.join(parent, \".codewhale-cu-backups\");\n      fs.mkdirSync(backups, { recursive: true, mode: 0o700 });\n      backup = path.join(backups, `${Date.now()}-${crypto.randomUUID()}.app`);\n      fs.renameSync(destination, backup);\n    }\n    try { fs.renameSync(next, destination); }\n    catch (error) { if (backup) fs.renameSync(backup, destination); throw error; }\n    return { backup };\n  } finally { fs.rmSync(staging, { recursive: true, force: true }); }\n}\n\nexport function verifySignature(bundle) {\n  const result=spawnSync(\"codesign\",[\"--verify\",\"--deep\",\"--strict\",bundle],{encoding:\"utf8\"});\n  if(result.status!==0) throw new Error(`The app signature did not verify: ${result.stderr?.trim() ?? \"codesign unavailable\"}`);\n}\n\nexport function verifyReleaseBundle(bundle) {\n  verifySignature(bundle);\n  const requirement='=anchor apple generic and identifier \"net.codewhale.computer-use\" and certificate leaf[subject.OU] = \"5RDNSHA5TY\"';\n  for(const [command,args] of [[\"/usr/bin/codesign\",[\"--verify\",\"--strict\",\"-R\",requirement,bundle]],[\"/usr/sbin/spctl\",[\"--assess\",\"--type\",\"execute\",\"--verbose=2\",bundle]]]) {\n    const result=spawnSync(command,args,{encoding:\"utf8\"});\n    // Gatekeeper ships with macOS. Requiring its notarized source also rejects\n    // local allow-list overrides; consumer Macs do not need Xcode's stapler.\n    if(result.status!==0 || (command.endsWith(\"/spctl\") && !/^source=Notarized Developer ID\\r?$/m.test(result.stderr))) throw new Error(\"The update is not a valid notarized Codewhale release. Your current app has been kept.\");\n  }\n  if(!fs.existsSync(path.join(bundle,\"Contents\",\"MacOS\",\"node\"))) throw new Error(\"The release is missing its bundled runtime.\");\n}\n","sourceCodeStart":15,"sourceCodeEnd":47,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/app/install-macos.mjs#L15-L47","documentation":"verifySignature runs `codesign --verify --deep --strict` on the staged bundle and throws when the codesign exit status is non-zero. This is the first line of defense ensuring the update binary is signed and untampered; the thrown message includes codesign's stderr for diagnosis.","triggerScenarios":"Verifying a bundle that is unsigned, signed with an expired/revoked certificate, modified after signing (hash mismatch), corrupted during download/extraction, or when the codesign tool itself fails/is unavailable (empty stderr yields 'codesign unavailable').","commonSituations":"Re-signing or patching the app locally after build; truncated or tampered download; CI artifacts built without a signing identity; a Mac with a broken or keychain-locked codesign environment.","solutions":["Re-download the release from the official source and re-verify (rules out corruption/tampering)","Sign the bundle with a valid Developer ID before distribution: codesign --deep --force --sign 'Developer ID Application: ...'","Inspect the stderr included in the message (e.g. 'code object is not signed at all', 'expired') and address the specific codesign failure","Ensure macOS command line tools are installed so /usr/bin/codesign exists and works"],"exampleFix":"// before (unsigned dev build goes straight to verify)\ncode.verifyReleaseBundle(staged);\n// after\ncode.spawnSync(\"codesign\", [\"--deep\", \"--force\", \"--sign\", process.env.DEV_ID, staged]);\ncode.verifyReleaseBundle(staged);","handlingStrategy":"try-catch","validationCode":"const probe = spawnSync(\"codesign\", [\"--verify\", \"--deep\", \"--strict\", bundle], { encoding: \"utf8\" });\nif (probe.status !== 0) console.error(\"signature check will fail:\", probe.stderr);","typeGuard":null,"tryCatchPattern":"try {\n  verifySignature(bundle);\n} catch (e) {\n  if (e.message.startsWith(\"The app signature did not verify\")) {\n    console.error(\"Rejecting bundle:\", e.message); // keep existing install\n  } else throw e;\n}","preventionTips":["Never modify bundle contents after signing","Sign with a valid, unexpired Developer ID certificate in CI","Verify downloads with the published SHA-256 before signature checks","Keep macOS command line tools installed so codesign is present"],"tags":["macos","codesign","security","signature-verification"],"backgroundTag":"checksum-mismatch","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}