Skip to content

Development

Rod Christiansen edited this page Oct 8, 2026 · 3 revisions

Development

Getting the package building and running on your own Mac.

Setup

git clone https://github.com/reportmate/reportmate-client-mac.git
cd reportmate-client-mac
brew install osquery bash

osquery is optional for compiling but necessary for realistic collection. Homebrew's bash is required by build.sh.

Build and test

A fresh clone does not compile with plain swift build: the collector calls ModuleVersions, which lives in Sources/Generated/ModuleVersions.swift, and that directory is gitignored. Run build.sh once without packaging. It generates the file from git history and leaves a placeholder behind when it exits, so later swift build and swift test runs work.

./build.sh --skip-pkg --skip-zip --skip-dmg
swift build
swift test
swift build --configuration release

Three test targets run under swift test:

Target Covers
ReportMateTests Configuration precedence, EDID decoding, DNS-correlated address inventory, osquery binary resolution, the process launch guard, and transmission retry
ReportMateXPCTests HelperPolicy (client requirement, allowed arguments, writable keys, trusted paths) and log-line level classification
ReportMateLoggingTests The rolling log file and the launchd capture trimmer

The module processors as a whole are exercised by running the binary against a real machine.

Running locally

The collector needs root, and the modules read real system state, so there is no useful unprivileged mode.

sudo .build/release/managedreportsrunner --run-module system -vv

Collect without transmitting while you are iterating, then read the cache:

sudo .build/release/managedreportsrunner --collect-only -vvv

-vvv prints the entire payload to the console between === COLLECTED DATA PAYLOAD === markers, which is usually faster than digging through the cache directory.

Point a dev build at a dev API. Environment variables rank below the system plist and any profile, so this only takes effect where neither sets the key:

sudo REPORTMATE_API_URL="https://reportmate.example.com" REPORTMATE_PASSPHRASE="dev" .build/release/managedreportsrunner --run-modules inventory,system

For a one-off override that beats everything, use --api-url instead.

sudo .build/release/managedreportsrunner --api-url "https://reportmate.example.com" --run-modules inventory,system

Install a local build over the top for end-to-end testing. build.sh calls sudo installer itself and needs a signing identity in .env:

./build.sh --sign --install

Technology constraints

The repo's AGENTS.md sets a hard rule: no Python. Data collection is Swift, osquery, the macadmins osquery extension, and bash. Use jq for JSON processing in shell fallbacks, called through BashService.

Adding a module

  1. Add a processor under Sources/DataCollection/Modules/, subclassing BaseModuleProcessor and implementing collectData().
  2. Use executeWithFallback(osquery:bash:) so the module still reports on a Mac without osquery. Return a BaseModuleData(moduleId:data:), or a Codable model that will be encoded to a dictionary.
  3. Register the name in createProcessor(for:config:usageService:) in Sources/ReportMateClient.swift. An unregistered name logs Unknown module: <name> and is skipped.
  4. Add a matching slot to UnifiedDevicePayload in Sources/Models/DeviceModels.swift, or the module's data will not reach the API.
  5. Add it to the default EnabledModules in ReportMateConfiguration, to the appropriate LaunchDaemon's --run-modules list in build.sh, to the MODULE_FILES map in build.sh so it gets a per-module version, and to ModuleDefinition so the GUI lists it.

Keep the output shape aligned with the Windows client where the dashboard reads both — the payload deliberately mirrors reportmate-client-win.

Code style tools

make format
make lint

Both are no-ops with a message if swift-format or swiftlint is not installed.

Worktrees

Development worktrees belong inside the repo at ./.worktrees/<name>, never as sibling directories. /.worktrees/ is gitignored.

What CI checks

A push or PR to main touching Sources/, Tests/, Package.swift, build.sh or the CI workflow runs a release compile on macos-26 with Xcode 26, compiles the app icon, and runs swift test. It does not package. Tagging triggers the release workflow, which builds and publishes an unsigned pkg; see Building and Releasing.

Clone this wiki locally