Xcode — the app
1
Add the Sparkle dependency
File → Add Package Dependencies… →
https://github.com/sparkle-project/Sparkle, Up to Next Major from
2.9.1 — that’s what the committed project pins. Tick the Sparkle
product on the privacycommand target.2
Set the app's signing team
privacycommand → Signing & Capabilities → Team. A personal team is fine
for development; distribution needs a Developer ID.
3
Match the helper's team to the app's
privacycommandHelper → Signing & Capabilities → Team, set to the same
team.Two different failures hang off getting this wrong, and only one of them is
loud. If both targets are team-signed but with different teams, the
helper’s
CodeSignValidator refuses the XPC connection at runtime and every
privileged feature stops working — obvious, and easy to diagnose. If the
helper ends up with no team at all — unsigned, ad-hoc, or
“Sign to Run Locally” — the validator has nothing to compare against and
accepts every caller instead, silently. Your build works, and the root
helper is reachable by any process running as you. See
How it protects itself.4
Build
⌘B to build, ⌘R to run, ⌘U for the app test bundle.
SwiftPM — the analyzer and CLI
privacycommandCore and auditctl. The SwiftUI app
is not built this way — it exists only in the Xcode project.
Use this loop when you’re working on detectors. It’s much faster than a GUI
build, and auditctl against a known-good system app is the quickest way to
see whether a change did what you meant.
How one source tree compiles both ways
App sources use a conditional import:SWIFT_PACKAGE is defined and Core is a separate module. Under
Xcode, everything is one app module and the import is skipped. Test files do the
same with @testable import.
If you add a file that references Core, keep this pattern or the other build
path breaks.
Verifying the build
privacycommandHelper is missing from Contents/MacOS, the embed phase
didn’t run and nothing privileged will work.