Repository navigation
fix(desktop): keep a development build's Keychain grant across rebuilds - #247
charleslpan wants to merge 2 commits into
Conversation
An ad-hoc signature carries no identity, so macOS derives the designated requirement from the bytes themselves — a bare cdhash, new on every build. Both the Keychain and TCC bind a grant to that requirement, so every rebuild is a program neither has seen before: the login-password dialog returns however many times "Always Allow" was pressed, and a capture run hangs indefinitely because Screen Recording was never granted to that hash. LUKE_DEV_CODESIGN_IDENTITY names an identity to sign development builds with, moving the requirement onto the certificate, which every later build satisfies. It decides nothing else: resolveSigningMode still reads ad-hoc, so the build is still not a release, still answers to the development name, and still keeps its Keychain entry apart from the released app's. LUKE_CODESIGN_IDENTITY stays release-only, with a test pinning that. Electron's prebuilt bundle needs the same treatment for `electron .` runs: it ships linker-signed ad-hoc with no sealed resources, so it fails `codesign --verify` outright and the Keychain can never hold a durable entry for it. sidecar_sign_development_electron re-signs it after install, and leaves it alone when no identity is named. Without an identity nothing changes: the packager signs ad-hoc exactly as before and the Electron bundle is left as Electron shipped it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit e4ff435. Configure here.
`codesign --display` reports only the executable path; the signature line comes from `-dvv`. The ad-hoc half of the skip test therefore matched nothing, so a bundle that verifies while still ad-hoc — one already re-signed `--sign -` — was left without the stable identity. The identity is trimmed here the way `developmentSigningIdentity` trims it too. A padded value would otherwise package fine and then reach codesign as a name wrapped in spaces, failing the lookup and taking the launch down with it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Risk: high. Left a non-blocking comment; this still changes codesigning and Keychain/TCC trust, so it stays above the approval threshold even though Bugbot and Security Agent passed and the prior findings are resolved. dastratakos is already assigned; no additional reviewers were added.
Sent by Cursor Approval Agent: Pull Request Router and Approver



Problem
A development build is signed ad-hoc, which carries no identity — so macOS derives the designated requirement from the bytes themselves, a bare
cdhashthat is new on every build. Both the Keychain and TCC bind a grant to that requirement, so every rebuild is a program neither has seen before.Two symptoms, one cause:
Luke Dev Safe Storagelogin-password dialog returns on every launch, however many times "Always Allow" was pressed. The item's ACL accumulates one dead entry per build path (-67068 cannot find code object on disk), all pinned bycdhash, while the released app's single entry is pinned by identity and survives every update../scripts/evidence.shhangs indefinitely with no error. The capture app launches, loads ScreenCaptureKit, and never writes a PNG, because Screen Recording was never granted to that hash. Apple states the rule directly: TCC uses the code signature to decide that version N+1 is the same code as version N, and an ad-hoc signed app has no stable identity to remember.electron .runs are worse: Electron's prebuilt bundle is linker-signed ad-hoc with no sealed resources, so it failscodesign --verifyoutright ("code has no resources but signature indicates they must be present") and the Keychain can never hold a durable entry for it at all.Change
LUKE_DEV_CODESIGN_IDENTITYnames an identity to sign development builds with, moving the requirement onto the certificate.sidecar_sign_development_electrongives Electron's bundle the same treatment after install.It decides nothing else —
resolveSigningModestill reads ad-hoc, so the build is still not a release, still answers to the development name, and still keeps its Keychain entry apart from the released app's.LUKE_CODESIGN_IDENTITYstays release-only, with a test pinning that.Without an identity named, nothing changes: the packager signs ad-hoc exactly as before, and the Electron bundle is left as Electron shipped it. The release path is untouched.
For review
This adds a third state to a boundary the project guards deliberately — signed, but still not a release.
app-identity.tsandresolveSigningModewere built around a two-way split. The tests pin the new state so it cannot drift, but it is a widening worth deciding rather than assuming.Also worth a look:
sidecar_ensure_dependenciesnow signs as well as bootstraps, so its name no longer covers what it does. Callingsidecar_sign_development_electronfromrun.shandevidence.shdirectly would keep each function to one job.Verification
./scripts/check.sh— passes./scripts/evidence.sh— passes, six PNGs, expanded frame inspected and unchanged. This only completes withLUKE_DEV_CODESIGN_IDENTITYset; without it the capture hangs on this machine, which is the second symptom above.buildCarriesDeveloperIdSigning()still compiles tofalse, so it keeps the development name, state directory, and Keychain entry.🤖 Generated with Claude Code
Automated visual evidence
Download the deterministic macOS evidence · workflow run
4c926586c310c1738bbb72cad23ba0d747e74dd1smoke