This is developer documentation for the Rust code in controller/. It builds the command-line controller that ships as:
dist/PolicyWitness.app/Contents/MacOS/policy-witness
PolicyWitness is specimen-first. The launcher’s job is to drive the embedded runner service (PWRunner.xpc) and to print a stable, machine-readable JSON witness for each run.
For the Swift runner implementation details, see runner/README.md.
Core controller modules:
controller/src/main.rs— entry point and module wiringcontroller/src/cli.rs— CLI usage text + top-level dispatchcontroller/src/run_flow.rs— run orchestration and JSON envelope assemblycontroller/src/runner_select.rs— runner selection + provenancecontroller/src/runner_client.rs— wrapper aroundpw-runner-clientcontroller/src/sandbox_log.rs— unified-log capture mapping for sandbox denialscontroller/src/sonoma_cross_check.rs—sb_api_validatorcross-check flowcontroller/src/runner_commands.rs— external runner install/list/verify/remove/refresh
Support modules:
controller/src/app_layout.rs— app bundle layout + embedded tool resolutioncontroller/src/plist.rs— PlistBuddy helpers for Info.plist lookupscontroller/src/bundle.rs— bundle metadata reader for external runnerscontroller/src/request_patch.rs— request JSON injection helperscontroller/src/policy_preflight.rs— SBPL preflight runner wiringcontroller/src/utils.rs— shared time + output helperscontroller/src/evidence.rs— evidence manifest parsing + verificationcontroller/src/json_contract.rs— JSON envelope rendering with sorted keyscontroller/src/runner_manager.rs— external runner registry + launchd wiring
Standalone helper tools (embedded into the .app):
controller/src/bin/sandbox-log-observer.rs→dist/PolicyWitness.app/Contents/MacOS/sandbox-log-observer- Captures unified-log sandbox deny lines by PID + process name
controller/src/bin/sbpl-preflight.rs→dist/PolicyWitness.app/Contents/MacOS/sbpl-preflight- Compiles SBPL policies and reports compiler errors before the runner launches
controller/tools/sb_api_validator/sb_api_validator→dist/PolicyWitness.app/Contents/MacOS/sb_api_validator- Direct
sandbox_checkcross-check helper (used by--sonoma-cross-check)
- Direct
The launcher intentionally exposes a minimal surface:
policy-witness run <request.json> [--timeout-ms <n>] [--log-last <dur>] [--runner-mode <standard|debuggable|byoxpc|machme>] [--instrumentation <json|@path>] [--sonoma-cross-check]
policy-witness runner <command> [options]
Runs a single runner evaluation against the selected runner service:
- Reads a request JSON file (runner request schema) that contains:
- a sandbox policy (
sbplsource), - and a probe plan (steps with
sandbox_check+ an attempted operation).
- a sandbox policy (
- Starts a fresh runner instance, applies the policy exactly once, executes the probe plan, and returns the runner’s structured JSON result.
- Captures supporting evidence (best-effort) using
sandbox-log-observerand attaches it to the output. - If
--sonoma-cross-checkis provided, the controller runs the embeddedsb_api_validatoragainst the runner PID while it is paused post-sandbox (a post-sandboxdebug_waitport is injected to hold the runner open). - Prints a single JSON envelope to stdout (no output directories; stdout is the artifact).
- Emits
data.runner_provenanceanddata.app_provenanceto keep results auditable. - If
--instrumentationis provided, the controller injects the instrumentation object into the request JSON (without modifying the original file).
Exit codes:
0:result.ok=true1:result.ok=false2: usage / tool error (prints a JSON error envelope)
The controller prints one JSON envelope to stdout (kind="run"). It contains:
data.runner_result: the runner's JSON (if parseable)data.runner_client: argv + stdout/stderr + timing for the client calldata.policy_preflight: SBPL compile report fromsbpl-preflight(best-effort)data.runner_startup_diagnostics: extra context when XPC startup failsdata.sandbox_log_capture: optional unified-log evidence (best-effort)data.sonoma_cross_check: optionalsandbox_checkcross-check report (best-effort)data.runner_provenance: runner identity + entitlements metadatadata.app_provenance: embedded app evidence metadata (and optional verification)
data.sandbox_log_capture.capture_status values:
captured: observer succeeded, no error reportedblocked: unified log access blocked (seeblocked_reason)error: observer returned an error or non-zero exitparse_error: observer stdout was not valid JSONrequested_unavailable: observer could not be executed
Optional:
PW_VERIFY_EVIDENCE=1runs a manifest hash verification pass and includes adata.app_provenance.evidence_verifyreport in the output.
run can target specific runner modes by adding one of the following to the request:
runner: { mode, id, service, required_entitlements }(preferred)- Legacy top-level fields:
runner_id,runner_service,required_entitlements,runner_mode
If required_entitlements is present, the controller enforces a superset
check against the runner’s recorded entitlements before dispatch.
Built-in modes are standard (default) and debuggable.
If runner.mode is present and an external runner is selected, it must match the registry kind (byoxpc or machme).
These commands manage external runners signed with user entitlements:
policy-witness runner install --bundle <path> [--kind byoxpc|machme] [--service-name <name>] [--scope user|system]
[--identity <codesign-id>] [--entitlements <plist>]
[--executable <path>] [--bundle-id <id>] [--allow-adhoc]
[--env KEY=VALUE]
[--skip-bootstrap]
policy-witness runner list
policy-witness runner status --id <runner-id> | --service-name <name>
policy-witness runner verify --id <runner-id> | --service-name <name> [--timeout-ms <n>]
policy-witness runner remove --id <runner-id> | --service-name <name> [--skip-bootout]
policy-witness runner refresh
Install writes a launchd plist, bootstraps the service, and records runner
metadata (entitlements + signature) in the local registry. The registry lives
under ~/Library/Application Support/PolicyWitness/runners.json.
Notes:
- BYOXPC runners require
CFBundlePackageType=XPC!and useCFBundleIdentifieras the service name. - MachMe runners accept
--service-nameoverrides and use Mach services for NSXPC.
The launcher does not speak NSXPC directly. It drives the Swift client helper embedded in the app bundle:
dist/PolicyWitness.app/Contents/MacOS/pw-runner-client
The Swift client is responsible for NSXPCConnection wiring; the Rust launcher owns run orchestration and evidence capture.