Skip to content

ci(desktop): gate PRs on the packaged macOS app actually launching - #3472

Open
benjaminshafii wants to merge 1 commit into
devfrom
ci/macos-signed-launch-gate
Open

ci(desktop): gate PRs on the packaged macOS app actually launching#3472
benjaminshafii wants to merge 1 commit into
devfrom
ci/macos-signed-launch-gate

Conversation

@benjaminshafii

Copy link
Copy Markdown
Member

Closes the hole that let the Electron 41 revert happen.

What went wrong

Adding the restricted keychain-access-groups entitlement made the signed app fail to launch — macOS AMFI killed it at exec:

Disallowing com.differentai.openwork because no eligible provisioning profiles found
Restricted entitlements not validated
AMFI: Code=-413 "No matching profile found"
→ exit 137 / SIGKILL, before stderr, before any JS

codesign --verify, spctl and stapler validate all passed. Signing succeeded; runtime entitlement authorization failed. So no build-time check could see it.

Why every check was green

Lane Result Why blind
evals/specs (Daytona) green Linux — AMFI doesn't exist
ci-tests.yml on macos-14 green never packages, signs, or launches Electron
local pnpm dev healthy unsigned → entitlements unenforced
local unsigned package boots unsigned → entitlements unenforced
signed artifact SIGKILL only built on push: dev, i.e. after merge

Nothing in the pipeline ever launched the artifact a user receives, before merge. build-electron-desktop.yml can sign+notarize but only triggers on workflow_dispatch or a branch named electron-notary-test — never on PRs.

Also worth noting: the test added alongside that entitlement asserted the plist contained the keychain group. It tested shape, never effect — the more correctly the fatal entitlement was wired, the greener it went.

The gate

.github/workflows/ci-macos-packaged-launch.yml + apps/desktop/scripts/macos-launch-gate.sh: package the app, ad-hoc sign it with the repo's real entitlements plist, launch it, require it to survive 10s.

Key point: ad-hoc signing reproduces the failure, so this needs no Developer ID cert, no notarization, and no repository secrets — it works on fork PRs and stays fast.

  • Path-filtered to the packaging/startup surface (entitlements*.plist, electron-builder*.yml, apps/desktop/electron/**, packaging scripts, lockfile)
  • On failure, prints exit code + signal, app stdout/stderr, the signed entitlements, and the matching AMFI log lines, so the cause is obvious from the red check
  • Third-party actions pinned to SHAs, per existing convention

Verified both directions locally

rm -rf apps/desktop/dist-electron \
  && CSC_IDENTITY_AUTO_DISCOVERY=false pnpm --filter @openwork/desktop package:electron:dir \
  && bash apps/desktop/scripts/macos-launch-gate.sh
Case Result
dev's current entitlements exit 0 — survived 10s (67s cold)
exact keychain-access-groups entitlement restored exit 1 — app exit 137, signal 9 SIGKILL, AMFI Restricted entitlements not validated (31s)

Entitlement reverted afterwards. Electron stays on 35 — this PR is the gate only, no re-land.

Also green: pnpm --filter @openwork/desktop test (174 passed, 1 skipped), actionlint, bash -n.

What this does NOT catch

Developer ID credential problems, provisioning-profile correctness, notarization/stapling/Gatekeeper failures, non-arm64 architectures, and anything that only breaks after the 10s window. It catches launch-blocking entitlement and startup-crash regressions — the class that just bit us.

The Electron 41 revert exposed a hole: adding the restricted
keychain-access-groups entitlement made the signed app die at exec with
AMFI SIGKILL (exit 137) before any JS ran, while every check went green.
ci-tests.yml runs on macos-14 but never packages or launches Electron,
and the signed build only runs on push to dev — after merge.

Ad-hoc signing reproduces the failure with no Developer ID and no
notarization, so this gate needs no secrets and works on fork PRs:
package, ad-hoc sign with the real entitlements, launch, require the
process to survive 10s. On failure it prints the exit signal and the
AMFI log lines naming the cause.

Verified both directions locally: passes on dev's entitlements, and
fails with exit 137 when the keychain entitlement is restored.
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
openwork-app Ready Ready Preview Aug 3, 2026 5:31pm
openwork-den Ready Ready Preview Aug 3, 2026 5:31pm
openwork-den-worker-proxy Ready Ready Preview Aug 3, 2026 5:31pm
openwork-diagnostics Ready Ready Preview Aug 3, 2026 5:31pm
openwork-landing Ready Ready Preview, v0 Aug 3, 2026 5:31pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant