feat(macos): sign and notarize the DMG, app, and server binary#10510
Open
localai-bot wants to merge 1 commit into
Open
feat(macos): sign and notarize the DMG, app, and server binary#10510localai-bot wants to merge 1 commit into
localai-bot wants to merge 1 commit into
Conversation
Produce a Gatekeeper-clean macOS distribution with no user workaround: - Launcher DMG + the LocalAI.app inside it are built via fyne, codesigned with the Developer ID under the hardened runtime, then the DMG is signed, notarized (notarytool) and stapled. Replaces macos-dmg-creator (which had no signing hook) with fyne package + hdiutil so we control the .app before packaging. - The bare local-ai darwin server binary is signed + notarized via GoReleaser's native notarize block (quill backend, runs on Linux). - All signing is gated on secrets being present, so forks/PRs/local builds stay unsigned and green (contrib/macos/sign-and-notarize.sh no-ops). - Add hardened-runtime entitlements and FyneApp.toml for deterministic packaging; update macOS install docs to drop the quarantine workaround. Assisted-by: Claude:claude-opus-4-8 [Claude Code] Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This was referenced Jun 25, 2026
This comment was marked as outdated.
This comment was marked as outdated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background / the issue
Until now LocalAI's macOS artifacts shipped unsigned and un-notarized:
LocalAI.dmgand theLocalAI.appinside it had no Developer ID signature.local-ai-<tag>-darwin-arm64server binary (the one the launcher downloads at runtime) was also unsigned.Because of that, macOS Gatekeeper quarantined the downloads and users had to run manual workarounds (
xattr -d com.apple.quarantine, right-click > Open, etc.) just to launch LocalAI. This was tracked in #6244 (signing) and #6268 (quarantine workaround), and called out in the install docs.This PR fixes that: both artifacts are now Developer ID code-signed and Apple-notarized, so they launch with no prompt and no workaround.
What
LocalAI.dmg+ theLocalAI.appinside it - built withfyne package, codesigned under the hardened runtime, wrapped into a drag-to-Applications DMG viahdiutil, the DMG is signed, thennotarytoolsubmits andstaplerstaples it. Replacesmacos-dmg-creator(which built the app+DMG atomically with no point to sign in between).local-ai-<tag>-darwin-arm64server binary - signed + notarized via GoReleaser's nativenotarizeblock (quill backend, so it still runs on the existing Linux GoReleaser job, no extra macOS runner). Signing both is what makes it truly workaround-free.How it stays green for forks/PRs
Every signing step is gated on its secret being present.
contrib/macos/sign-and-notarize.shno-ops when theMACOS_*secrets are unset, and the GoReleasernotarizeblock isenabled: '{{ isEnvSet \"MACOS_SIGN_P12\" }}'. So forks, PRs, and localmake build-launcher-darwinkeep producing unsigned artifacts and never fail.Required repo secrets (configured on mudler/LocalAI)
MACOS_CERTIFICATE,MACOS_CERTIFICATE_PWD,MACOS_CI_KEYCHAIN_PWD,MACOS_SIGN_IDENTITY,MACOS_NOTARY_KEY,MACOS_NOTARY_KEY_ID,MACOS_NOTARY_ISSUER_ID.Files
contrib/macos/sign-and-notarize.sh(new) - import-cert / sign / notarize+staple helper, all no-op without secrets.contrib/macos/Launcher.entitlements(new) - hardened-runtime entitlements (network + JIT/unsigned-exec-memory for Fyne).cmd/launcher/FyneApp.toml(new) - deterministicfyne packagemetadata.Makefile- newbuild-launcher-darwin(fyne + sign),dmg-launcher-darwin(hdiutil + sign),notarize-launcher-darwin,release-launcher-darwin; Linux launchermvupdated toLocalAI.tar.xz(FyneApp.toml renames the output)..goreleaser.yaml- buildid: local-ai+notarize:block..github/workflows/release.yaml- cert import + signed DMG build on the darwin job;MACOS_*env on the GoReleaser job.docs/content/installation/macos.md- drop the quarantine workaround, document verification.Known limitations / things to watch
fyne/hdiutil/codesign/notarytoolinvocations only run on the macOS runner during a realv*release, so the signing path is exercised for the first time on the next release tag, not on this PR. Local validation was limited tobash -n,make -n release-launcher-darwin, and plist/toml lint (all pass).contrib/macos/Launcher.entitlements; debug viaxcrun notarytool log <submission-id>.FyneApp.toml(launcher.tar.xz->LocalAI.tar.xz); thebuild-launcher-linuxmvwas updated to match - watch that job stays green.Verification plan
Push a throwaway tag (e.g.
v0.0.0-sigtest), confirm thegoreleaser+launcher-build-darwinjobs succeed, download the DMG/binary and runspctl --assess --type open -von a Mac, then delete the test tag/release.Closes #6244
Closes #6268
Assisted-by: Claude:claude-opus-4-8 [Claude Code]