{"record":{"id":"4e28717ebd31fd79","repo":"jdx/mise","slug":"the-embedded-notification-helper-is-not-developer","errorCode":null,"errorMessage":"the embedded notification helper is not Developer ID signed","messagePattern":"the embedded notification helper is not Developer ID signed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/notify/macos.rs","lineNumber":51,"sourceCode":"    // running helper. The bundle identifier remains stable across versions.\n    let fingerprint = crate::hash::hash_to_str(&(HELPER, INFO, ICON, CODE_RESOURCES));\n    root.join(fingerprint).join(\"mise.app\")\n}\n\nfn executable(app: &Path) -> PathBuf {\n    app.join(\"Contents/MacOS/mise-notify\")\n}\n\nfn complete(app: &Path) -> bool {\n    executable(app).is_file()\n        && app.join(\"Contents/Info.plist\").is_file()\n        && app.join(\"Contents/Resources/mise.icns\").is_file()\n        && app.join(\"Contents/_CodeSignature/CodeResources\").is_file()\n}\n\npub(super) fn notification(title: &str, body: &str) -> Result<Command> {\n    if !release_signed() {\n        bail!(\"the embedded notification helper is not Developer ID signed\");\n    }\n    let app = ensure_app(&crate::dirs::DATA.join(\"notifications\"))?;\n    Ok(notification_command(&app, title, body))\n}\n\nfn notification_command(app: &Path, title: &str, body: &str) -> Command {\n    let mut command = Command::new(executable(app));\n    command.args([title, body]);\n    command\n}\n\nfn ensure_app(root: &Path) -> Result<PathBuf> {\n    let app = app_path(root);\n    if complete(&app) {\n        return Ok(app);\n    }\n    crate::file::create_dir_all(root)?;\n    let mut lock = fslock::LockFile::open(&root.join(\"install.lock\"))?;","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/notify/macos.rs#L33-L69","documentation":"On macOS, mise shows notifications through an embedded helper app bundle that must be signed with a Developer ID (and contain the expected icon/signature resources). notification() refuses to proceed when the checked bundle fails the release_signed() probe, because unsigned helpers are killed by notification infrastructure (especially Gatekeeper/notarization rules).","triggerScenarios":"Requesting a macOS notification when the helper app at Contents/MacOS / mise.icns / _CodeSignature checks pass structurally but the code signature is not a Developer ID signature — e.g. running a self-built or ad-hoc-signed mise, or a tampered helper bundle.","commonSituations":"Developer built mise from source and its embedded app is ad-hoc signed; the helper bundle was rebuilt locally losing the Developer ID signature; a packaged distribution stripped or re-signed the embedded app with a non-Developer ID identity.","solutions":["Install an official mise release (Developer ID signed) via the recommended installer or package manager instead of a locally built binary.","Re-build/obtain the helper with a valid Developer ID Application certificate: `codesign --sign \"Developer ID Application: <team>\"`.","Verify the signature with `codesign -dv --verbose=4 <path>/mise.app` and re-deploy the correct bundle.","Disable notifications from mise if unsigned local builds are required (avoid the notify path)."],"exampleFix":"// before (local build)\ncargo build --release   # helper ad-hoc signed -> error\n// after\n# install official signed release\ncurl https://mise.run | sh\n# or sign the helper\ncodesign --force --sign \"Developer ID Application: YOURTEAM\" mise.app","handlingStrategy":"fallback","validationCode":"const { execSync } = require('child_process');\nexport function isDeveloperIdSigned(appPath: string): boolean {\n  try {\n    const out = execSync(`codesign -dv \"${appPath}\" 2>&1`).toString();\n    return /Authority=Developer ID Application/.test(out);\n  } catch {\n    return false;\n  }\n}","typeGuard":"function hasCodeSignature(app: string): boolean {\n  return require('fs').existsSync(`${app}/Contents/_CodeSignature/CodeResources`);\n}","tryCatchPattern":"try {\n  await notify(title, body);\n} catch (e) {\n  if (/not Developer ID signed/.test(String(e))) {\n    logger.warn('notifications unavailable for unsigned local builds');\n  } else throw e;\n}","preventionTips":["Use official signed mise releases on macOS","Re-sign locally built helper bundles with a Developer ID certificate","Verify with `codesign -dv` before packaging"],"tags":["macos","code-signing","notification","gatekeeper"],"backgroundTag":"missing-dependency","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}