You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 6765d41
Browse filesBrowse the repository at this point in the historyBrowse files
<!-- pair-release-intent:v1 -->
### Changelog title
Restore macOS privileged helper communication after upgrades
### Changelog body
- Preserve the helper-specific signing identifier needed to communicate
with the macOS background helper and complete setup.
- Replace an enabled but unreachable helper once per app version after
an upgrade, and keep setup incomplete until helper communication and
firewall configuration succeed.
### Bumps
- services: minor
- 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 -->
## 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 requires
`com.nvidia.nvpair.helper`. Filename-derived signing can strip the
`.helper` suffix, leaving registration enabled but XPC unreachable and
setup incomplete.
Embed the daemon's canonical `CFBundleIdentifier` in 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.main` required by ServiceManagement.
No Go service implementation changes.
## Validation
- Linux, Node.js 26.13.0, locked public dependencies: `make check` and
`npm --prefix desktop run dead-code:check` pass. Includes lint, all
TypeScript targets, build-script checks, service contracts, SPDX
headers, 297 Vitest tests, and 26 Node tests.
- Fifteen helper setup tests exercise the real setup wrapper and
configuration persistence with the native control tool mocked. Coverage
includes the missing daemon version on upgrade, successful replacement,
failed unregister/register, unreachable replacement, persisted retry
limits, interrupted repair, retry after an app-version change, approval,
fresh registration, healthy startup, version refresh, and firewall
failure/retry. The upgrade regression failed before the recovery change.
- `git diff --check` passes. Prior `sh -n` validation of both added
shell scripts passes; they are unchanged by the recovery update.
- Prior Apple Silicon macOS testing of the same native implementation:
`npm run build:helper:mac` and `npm run test:helper-signing:mac` pass
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.
- The full validator rejects the affected installed helper, missing
artifacts, and ad hoc signatures; it accepts the affected release's
correctly signed control tool and app.
- The maintainer [reported verification of the initial signing change
with an internally signed
build](#192 (comment)).
The startup recovery update still needs signed-build verification.
## 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.
- [ ] Verify an NVIDIA-signed candidate containing the startup recovery
update against the complete pinned requirements for every architecture.
- [ ] Upgrade in place from the affected release without unregistering
its helper or clearing user data. Verify one replacement attempt,
reachable XPC status and matching versions, successful firewall
configuration, and setup completion persisting across two
quits/relaunches and a reboot.
- [ ] Verify clean installation and approval-pending recovery with the
signed candidate.
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
- [x] I have read the [Contributing
Guidelines](https://github.com/NVIDIA/Personal-AI-Router/blob/develop/CONTRIBUTING.md).
- [x] Every commit is signed off (`git commit -s`), certifying the
Developer Certificate of Origin.
- [x] Relevant automated or manual checks cover the change, as recorded
above.
- [x] 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] I recorded validation commands and results above, including
outstanding checks.
- [x] I declared version bumps in the release-intent block. No Go
service implementation changes; all component bumps are `none`. Version
files and changelog are left to automation.
---------
Signed-off-by: Myles Shannon <github@mylesshannon.com>
Copy file name to clipboardExpand all lines: desktop/src/electron/config/ui-config.ts
+15-1Lines changed: 15 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -17,12 +17,15 @@ interface UiConfig {
17
17
modularLogLevel: ModularLogLevel
18
18
/** macOS only: the one-time privileged-helper setup (register the SMAppService daemon + configure the Application Firewall) has completed. Gates the first-run admin prompt; left false until the daemon is enabled and firewall configuration succeeds, so an approval-pending launch retries next time. */
19
19
macHelperSetupComplete: boolean
20
+
/** Last app version that attempted to replace an enabled but stale helper. */
21
+
macHelperRepairAttemptVersion: string
20
22
}
21
23
22
24
constDEFAULTS: UiConfig={
23
25
firstRun: true,
24
26
modularLogLevel: MODULAR_DEFAULT_LOG_LEVEL,
25
-
macHelperSetupComplete: false
27
+
macHelperSetupComplete: false,
28
+
macHelperRepairAttemptVersion: ''
26
29
}
27
30
28
31
letconfig: UiConfig={ ...DEFAULTS}
@@ -121,3 +124,14 @@ export function setMacHelperSetupComplete(value: boolean): void {
0 commit comments