fix(release): grant V8 the JIT entitlements the Hardened Runtime requires - #20
Merged
Conversation
…ires v0.2.0 notarized cleanly and then crashed on launch. Enabling the Hardened Runtime to satisfy the notary service also denies V8 the executable memory it needs, so the Deno runtime thread aborted with SIGTRAP before the window opened. `deno desktop` had never enabled the Hardened Runtime, which is why this only appeared once signing was fixed. Sign every bundle that hosts V8 — the app and the CEF helper apps — with allow-jit, allow-unsigned-executable-memory, disable-library-validation and allow-dyld-environment-variables. Verified by re-signing the shipped build with these entitlements and nothing else: it went from exiting 133 to serving the studio bundle. Add the two checks that would have caught it. The signing step now asserts allow-jit on every V8 host, and a new step launches the signed app and requires it to stay up and serve the bundle. Notarization only proves Gatekeeper permits the app to run, which is what was verified for v0.2.0 and is not the same as it working.
There was a problem hiding this comment.
Code Review
This pull request adds a new entitlements.plist file for macOS packaging to define Hardened Runtime exceptions required by the embedded V8 and CEF runtimes, including permissions for JIT compilation, unsigned executable memory, disabled library validation, and DYLD environment variables. I have no feedback to provide on these changes.
Greptile SummaryThis PR repairs the signed macOS release path and adds launch verification.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| .github/workflows/release.yml | Reworks macOS signing to apply JIT entitlements, validates V8 hosts, adds native-architecture launch testing, and rebuilds the disk image from the signed bundle; the previously reported wait diagnostic issue is fixed by temporarily disabling errexit. |
| packaging/macos/entitlements.plist | Defines the Hardened Runtime exceptions required by the embedded Deno and CEF V8 processes. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Build macOS app bundle] --> B[Sign nested libraries]
B --> C[Sign V8 host bundles with entitlements]
C --> D[Verify signatures and allow-jit]
D --> E{Runner matches target architecture?}
E -->|Yes| F[Launch smoke test]
E -->|No| G[Warn that launch is unverified]
F --> H[Require process survival and Listening on log]
G --> I[Rebuild disk image]
H --> I
I --> J[Sign disk image]
J --> K[Notarize and staple]
Reviews (2): Last reviewed commit: "chore: apply AI code review suggestions" | Re-trigger Greptile
Run `wait` outside errexit in the smoke test. The app's exit status is non-zero by definition on that branch, so `set -e` killed the step before it could print the status, flag SIGTRAP, or dump the runtime log — the diagnostic path in the diagnostic step never ran.
|
amondnet
added a commit
that referenced
this pull request
Jul 28, 2026
v0.2.1 notarized as Invalid on both arches with a single issue:
path: OpenHWP.app/Contents/MacOS/laufey
message: The signature of the binary is invalid.
The signature was fine. On a successful start the app writes a 2-byte
marker, Contents/MacOS/laufey.dylib.update-ok, into its own bundle. That
adds a file the signature does not seal:
codesign --verify --deep --strict
a sealed resource is missing or invalid
file added: .../Contents/MacOS/laufey.dylib.update-ok
so the smoke test added in #20 broke the very artifact it was verifying,
between signing and packaging. v0.2.0 notarized only because it never
launched the app.
Launch a byte-identical copy in $RUNNER_TEMP instead. The copy absorbs
the marker and the shipped bundle is never executed. Reproduced and
verified locally: the copy gets the marker, the shipped bundle does not
and still reports "valid on disk / satisfies its Designated Requirement",
and the smoke test still logs "Listening on".
Also re-verify the bundle immediately before hdiutil. Any future mutation
under Contents/ now fails in seconds with the offending path named,
instead of coming back as an opaque notarization rejection ten minutes
later. Confirmed to exit 1 with the marker present and 0 without it.
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.



v0.2.0 is published and crashes on launch
Reported from a real install on macOS 15.6.1 / Intel:
EXC_BREAKPOINT (SIGTRAP)on the Deno runtime thread (RuntimeLoader::RuntimeThread→laufey_runtime_start), with V8 worker threads alive alongside it.I caused this in #18. To satisfy the notary service I signed everything with
--options runtime, but passed no entitlements. The Hardened Runtime denies a JIT its executable memory, so V8 aborts before the window opens.deno desktophad never enabled the Hardened Runtime — a plain build isflags=0x2(adhoc)— so the problem only appeared once signing was fixed.Proof
Same binaries, only the signature differs:
runtime, no entitlements)Runtime started,Listening on http://127.0.0.1:56287/Fix
packaging/macos/entitlements.plistgrants the standard V8/CEF Hardened Runtime exceptions —allow-jit,allow-unsigned-executable-memory,disable-library-validation,allow-dyld-environment-variables— applied to every bundle that hosts V8: the app and the five CEF helper apps. Libraries are signed without entitlements; they inherit the host process's.Why my verification missed it
I verified checksums,
spctl, stapling and the cask, and called the release "genuinely installable".spctl --assessonly says Gatekeeper will permit execution — it says nothing about whether the app runs. I never launched it.Two checks close that gap:
allow-jiton every V8 host and names the offending bundle.Listening on, and calls out exit 133 as a likely Hardened Runtime JIT denial. Cross-arch runs emit a::warning::saying the build is not launch-verified rather than passing silently.The workflow header comment is corrected too — it asserted that
deno desktopapplies the Hardened Runtime, which is the belief that produced this bug.Summary by cubic
Fixes the macOS launch crash by granting V8 the JIT entitlements required by the Hardened Runtime and verifying app startup in the release workflow. This ensures v0.2.0+ builds run instead of aborting with SIGTRAP.
packaging/macos/entitlements.plistwithallow-jit,allow-unsigned-executable-memory,disable-library-validation, andallow-dyld-environment-variables; applied to the app and CEF helper apps (libraries inherit).allow-jiton all V8 hosts during signing.waitoutsideerrexitso failures report the exit code and logs (cross-arch runs warn and skip).Written for commit fe76ba0. Summary will update on new commits.