Hmbown/CodeWhale · critical · Error
The app signature did not verify
Error message
The app signature did not verify: ${result.stderr?.trim() ?? "codesign unavailable"} What it means
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.
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
Example fix
// before (unsigned dev build goes straight to verify)
code.verifyReleaseBundle(staged);
// after
code.spawnSync("codesign", ["--deep", "--force", "--sign", process.env.DEV_ID, staged]);
code.verifyReleaseBundle(staged); Defensive patterns
Strategy: try-catch
Validate before calling
const probe = spawnSync("codesign", ["--verify", "--deep", "--strict", bundle], { encoding: "utf8" });
if (probe.status !== 0) console.error("signature check will fail:", probe.stderr); Try / catch
try {
verifySignature(bundle);
} catch (e) {
if (e.message.startsWith("The app signature did not verify")) {
console.error("Rejecting bundle:", e.message); // keep existing install
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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').
Common situations: 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.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- macOS builds require codesign to package Computer Use
- The update is not a valid notarized Codewhale release. Your…
- agent action=claim widens an enforced write scope, and the…
- allowlisted read-only executable
- append_allow_rules only accepts action = "allow"
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/40bc967821413021.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/app/install-macos.mjs:33
try {
fs.cpSync(source, next, { recursive: true });
prepare(next);
verify(next);
if (fs.existsSync(destination)) {
const backups = path.join(parent, ".codewhale-cu-backups");
fs.mkdirSync(backups, { recursive: true, mode: 0o700 });
backup = path.join(backups, `${Date.now()}-${crypto.randomUUID()}.app`);
fs.renameSync(destination, backup);
}
try { fs.renameSync(next, destination); }
catch (error) { if (backup) fs.renameSync(backup, destination); throw error; }
return { backup };
} finally { fs.rmSync(staging, { recursive: true, force: true }); }
}
export function verifySignature(bundle) {
const result=spawnSync("codesign",["--verify","--deep","--strict",bundle],{encoding:"utf8"});
if(result.status!==0) throw new Error(`The app signature did not verify: ${result.stderr?.trim() ?? "codesign unavailable"}`);
}
export function verifyReleaseBundle(bundle) {
verifySignature(bundle);
const requirement='=anchor apple generic and identifier "net.codewhale.computer-use" and certificate leaf[subject.OU] = "5RDNSHA5TY"';
for(const [command,args] of [["/usr/bin/codesign",["--verify","--strict","-R",requirement,bundle]],["/usr/sbin/spctl",["--assess","--type","execute","--verbose=2",bundle]]]) {
const result=spawnSync(command,args,{encoding:"utf8"});
// Gatekeeper ships with macOS. Requiring its notarized source also rejects
// local allow-list overrides; consumer Macs do not need Xcode's stapler.
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.");
}
if(!fs.existsSync(path.join(bundle,"Contents","MacOS","node"))) throw new Error("The release is missing its bundled runtime.");
}
View on GitHub (pinned to 73e0f67d83)