fix(release): sign macOS DMGs so they install and run#899
Merged
Conversation
The DMGs were cross-compiled on the Linux job via dotnetpackager, so the arm64 Mach-O binaries shipped unsigned and macOS reported the app as "damaged and can't be opened". Add a dedicated build-macos job on macos-latest (matrix x64/arm64) that publishes natively, assembles the .app bundle, ad-hoc signs it with hardened-runtime + JIT entitlements (without which .NET fails to start CoreCLR), and packs a verified DMG. Removes the cross-compile DMG steps from build-linux (artifact renamed linux-macos-packages -> linux-packages) and wires build-macos into the release job. Documents the one-time first-launch bypass in the README. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The composition roots only registered an ISecureKeyProvider for Windows (DPAPI) and Linux, throwing PlatformNotSupportedException on macOS, so the desktop app crashed at launch on Mac. LinuxSecureKeyProvider is just a chmod-600 file store with nothing Linux-specific, so rename it to UnixFileSecureKeyProvider and register it for Linux || macOS in both the Avalonia app and the CLI. A Keychain-backed provider can replace it later without changing the contract. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Websocket.Client embeds LibLog, which reflects over Serilog to wire up its
internal logging. Partial trimming removed the reflected members, so the
app logged an ArgumentNullException ("Parameter 'method'") at startup.
Root both assemblies so the reflection targets survive.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The .icns was a full-bleed square (no rounded corners, no margin), so it looked wrong next to native macOS apps. Regenerate it on the macOS icon grid (1024 canvas, 824 rounded body, 100px transparent margin) with the full slice set including the 512pt and 1024px sizes the old icon lacked. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem
The published macOS
.dmgartifacts reported "damaged and can't be opened" on download. Root cause: the DMGs were cross-compiled on the Linux release job (dotnetpackager dmg), so the arm64 Mach-O binaries shipped unsigned — and macOS refuses to run an unsigned arm64 binary, surfacing it as "damaged" (a Gatekeeper/quarantine result, not real corruption).Fixing the signing alone wasn't enough — local testing surfaced two further blockers that meant the app couldn't run on macOS at all, plus a startup error.
Changes
build-macosjob (release-avalonia.yml) — new job onmacos-latest(matrix x64/arm64) that publishes natively, assembles the.app, ad-hoc signs it with hardened runtime + JIT entitlements, and packs a verified DMG. Cross-compile DMG steps removed frombuild-linux(artifactlinux-macos-packages→linux-packages).allow-jit,allow-unsigned-executable-memory, …) are required or .NET dies at launch withFailed to create CoreCLR, HRESULT: 0x80070008.CompositionRootonly handled Windows/Linux and threwPlatformNotSupportedExceptionon macOS. RenamedLinuxSecureKeyProvider→UnixFileSecureKeyProvider(a chmod-600 file store, nothing Linux-specific) and registered it forLinux || macOSin the app and CLI.Websocket.Client+Serilogso its embedded LibLog reflection survives trimming (was logging anArgumentNullExceptionat startup).AppIcon.icnson the macOS grid (rounded squircle + transparent margin; adds the 512pt/1024px slices the old square icon lacked).Signing approach
Ad-hoc (free, no Apple Developer ID). This removes "damaged"; users get the standard bypassable "unidentified developer" prompt on first launch. The bundle keeps hardened runtime, so it's notarization-ready if a Developer ID is added later.
Testing
Built both arm64 and x64 DMGs locally through the exact CI pipeline (official .NET SDK, ad-hoc sign + entitlements,
hdiutilUDZO). The app launches and runs: connects to Nostr relays, loads the wallet and investments, no runtime errors. Release build is 0 errors.🤖 Generated with Claude Code