Install macOS helper from PKG for XPC enroll
Browser enrollment used osascript on every elevate. Ship a signed privileged helper installed at PKG time so probo:// can enroll over XPC with no second admin prompt. Add make install/uninstall/clean for local PKG test loops, and show alerts only on failure. Mirror the Go lint path for the macOS SPM package: Make targets, root configs, and a Linux CI job. Keep checks syntax-only so they do not need a macOS SDK. Format the existing sources so the new gates start clean. Signed-off-by: Ludovic Vielle <ludovic@probo.com>
This commit is contained in:
@@ -14,8 +14,10 @@ The project uses a `GNUmakefile` at the root. Builds run with `--jobs=$(nproc)`
|
||||
| `make test-short` | Short tests only |
|
||||
| `make test-bench` | Run benchmarks |
|
||||
| `make test-e2e` | Run console end-to-end tests (requires `bin/probod`) |
|
||||
| `make lint` | Run all linters: `vet` + `go-fmt` + `go-fix` + `go-lint` + `lint-js` |
|
||||
| `make fmt` | Format Go code (`go fmt ./...`) |
|
||||
| `make lint` | Run Go + JS linters: `vet` + `go-fmt` + `go-fix` + `go-lint` + `lint-js` |
|
||||
| `make lint-swift` | Opt-in: lint Swift enroll-ui (`swift-fmt` + `swift-lint`; needs Swift + SwiftLint; CI runs this on Linux) |
|
||||
| `make fmt` | Format Go code |
|
||||
| `make fmt-swift` | Opt-in: format Swift enroll-ui (`swift format` + SwiftLint `--fix`; needs Swift) |
|
||||
| `make clean` | Remove all build artifacts, `node_modules`, generated files, and coverage |
|
||||
| `make help` | List targets with `##` doc comments |
|
||||
|
||||
@@ -81,3 +83,6 @@ Individual codegen is driven by `go generate`:
|
||||
| `GOOS` | (host) | Cross-compile target OS |
|
||||
| `TEST_FLAGS` | `-race -cover -coverprofile=coverage.out` | Extra flags passed to `go test` |
|
||||
| `DOCKER_BUILD_FLAGS` | (empty) | Extra flags for `docker build` |
|
||||
| `SWIFTLINTCMD` | `swiftlint` | SwiftLint binary |
|
||||
| `SWIFTCMD` | `swift` | Swift toolchain binary (`swift format`) |
|
||||
| `SWIFT_ENROLL_UI` | `cmd/probo-agent/installer/macos/enroll-ui` | Path to the Swift SPM package |
|
||||
|
||||
@@ -28,9 +28,9 @@ If empty or non-user-facing only, do not release this track.
|
||||
make bin/probo-agent
|
||||
```
|
||||
|
||||
On macOS and Windows hosts, `make` enables CGO automatically so the
|
||||
menu bar / tray enrollment helper is included. Linux and FreeBSD builds
|
||||
stay pure Go (no tray).
|
||||
On macOS hosts, `make` enables CGO so the menu bar enrollment helper
|
||||
is included. Windows tray support is pure Go (`CGO_ENABLED=0`). Linux
|
||||
and FreeBSD builds stay pure Go (no tray).
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -45,27 +45,34 @@ verifies the cosign bundle before installing.
|
||||
The menu bar / tray enrollment flow is **macOS and Windows only**.
|
||||
Linux and FreeBSD use `probo-agent install --server …
|
||||
--enrollment-token …` from the shell, or the curl-to-sh installer
|
||||
documented below. Windows release binaries are
|
||||
cross-compiled from Linux with MinGW (CGO). macOS release binaries and
|
||||
the `.pkg` are built on macOS with `CGO_ENABLED=1`.
|
||||
documented below. Windows release binaries are cross-compiled from
|
||||
Linux with `CGO_ENABLED=0` (tray is pure Go). macOS release binaries
|
||||
and the `.pkg` are built on macOS with `CGO_ENABLED=1`.
|
||||
|
||||
### macOS `.pkg` (MDM / GUI install)
|
||||
|
||||
Release and local builds use
|
||||
`cmd/probo-agent/installer/macos/build.sh` (requires macOS, a
|
||||
pre-built binary — preferably universal via `lipo` — and the Swift
|
||||
toolchain). The script compiles `Probo Agent.app` (the headless
|
||||
`probo://` URL handler) from
|
||||
`cmd/probo-agent/installer/macos/enroll-ui/`, signs the binary and app
|
||||
when `CODESIGN_IDENTITY` is set, signs the product with
|
||||
`INSTALLER_IDENTITY`, and notarizes/staples when
|
||||
`NOTARYTOOL_KEYCHAIN_PROFILE` is set, or when `APPLE_ID`,
|
||||
`APPLE_ID_PASSWORD`, and `APPLE_TEAM_ID` are set (password is stored
|
||||
into a keychain profile; submits use `--keychain-profile` so the secret
|
||||
is not on `notarytool submit` argv).
|
||||
toolchain). **Signing is mandatory:** `CODESIGN_IDENTITY` and
|
||||
`APPLE_TEAM_ID` must be set. The script compiles `Probo Agent.app`
|
||||
(the headless `probo://` URL handler + privileged helper) from
|
||||
`cmd/probo-agent/installer/macos/enroll-ui/`, signs the binary and
|
||||
app, optionally signs the product with `INSTALLER_IDENTITY`, and
|
||||
notarizes/staples when `APPLE_ID` and `APPLE_ID_PASSWORD` are set
|
||||
(password is stored into a keychain profile; submits use
|
||||
`--keychain-profile` so the secret is not on `notarytool submit` argv).
|
||||
|
||||
There is no unsigned PKG path and no osascript elevation fallback.
|
||||
Local testing of browser enrollment requires a Developer ID–signed
|
||||
build. CLI enrollment without the app uses `sudo probo-agent install`.
|
||||
|
||||
```shell
|
||||
# Local unsigned universal pkg (example)
|
||||
# Local signed pkg (example)
|
||||
export CODESIGN_IDENTITY="Developer ID Application: Probo Inc (TEAMID)"
|
||||
export INSTALLER_IDENTITY="Developer ID Installer: Probo Inc (TEAMID)"
|
||||
export APPLE_TEAM_ID="TEAMID"
|
||||
|
||||
GOOS=darwin GOARCH=arm64 CGO_ENABLED=1 go build -o dist/probo-agent_arm64 ./cmd/probo-agent
|
||||
GOOS=darwin GOARCH=amd64 CGO_ENABLED=1 go build -o dist/probo-agent_amd64 ./cmd/probo-agent
|
||||
lipo -create dist/probo-agent_arm64 dist/probo-agent_amd64 -output dist/probo-agent_universal
|
||||
@@ -75,11 +82,29 @@ cmd/probo-agent/installer/macos/build.sh \
|
||||
--version "$(cat cmd/probo-agent/VERSION)"
|
||||
```
|
||||
|
||||
PKG postinstall always installs the global tray LaunchAgent and
|
||||
registers `probo://`. The LaunchDaemon for `probo-agent run` is created
|
||||
only after enrollment (`probo-agent install`, deep link, or MDM
|
||||
PKG postinstall always installs the global tray LaunchAgent, registers
|
||||
`probo://`, and installs the privileged helper
|
||||
(`com.probo.agent.helper`) under `/Library/PrivilegedHelperTools` as
|
||||
root. The only admin authentication is the normal macOS Installer
|
||||
prompt for the PKG itself. The LaunchDaemon for `probo-agent run` is
|
||||
created only after enrollment (`probo-agent install`, deep link, or MDM
|
||||
`/tmp/probo-agent.conf`).
|
||||
|
||||
Browser enrollment uses `Probo Agent.app` over XPC to the
|
||||
PKG-installed helper — no SMJobBless and no admin prompt on the enroll
|
||||
path. A missing or dead helper surfaces an error asking to reinstall
|
||||
the package.
|
||||
|
||||
Manual QA checklist (macOS PKG):
|
||||
|
||||
1. Fresh signed PKG: Installer may ask for admin once; deep link enrolls with no further prompt.
|
||||
2. Repeat deep link on an enrolled device: no prompt, immediate success.
|
||||
3. After `sudo make -C cmd/probo-agent uninstall`, deep link fails with a clear “reinstall package” error (no osascript).
|
||||
4. `sudo make -C cmd/probo-agent uninstall` removes daemon, tray, helper, app, and state.
|
||||
5. MDM `/tmp/probo-agent.conf` postinstall still enrolls without a browser prompt.
|
||||
6. Notarized PKG passes Gatekeeper; `codesign --verify --deep` succeeds on the app bundle.
|
||||
7. Unsigned `build-app.sh` / `build.sh` exits with an error requiring `CODESIGN_IDENTITY`.
|
||||
|
||||
### Apple signing secrets (GitHub)
|
||||
|
||||
The `build-macos` job in `release-probo-agent.yaml` expects the same
|
||||
@@ -97,24 +122,23 @@ the probo GitHub repository (or org) before tagging a release:
|
||||
| `APPLE_ID_PASSWORD` | App-specific password (stored into a keychain profile; not passed to `submit`) |
|
||||
| `APPLE_TEAM_ID` | 10-character Team ID |
|
||||
|
||||
Local notarization can reuse a pre-stored profile instead of putting the
|
||||
password in the environment:
|
||||
Local notarization uses the same env vars as CI:
|
||||
|
||||
```shell
|
||||
xcrun notarytool store-credentials probo-agent-notary \
|
||||
--apple-id "$APPLE_ID" --team-id "$APPLE_TEAM_ID"
|
||||
# prompts for the app-specific password once
|
||||
export NOTARYTOOL_KEYCHAIN_PROFILE=probo-agent-notary
|
||||
export APPLE_ID="you@example.com"
|
||||
export APPLE_ID_PASSWORD="app-specific-password"
|
||||
# optional: NOTARYTOOL_KEYCHAIN_PROFILE=probo-agent-notary (default)
|
||||
```
|
||||
|
||||
Windows enrollment is browser-driven: the console issues a
|
||||
`probo://enroll?server=...&token=...` deep link handled by
|
||||
`probo-agent enroll-url`. After install, register the protocol for the
|
||||
`Probo Agent.app` on macOS (PKG-installed helper + XPC) or
|
||||
`probo-agent enroll-url` on Windows. After install, register the protocol for the
|
||||
current user with
|
||||
`cmd/probo-agent/installer/windows/register-protocol.ps1` (per-user
|
||||
`HKCU` handler pointing at `probo-agent.exe`). The system tray helper
|
||||
(`probo-agent tray`, CGO build on local Windows hosts) shows enrollment
|
||||
status; enrollment itself happens in the browser.
|
||||
(`probo-agent tray`) shows enrollment status; enrollment itself happens
|
||||
in the browser.
|
||||
|
||||
Region labels and console URLs for the macOS installer HTML live in
|
||||
`cmd/probo-agent/installer/regions.json`. A Go test keeps US/EU URLs in
|
||||
@@ -165,34 +189,32 @@ Environment variables:
|
||||
|
||||
Never pass the enrollment token in the curl URL.
|
||||
|
||||
## Local dev install
|
||||
## Local install (macOS PKG)
|
||||
|
||||
Build, package, and install a dev binary with `sudo`. Agent state is stored
|
||||
under `~/.local/share/probo-agent-dev` (`--dir`); release archives are staged
|
||||
under `~/.cache/probo-agent-dev` so the two trees do not overlap.
|
||||
Primary loop for testing browser enrollment (app + privileged helper):
|
||||
|
||||
```shell
|
||||
make -C cmd/probo-agent install \
|
||||
export CODESIGN_IDENTITY="Developer ID Application: … (TEAMID)"
|
||||
export INSTALLER_IDENTITY="Developer ID Installer: … (TEAMID)" # optional
|
||||
export APPLE_TEAM_ID="TEAMID"
|
||||
|
||||
make -C cmd/probo-agent install # uninstall leftovers → build PKG → installer
|
||||
make -C cmd/probo-agent uninstall # full system teardown (idempotent)
|
||||
make -C cmd/probo-agent clean # uninstall + wipe dist/ caches / enroll-ui/.build
|
||||
```
|
||||
|
||||
`install` always runs `uninstall` first so previous helpers, apps, and
|
||||
Launch Services registrations cannot shadow the new build. Signing env
|
||||
vars are required for `pkg` / `install` on Darwin.
|
||||
|
||||
### CLI-only install (no app / helper)
|
||||
|
||||
Binary-only path via `installer/install.sh` (any Unix). State under
|
||||
`~/.local/share/probo-agent-dev`; staging under `~/.cache/probo-agent-dev`.
|
||||
|
||||
```shell
|
||||
make -C cmd/probo-agent install-cli \
|
||||
PROBO_SERVER_URL=https://us.probo.com \
|
||||
PROBO_ENROLLMENT_TOKEN='…'
|
||||
```
|
||||
|
||||
This does not compile Go in `cmd/probo-agent`; it reuses `bin/probo-agent` from
|
||||
the root `GNUmakefile` (via `make bin/probo-agent`, invoked automatically when
|
||||
needed), stages it into a local release archive, then runs `installer/install.sh`
|
||||
against that `file://` archive with `PROBO_AGENT_RELEASE_TAG=probo-agent/dev`,
|
||||
skips checksum verification, installs the binary to `/usr/local/bin/probo-agent`,
|
||||
and passes `--skip-service` and `--dir ~/.local/share/probo-agent-dev` by default
|
||||
(`INSTALL_ARGS` overrides).
|
||||
|
||||
Run the agent in the foreground against the same dev state directory:
|
||||
|
||||
```shell
|
||||
make -C cmd/probo-agent run
|
||||
```
|
||||
|
||||
Remove dev artifacts:
|
||||
|
||||
```shell
|
||||
make -C cmd/probo-agent clean
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user