Skip to content

Commit 6765d41

Browse files
authored
fix(mac): preserve privileged helper signing identity (#175) (#192)
<!-- 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>
1 parent 9ec1791 commit 6765d41

12 files changed

Lines changed: 599 additions & 21 deletions

File tree

‎desktop/docs/macos-privileged-helper.md‎

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,17 +45,27 @@ flowchart TD
4545
background helper.
4646
2. Call `macPrivilege.ensureConfigured(firstTime)`, which (no UI):
4747
- reads `nvpair-helper-ctl status`;
48-
- if the daemon version != app version (in-place Squirrel.Mac update),
49-
`uninstall` + `install` to refresh it, and force a firewall reconfigure;
48+
- if enabled but unreachable, or the daemon version differs from the app
49+
version, attempt `uninstall` + `install` once per app version, re-check
50+
`status`, and force a firewall reconfigure;
5051
- if not registered, `install` (which calls `SMAppService.daemon().register()`);
51-
- when `enabled`, run `configure-firewall` (no `--app-path`: the daemon
52+
- when `enabled` and reachable with no known version mismatch, run
53+
`configure-firewall` (no `--app-path`: the daemon
5254
derives the target bundle from the verified caller — see Security).
5355
3. On `requiresApproval`, the control tool calls
5456
`SMAppService.openSystemSettingsLoginItems()`; main surfaces guidance to
5557
enable the background item under **System Settings → General → Login Items &
5658
Extensions**, then relaunch.
5759
4. On success (`enabled` + firewall configured), set the one-time
58-
`macHelperSetupComplete` flag in `ui-config.ts`.
60+
`macHelperSetupComplete` flag in `ui-config.ts`. Clear it if setup fails or
61+
approval is pending so firewall configuration is retried on the next launch.
62+
63+
Before replacing a stale helper, PAIR persists `macHelperRepairAttemptVersion`
64+
and clears `macHelperSetupComplete` in `configs/ui-config.json`. This also covers
65+
upgrades from 1.0.0 where signature rejection prevents reading a daemon version.
66+
An interrupted or unsuccessful replacement is not repeated for the same app
67+
version. An enabled helper that remains unreachable or reports a different
68+
version leaves setup incomplete; registration alone does not imply success.
5969

6070
The firewall is reconfigured on first run, after a version refresh, and after a
6171
fresh registration (so a release that adds a networked binary still gets its
@@ -144,6 +154,103 @@ any non-zero `socketfilterfw` exit.
144154
- macOS packaging requires `swiftc`; build environments should verify it with
145155
`xcrun --find swiftc`.
146156

157+
The daemon embeds `native/PrivilegedHelper/Info.plist` in `__TEXT,__info_plist`
158+
in both architectures. Its `CFBundleIdentifier` supplies the signing identifier
159+
even when a signing service re-signs the enclosing app recursively. Without it,
160+
the filename-derived default can strip `.helper` and produce `com.nvidia.nvpair`.
161+
The control tool must continue using the enclosing app's `Bundle.main` for
162+
ServiceManagement; it does not embed a helper-specific Info.plist.
163+
164+
On macOS, check the built daemon's identifier through standalone and recursive
165+
ad hoc signing of disposable copies:
166+
167+
```bash
168+
npm run build:helper:mac
169+
npm run test:helper-signing:mac
170+
```
171+
172+
This regression test checks identifier stability in every architecture, not
173+
Developer ID trust. It does not run or register the copied daemon.
174+
175+
### Required release validation
176+
177+
The signing identifiers of the loose helper executables are part of the XPC
178+
authentication contract:
179+
180+
| Executable | Required signing identifier |
181+
| --- | --- |
182+
| `Contents/MacOS/com.nvidia.nvpair.helper` | `com.nvidia.nvpair.helper` |
183+
| `Contents/MacOS/nvpair-helper-ctl` | `nvpair-helper-ctl` |
184+
| Host application | `com.nvidia.nvpair` |
185+
186+
The release signer must assign each helper its own identifier, retain hardened
187+
runtime and NVIDIA's Developer ID Application signature, and sign the enclosing
188+
app after signing its nested executables. It must not overwrite the daemon's
189+
identifier with the host app's identifier during a later signing pass.
190+
Pass `--identifier com.nvidia.nvpair.helper` when signing the daemon and
191+
`--identifier nvpair-helper-ctl` when signing the control tool (or the signing
192+
service's equivalent). Do not rely on filename-derived defaults: `codesign`
193+
can strip `.helper` from the daemon's filename and produce the app's identifier.
194+
An explicit identifier in an earlier signature is insufficient if a later
195+
signing pass derives a new default.
196+
197+
After the **final** app signing pass, before notarization or creating release
198+
archives, the signed release pipeline must run this command from `desktop/`
199+
and fail the build if it exits nonzero:
200+
201+
```bash
202+
npm run verify:helper-signatures:mac -- "/path/to/NVIDIA PAIR.app"
203+
```
204+
205+
The command compiles a temporary validator with the same `HelperProtocol.swift`
206+
used by both helpers. It verifies each helper and the app against their complete
207+
pinned requirements with `codesign --verify --strict --all-architectures`.
208+
It does not register the helper, modify signatures, or change firewall rules.
209+
Unsigned public builds are expected to fail this release check.
210+
211+
Release maintainers must integrate this check into the signing pipeline after
212+
the final signing pass; adding the validator to the source tree does not wire
213+
it into release signing. The public build remains unsigned. Run the check again
214+
against the app extracted from each final DMG and ZIP before publishing.
215+
General app signature verification
216+
alone is insufficient: a valid NVIDIA signature can still have an identifier
217+
that the XPC peer rejects, as reported in
218+
[issue #175](https://github.com/NVIDIA/Personal-AI-Router/issues/175).
219+
220+
### Signed-build acceptance checks
221+
222+
Use a signed release candidate on a test Mac, including an upgrade from the
223+
affected release. Install in `/Applications`, launch PAIR as the normal user,
224+
and approve its background helper if prompted. Do not re-sign the installed
225+
app or alter the pinned requirements to make these checks pass.
226+
227+
For upgrade coverage, first confirm the affected release reports `enabled` but
228+
`reachable: false`, then replace the app in place without unregistering the old
229+
helper or clearing user data. On the updated app's first launch, confirm it
230+
re-registers the helper and records the new app version in
231+
`macHelperRepairAttemptVersion`. Follow the checks below after any required
232+
approval. If repair fails, verify setup remains incomplete and relaunching the
233+
same version does not trigger another unregister/register cycle.
234+
235+
1. Run the release validation command above against the installed app.
236+
2. Run `"/Applications/NVIDIA PAIR.app/Contents/MacOS/nvpair-helper-ctl" status`.
237+
Require `registration: "enabled"`, `reachable: true`, and a `daemonVersion`
238+
matching `ctlVersion` and the app version. The command's exit status alone
239+
does not prove reachability.
240+
3. Run `"/Applications/NVIDIA PAIR.app/Contents/MacOS/nvpair-helper-ctl" configure-firewall`.
241+
This changes firewall rules; require exit zero and JSON `ok: true`.
242+
Check each of the seven networked binaries listed above with
243+
`/usr/libexec/ApplicationFirewall/socketfilterfw --getappblocked <binary-path>`.
244+
4. Confirm normal app setup writes `macHelperSetupComplete: true` in the
245+
app's user-data `configs/ui-config.json`. Do not set the flag manually.
246+
5. Fully quit and reopen PAIR twice. Confirm the flag remains true, the helper
247+
stays reachable, and no helper-authorization dialog returns. Repeat after
248+
a reboot. Closing only the window leaves PAIR running in the tray.
249+
250+
Record the app/build version, macOS version, architecture, command results,
251+
and whether this was a clean install or an upgrade. A running launchd job or
252+
the Service page's Running state is not evidence of helper XPC reachability.
253+
147254
## Uninstall
148255

149256
`scripts/build/macos/uninstall.sh` (shipped at
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
4+
SPDX-License-Identifier: Apache-2.0
5+
-->
6+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
7+
<plist version="1.0">
8+
<dict>
9+
<key>CFBundleIdentifier</key>
10+
<string>com.nvidia.nvpair.helper</string>
11+
</dict>
12+
</plist>

‎desktop/native/Shared/HelperProtocol.swift‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ enum HelperConstants {
2020
static let teamIdentifier = "6KR3T733EC"
2121
static let appBundleIdentifier = "com.nvidia.nvpair"
2222

23-
/// Basenames `codesign` assigns as the signing identifier of the two loose
24-
/// helper Mach-O files (codesign defaults the identifier to the file name).
23+
/// Required signing identifiers of the two loose helper Mach-O files.
24+
/// Set these explicitly when signing: codesign's default can strip suffixes.
2525
static let ctlIdentifier = "nvpair-helper-ctl"
2626
static let daemonIdentifier = "com.nvidia.nvpair.helper"
2727

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
import Foundation
5+
6+
guard CommandLine.arguments.count == 2 else {
7+
fputs("usage: verify-helper-signatures <signed-app.app>\n", stderr)
8+
exit(2)
9+
}
10+
11+
let app = URL(fileURLWithPath: CommandLine.arguments[1]).standardizedFileURL
12+
let checks = [
13+
(
14+
app.appendingPathComponent("Contents/MacOS/\(HelperConstants.daemonIdentifier)"),
15+
HelperConstants.daemonCodeSigningRequirement
16+
),
17+
(
18+
app.appendingPathComponent("Contents/MacOS/\(HelperConstants.ctlIdentifier)"),
19+
HelperConstants.ctlCodeSigningRequirement
20+
),
21+
(app, HelperConstants.appCodeSigningRequirement)
22+
]
23+
24+
var failed = false
25+
for (target, requirement) in checks {
26+
let process = Process()
27+
process.executableURL = URL(fileURLWithPath: "/usr/bin/codesign")
28+
process.arguments = [
29+
"--verify", "--strict", "--all-architectures", "--verbose=2",
30+
"-R=\(requirement)", target.path
31+
]
32+
do {
33+
try process.run()
34+
process.waitUntilExit()
35+
if process.terminationStatus != 0 {
36+
fputs("Signing requirement failed: \(target.path)\n", stderr)
37+
failed = true
38+
}
39+
} catch {
40+
fputs("Cannot verify \(target.path): \(error.localizedDescription)\n", stderr)
41+
failed = true
42+
}
43+
}
44+
45+
exit(failed ? 1 : 0)

‎desktop/package.json‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
"build:electron:linux:x64": "npm run licenses && npm run build:modular-binaries:linux:x64 -- --force && npm run build:collect-logs:linux:x64 && electron-builder -c electron-builder.config.ts --linux --x64 --publish never",
6565
"build:electron:linux:arm64": "npm run licenses && npm run build:modular-binaries:linux:arm64 -- --force && npm run build:collect-logs:linux:arm64 && electron-builder -c electron-builder.config.ts --linux --arm64 --publish never",
6666
"build:helper:mac": "tsx scripts/build/macos/build-helper.ts",
67+
"test:helper-signing:mac": "sh scripts/build/macos/test-helper-signing.sh",
68+
"verify:helper-signatures:mac": "sh scripts/build/macos/verify-helper-signatures.sh",
6769
"build:electron:mac:x64": "npm run licenses && npm run build:modular-binaries:mac:x64 -- --force && npm run build:collect-logs:mac:x64 && npm run build:helper:mac && electron-builder -c electron-builder.config.ts --mac --x64 --publish never",
6870
"build:electron:mac:arm64": "npm run licenses && npm run build:modular-binaries:mac:arm64 -- --force && npm run build:collect-logs:mac:arm64 && npm run build:helper:mac && electron-builder -c electron-builder.config.ts --mac --arm64 --publish never",
6971
"build:win": "npm run build && npm run build:electron:win:x64 && npm run build:electron:win:arm64",

‎desktop/scripts/build/macos/build-helper.ts‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ function buildUniversal(
100100
sdkPath: string,
101101
outputName: string,
102102
sources: string[],
103-
frameworks: string[]
103+
frameworks: string[],
104+
linkerArgs: string[]
104105
): void {
105106
const archBinaries: string[] = []
106107
for (const arch of ARCHS) {
@@ -117,6 +118,7 @@ function buildUniversal(
117118
'-target',
118119
`${arch}-apple-macos${DEPLOYMENT_TARGET}`,
119120
...frameworkArgs,
121+
...linkerArgs,
120122
'-o',
121123
archOut,
122124
...sources
@@ -149,14 +151,25 @@ function main(): void {
149151
sdkPath,
150152
DAEMON_OUTPUT,
151153
[...shared, versionSource, ...swiftSources(DAEMON_DIR)],
152-
['Foundation', 'Security']
154+
['Foundation', 'Security'],
155+
[
156+
'-Xlinker',
157+
'-sectcreate',
158+
'-Xlinker',
159+
'__TEXT',
160+
'-Xlinker',
161+
'__info_plist',
162+
'-Xlinker',
163+
path.join(DAEMON_DIR, 'Info.plist')
164+
]
153165
)
154166
buildUniversal(
155167
swiftc,
156168
sdkPath,
157169
CTL_OUTPUT,
158170
[...shared, versionSource, ...swiftSources(CTL_DIR)],
159-
['Foundation', 'ServiceManagement']
171+
['Foundation', 'ServiceManagement'],
172+
[]
160173
)
161174

162175
console.log(`[build-helper] helper binaries ready in ${BUILD_DIR} (v${version})`)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
set -eu
6+
7+
DESKTOP_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)
8+
TEST_DIR=$(mktemp -d "${TMPDIR:-/tmp}/pair-helper-signing.XXXXXX")
9+
trap 'rm -rf "$TEST_DIR"' EXIT
10+
trap 'exit 1' HUP INT TERM
11+
12+
APP="$TEST_DIR/Fixture.app"
13+
DAEMON="$APP/Contents/MacOS/com.nvidia.nvpair.helper"
14+
mkdir -p "$APP/Contents/MacOS"
15+
cp "$DESKTOP_DIR/native/build/com.nvidia.nvpair.helper" "$DAEMON"
16+
cp /usr/bin/true "$APP/Contents/MacOS/Fixture"
17+
/usr/bin/plutil -create xml1 "$APP/Contents/Info.plist"
18+
/usr/bin/plutil -insert CFBundleIdentifier -string com.nvidia.nvpair "$APP/Contents/Info.plist"
19+
/usr/bin/plutil -insert CFBundleExecutable -string Fixture "$APP/Contents/Info.plist"
20+
/usr/bin/plutil -insert CFBundlePackageType -string APPL "$APP/Contents/Info.plist"
21+
22+
echo 'Checking daemon identifier after standalone signing'
23+
/usr/bin/codesign --force --sign - "$DAEMON"
24+
/usr/bin/codesign --verify --strict --all-architectures \
25+
'-R=identifier "com.nvidia.nvpair.helper"' "$DAEMON"
26+
27+
echo 'Checking daemon identifier after recursive bundle signing'
28+
/usr/bin/codesign --force --deep --sign - "$APP"
29+
/usr/bin/codesign --verify --deep --strict "$APP"
30+
/usr/bin/codesign --verify --strict --all-architectures \
31+
'-R=identifier "com.nvidia.nvpair.helper"' "$DAEMON"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/sh
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
set -eu
6+
7+
if [ "$#" -ne 1 ]; then
8+
echo "usage: $0 <signed-app.app>" >&2
9+
exit 2
10+
fi
11+
12+
DESKTOP_DIR=$(CDPATH= cd -- "$(dirname -- "$0")/../../.." && pwd)
13+
VERIFY_DIR=$(mktemp -d "${TMPDIR:-/tmp}/pair-helper-signatures.XXXXXX")
14+
trap 'rm -rf "$VERIFY_DIR"' EXIT
15+
trap 'exit 1' HUP INT TERM
16+
17+
/usr/bin/xcrun --sdk macosx swiftc \
18+
-module-cache-path "$VERIFY_DIR/module-cache" \
19+
"$DESKTOP_DIR/native/Shared/HelperProtocol.swift" \
20+
"$DESKTOP_DIR/native/VerifyHelperSignatures/main.swift" \
21+
-o "$VERIFY_DIR/verify-helper-signatures"
22+
23+
"$VERIFY_DIR/verify-helper-signatures" "$1"

‎desktop/src/electron/config/ui-config.ts‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ interface UiConfig {
1717
modularLogLevel: ModularLogLevel
1818
/** 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. */
1919
macHelperSetupComplete: boolean
20+
/** Last app version that attempted to replace an enabled but stale helper. */
21+
macHelperRepairAttemptVersion: string
2022
}
2123

2224
const DEFAULTS: UiConfig = {
2325
firstRun: true,
2426
modularLogLevel: MODULAR_DEFAULT_LOG_LEVEL,
25-
macHelperSetupComplete: false
27+
macHelperSetupComplete: false,
28+
macHelperRepairAttemptVersion: ''
2629
}
2730

2831
let config: UiConfig = { ...DEFAULTS }
@@ -121,3 +124,14 @@ export function setMacHelperSetupComplete(value: boolean): void {
121124
config.macHelperSetupComplete = value
122125
save()
123126
}
127+
128+
export function getMacHelperRepairAttemptVersion(): string {
129+
return config.macHelperRepairAttemptVersion
130+
}
131+
132+
/** Record the attempt and invalidate completed setup before replacing the helper. */
133+
export function setMacHelperRepairAttemptVersion(value: string): void {
134+
config.macHelperRepairAttemptVersion = value
135+
config.macHelperSetupComplete = false
136+
save()
137+
}

‎desktop/src/electron/main.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,9 @@ if (!gotTheLock || exitRequested) {
172172

173173
const result = await macPrivilege.ensureConfigured(firstTime)
174174
if (!result.supported) return
175+
setMacHelperSetupComplete(
176+
result.registration === 'enabled' && result.firewallConfigured
177+
)
175178

176179
if (result.registration === 'requiresApproval') {
177180
if (firstTime) {
@@ -190,7 +193,6 @@ if (!gotTheLock || exitRequested) {
190193
}
191194

192195
if (result.registration === 'enabled' && result.firewallConfigured) {
193-
setMacHelperSetupComplete(true)
194196
log.info({ sublevel: 'mac-helper', message: 'Privileged helper configured' })
195197
} else {
196198
log.error({
@@ -199,6 +201,7 @@ if (!gotTheLock || exitRequested) {
199201
})
200202
}
201203
} catch (err) {
204+
setMacHelperSetupComplete(false)
202205
log.error({ sublevel: 'mac-helper', message: `Privileged setup error: ${err}` })
203206
}
204207
}

0 commit comments

Comments
 (0)