{"record":{"id":"5a670c8b52669163","repo":"Hmbown/CodeWhale","slug":"the-update-is-not-a-valid-notarized-codewhale-release-your","errorCode":null,"errorMessage":"The update is not a valid notarized Codewhale release. Your current app has been kept.","messagePattern":"The update is not a valid notarized Codewhale release\\. Your current app has been kept\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"crates/tui/plugins/computer-use/app/install-macos.mjs","lineNumber":43,"sourceCode":"    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":25,"sourceCodeEnd":47,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/app/install-macos.mjs#L25-L47","documentation":"verifyReleaseBundle enforces Apple's Gatekeeper notarization: codesign -R with the Codewhale team-ID/identifier requirement plus spctl --assess must pass, and spctl must report 'source=Notarized Developer ID'. If either command fails or the source is not notarized, the bundle is rejected as an unofficial release and the existing install is kept untouched.","triggerScenarios":"A bundle signed by a different team (not 5RDNSHA5TY), with a different identifier, ad-hoc/self-signed, notarization expired or never stapled, or spctl reporting a source other than 'Notarized Developer ID' (e.g. a local allow-list override).","commonSituations":"Distributing a locally built or self-signed build; a third-party mirror serving a re-signed app; macOS unable to contact Apple's notarization services (offline) so assessment fails; testing an update produced outside the official release pipeline.","solutions":["Download updates only from the official Codewhale release channel and retry","Distribute through the official notarization pipeline: archive with team 5RDNSHA5TY, codesign with Developer ID, xcrun notarytool submit, staple the ticket","Check spctl --assess --verbose=2 output to see the reported source and fix the specific gap (missing staple, wrong team)","Confirm network access to Apple's notarization services if assessment fails intermittently"],"exampleFix":"// before (locally signed build fails the notarization gate)\ncode.verifyReleaseBundle(localBuild);\n// after\ncode.spawnSync(\"xcrun\", [\"notarytool\", \"submit\", \"build.zip\", \"--keychain-profile\", \"AC_NOTARY\", \"--wait\"]);\ncode.spawnSync(\"xcrun\", [\"stapler\", \"staple\", \"build/Codewhale Computer Use.app\"]);\ncode.verifyReleaseBundle(\"build/Codewhale Computer Use.app\");","handlingStrategy":"try-catch","validationCode":"const out = spawnSync(\"/usr/sbin/spctl\", [\"--assess\", \"--type\", \"execute\", \"--verbose=2\", bundle], { encoding: \"utf8\" });\nif (out.status !== 0 || !/^source=Notarized Developer ID\\r?$/m.test(out.stderr)) throw new Error(\"bundle is not notarized\");","typeGuard":null,"tryCatchPattern":"try {\n  verifyReleaseBundle(bundle);\n} catch (e) {\n  if (e.message.includes(\"not a valid notarized\")) {\n    keepCurrentInstall();\n    reportRejectedUpdate(e.message);\n  } else throw e;\n}","preventionTips":["Only distribute updates from the official notarized release channel","Run notarytool submit + stapler staple for every release build","Pin the team ID (5RDNSHA5TY) requirement in release verification","Ensure network access to Apple's notarization services when assessing"],"tags":["macos","notarization","gatekeeper","security"],"backgroundTag":"unexpected-api-response-shape","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"}