Skip to content

Remove spctl --assess check that blocks Homebrew Cask daemon setup #244

@nicobistolfi

Description

@nicobistolfi

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

  1. Remove the spctl --assess check from prepareMacOSDaemonBinary(). The remaining flow (remove xattrs → ad-hoc codesign) is sufficient for launchd to load the daemon.

  2. 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:

  1. An Apple Developer ID ($99/year)
  2. Sign binaries with codesign --sign "Developer ID Application: ..." in the release workflow
  3. Notarize via notarytool in GitHub Actions
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions