Repository navigation
fix(mac): preserve privileged helper signing identity (#175) - #192
Noah-Tervalon-Nvidia merged 2 commits into
Conversation
Signed-off-by: Myles Shannon <github@mylesshannon.com>
Noah-Tervalon-Nvidia
left a comment
There was a problem hiding this comment.
This looks great, but one thing is missing - when someone upgrades from 1.0.0 to whichever version has this they won't get the fix. Since the 1.0.0 version causes the daemon to fail it'll be unreachable, and in desktop/src/electron/services/mac-privilege-service.ts unreachable is treated as healthy so we wouldn't re-register the correctly signed helper.
Pretty sure the fix is just treat enabled && !reachable as stale, run uninstall() + install() once per app version, then re-check status(). Also stop reporting firewallConfigured: true without reaching the daemon (i.e. treat unreachable as failure rather than success).
|
moving out of draft as well. I have verified this with an internally signed build, with the fix, I'll do another round of verification and then we can merge this in. |
Signed-off-by: Myles Shannon <github@mylesshannon.com>
|
I’ve pushed an update addressing the upgrade path. Enabled but unreachable helpers now get one unregister/register attempt per app version, persisted across restarts, followed by another status check. Setup stays incomplete if the helper remains unreachable or firewall configuration fails. I added regression coverage, and all local checks pass. It’s ready for another round of signed-build testing. Thanks for catching this. |
<!-- pair-release-intent:v1 --> ### Changelog title Recover stale macOS helper registrations after upgrades ### Changelog body - Allow a delayed, bounded retry when macOS retains the privileged helper's old signing identity after an upgrade. - Preserve the retry limit across application restarts and pending background-item approval. ### Bumps - services: patch - nvpair-cluster-manager: none - nvpair-engine-manager: none - nvpair-errors: none - nvpair-job-scheduler: none - nvpair-manual-nodes: none - nvpair-node-info: none - nvpair-node-scanner: none - nvpair-node-settings: none - nvpair-proxy: none - nvpair-tui: none - nvpair-ui-broker: none - nvpair-workload-manager: none <!-- /pair-release-intent:v1 --> ## Summary Follow-up to #192, related to #175. **Depends on #192.** This branch includes its two commits and merges the latest `develop`; the new recovery change is isolated in [a4dd4bf](MylesShannon@a4dd4bf). The PR diff currently includes the prerequisite signing fix. Testing the signed build on my Apple Silicon Mac confirmed that both native binaries satisfy the pinned signing requirements. However, launchd retained a launch constraint requiring the old helper identifier, `com.nvidia.nvpair`, and rejected the correctly signed `com.nvidia.nvpair.helper`. macOS invalidated the old registration about 10 seconds later, but the job continued failing. An additional unregister/register cycle recovered XPC communication, firewall configuration, and setup persistence across app restarts. The existing once-per-version repair marker prevented that additional cycle. This change permits at most two replacement attempts per app version, saving the count and clearing setup completion before each unregister. Before the second attempt, it waits 12 seconds and checks status again. A recovered helper is left running, and pending approval stops recovery until a subsequent launch. A saved version without a count consumes the first attempt. ## Scope macOS helper recovery, persisted attempt bookkeeping, regression tests, and the existing helper documentation. The follow-up leaves signing requirements, helper identifiers, privileged operations, and Windows/Linux behavior unchanged. `services: patch` records the desktop bug fix in release notes; all Go component bumps remain `none` because their compiled output is unchanged. ## Validation - `make -o desktop/package-lock.json check`: SPDX headers, build-script verification, lint, all three TypeScript targets, service contracts, 26 Node tests, and 303 Vitest tests passed. The make option reuses installed dependencies; the upstream lockfile change only updates the application version. - `cd desktop && npm run dead-code:check`: passed. - `cd desktop && ./node_modules/.bin/vitest run --project unit tests/modular/mac-privilege-service.test.ts`: 21 tests passed. The five initial recovery regressions failed against the previous implementation before the fix. - Coverage includes waiting before a second unregister, recovery during the wait, approval before/during recovery, interrupted attempts, persisted limits across reloads, a new app version, and the previous version-only repair marker. - `git diff --check`: passed. - Manual evidence above is from the signed prerequisite build plus a controlled CLI recovery, not a signed build of this follow-up. ## Risk and remaining test The 12-second delay is based on the observed launchd repair window, not an Apple timing guarantee. A failed retry leaves setup incomplete and cannot repeat replacement indefinitely. Signature pinning remains enforced throughout. - [ ] Validate this commit in an NVIDIA-signed build by upgrading an affected installation in place, without manually unregistering the helper or clearing its data. Confirm the automatic second attempt, XPC status, firewall configuration, and setup persistence across full app restarts and a reboot. Exercise approval followed by relaunch as well. ## Checklist - [x] I have read the contributing guidelines. - [x] Every commit is signed off for the Developer Certificate of Origin. - [x] Tests cover the change and relevant documentation is updated. - [x] I checked the diff, changed filenames, and commit messages for credentials, private data, internal URLs, internal issue identifiers, and generated artifacts. - [x] Validation commands and limitations are recorded above. - [x] Release intent is declared without editing automation-owned version files. --------- Signed-off-by: Myles Shannon <github@mylesshannon.com>
Changelog title
Restore macOS privileged helper communication after upgrades
Changelog body
Bumps
Description
Addresses #175. In PAIR 1.0.0 (build 1.0.0.85), the running helper is signed as
com.nvidia.nvpair, while its XPC peer correctly requirescom.nvidia.nvpair.helper. Filename-derived signing can strip the.helpersuffix, leaving registration enabled but XPC unreachable and setup incomplete.Embed the daemon's canonical
CFBundleIdentifierin both Mach-O architecture slices so standalone and recursive signing preserve its identity. Add a signing regression test and a release validator using the existing shared Swift requirements.On upgrade, treat an enabled but unreachable helper as stale even when its daemon version cannot be read. Persist the repair attempt and invalidate cached setup completion before unregistering, then register the replacement, re-check status, and configure the firewall. Replacement is limited to once per app version across launches. Registration errors, unreachable helpers, and a remaining version mismatch leave setup incomplete. Pending approval and firewall failures retain the normal next-launch setup path without another replacement cycle.
Scope
macOS helper build metadata, startup recovery, signing and recovery regression coverage, signature validation tooling, and release acceptance documentation. Existing XPC authentication, Developer ID trust, and identifier pinning remain intact. The control tool retains the enclosing application's
Bundle.mainrequired by ServiceManagement. No Go service implementation changes.Validation
make checkandnpm --prefix desktop run dead-code:checkpass. Includes lint, all TypeScript targets, build-script checks, service contracts, SPDX headers, 297 Vitest tests, and 26 Node tests.git diff --checkpasses. Priorsh -nvalidation of both added shell scripts passes; they are unchanged by the recovery update.npm run build:helper:macandnpm run test:helper-signing:macpass for the universal daemon. Without the embedded plist, the regression test fails. Incorrect identifiers in the x86_64 slice are rejected even when arm64 is correct.Release integration and outstanding checks
Release maintainers must invoke
npm run verify:helper-signatures:mac -- "/path/to/NVIDIA PAIR.app"after the final signing pass and fail the release if it exits nonzero. Repeat against each extracted DMG/ZIP. The public source change supplies the validator; release signing integration is still required.A development app skips helper setup, so the absence of its prompt is not validation of this fix. The signed-build acceptance procedure is documented in
desktop/docs/macos-privileged-helper.md.Risk
Packaging metadata must survive every signing pass. The first launch of each app version may replace a stale helper and require macOS approval. A failed replacement is not repeatedly attempted for the same version. No signing credentials or private signing implementation are included.
Checklist
git commit -s), certifying the Developer Certificate of Origin.none. Version files and changelog are left to automation.