Problem
Running vigilante setup -d after installing via Homebrew Cask fails with:
error: macOS rejected daemon binary assessed_path="/opt/homebrew/Caskroom/vigilante/1.0.2/vigilante" invoked_path="/opt/homebrew/bin/vigilante" removed_xattrs=com.apple.provenance: spctl [--assess --type execute -vv /opt/homebrew/Caskroom/vigilante/1.0.2/vigilante]: exit status 3
Root Cause
prepareMacOSDaemonBinary() in internal/service/service.go runs spctl --assess --type execute -vv after ad-hoc signing the binary. This check enforces Apple's notarization policy — ad-hoc signed binaries (codesign --force --sign -) will always fail spctl --assess on modern macOS. Only binaries signed with an Apple Developer ID certificate and submitted to Apple's notary service pass this check.
Homebrew itself doesn't require notarization — it handles Gatekeeper by removing quarantine xattrs. The spctl check is overly strict for Homebrew-distributed binaries.
Fix
-
Remove the spctl --assess check from prepareMacOSDaemonBinary(). The remaining flow (remove xattrs → ad-hoc codesign) is sufficient for launchd to load the daemon.
-
Fix pre-existing test bug: In TestPrepareMacOSDaemonBinaryUsesResolvedPath and the spctl failure test, caskRoot is computed before filepath.EvalSymlinks resolves the path. On macOS, t.TempDir() returns /var/folders/... but EvalSymlinks resolves it to /private/var/folders/..., causing the test's mock output map keys to not match the actual commands. caskRoot must be computed after EvalSymlinks.
Optional Future Enhancement
For releases that pass spctl natively (no xattr removal needed), the project would need:
- An Apple Developer ID ($99/year)
- Sign binaries with
codesign --sign "Developer ID Application: ..." in the release workflow
- Notarize via
notarytool in GitHub Actions
- Staple the notarization ticket with
xcrun stapler staple
This is optional — removing the spctl check is the standard approach for CLI tools distributed via Homebrew.
Problem
Running
vigilante setup -dafter installing via Homebrew Cask fails with:Root Cause
prepareMacOSDaemonBinary()ininternal/service/service.gorunsspctl --assess --type execute -vvafter ad-hoc signing the binary. This check enforces Apple's notarization policy — ad-hoc signed binaries (codesign --force --sign -) will always failspctl --assesson modern macOS. Only binaries signed with an Apple Developer ID certificate and submitted to Apple's notary service pass this check.Homebrew itself doesn't require notarization — it handles Gatekeeper by removing quarantine xattrs. The
spctlcheck is overly strict for Homebrew-distributed binaries.Fix
Remove the
spctl --assesscheck fromprepareMacOSDaemonBinary(). The remaining flow (remove xattrs → ad-hoc codesign) is sufficient for launchd to load the daemon.Fix pre-existing test bug: In
TestPrepareMacOSDaemonBinaryUsesResolvedPathand the spctl failure test,caskRootis computed beforefilepath.EvalSymlinksresolves the path. On macOS,t.TempDir()returns/var/folders/...but EvalSymlinks resolves it to/private/var/folders/..., causing the test's mock output map keys to not match the actual commands.caskRootmust be computed after EvalSymlinks.Optional Future Enhancement
For releases that pass
spctlnatively (no xattr removal needed), the project would need:codesign --sign "Developer ID Application: ..."in the release workflownotarytoolin GitHub Actionsxcrun stapler stapleThis is optional — removing the
spctlcheck is the standard approach for CLI tools distributed via Homebrew.