# auditctl (CLI)
Source: https://docs.privacycommand.privacykey.org/auditctl

The same analyzer, on the command line — for scripting, CI, and previewing updates before you take them.

`auditctl` is a small CLI over the same analyzer the app uses. Useful for
scripting, for CI, and for the one thing the GUI can't easily do: checking an
update *before* you install it.

## Building it

`auditctl` is not shipped in the DMG. Build it from a checkout:

```bash
cd privacycommand
swift build -c release
swift run -c release auditctl --help
```

## Usage

```
auditctl                       interactive browser (on a terminal)
auditctl <target>              static audit of one app (name or path)
auditctl audit <target>        same, explicit
auditctl -i, interactive       force the interactive browser
auditctl preview [options]     preview apps before you update them
```

`<target>` is either a path to a `.app` or a substring of an app name, so
`auditctl fire` will find Firefox.

Run bare on a terminal, `auditctl` opens an interactive browser. With stdin or
stdout redirected it prints usage instead, which keeps it safe in CI.

### Auditing one app

```bash
swift run -c release auditctl /Applications/SomeApp.app
```

Pretty-printed by default, non-zero exit on parse failure. Useful options:

| Flag | Effect |
|---|---|
| `--json` | Machine-readable output |
| `--short` | Condensed summary |
| `--tree` | Tree view of the bundle |
| `--warnings` | Findings only |
| `--warn-exit` | Non-zero exit when warnings are present — the one you want in CI |
| `--no-color` | Plain output. Setting `NO_COLOR` in the environment does the same |
| `--verbose`, `--exact` | As they sound |

There is no risk-tier filter here — `--min-tier` belongs to `preview`, and
`auditctl` exits 2 on any flag it doesn't recognise.

## Previewing updates

`preview` is the interesting subcommand. With no arguments it looks at your
**outdated Homebrew casks** and audits what you're about to receive:

```bash
swift run -c release auditctl preview
swift run -c release auditctl preview --all-apps --only-noteworthy --min-tier high
swift run -c release auditctl preview --json
```

`brew` is looked for at `$HOMEBREW_PREFIX/bin/brew` if that variable is set,
then `/opt/homebrew/bin/brew` and `/usr/local/bin/brew`. If none of them is
executable, `preview` exits 2 and says so — `--all-apps` skips Homebrew
entirely and reads `/Applications` and `~/Applications` directly.

With `--fetch`, it downloads the incoming cask build and diffs it against the
version you have installed — so you can see what an update *adds* before taking
it:

```bash
swift run -c release auditctl preview --fetch firefox
```

| Flag | Effect |
|---|---|
| `--all-apps` | Scan everything installed, not just outdated casks |
| `--apps-dir <path>` | Look somewhere other than `/Applications` |
| `--fetch` | Download the incoming build and diff it |
| `--only-noteworthy` | Suppress apps with nothing to say |
| `--min-tier <tier>` | Only report at or above a risk tier — `low`, `medium`, `high` or `critical`. Anything else exits 2 |
| `--json` | Machine-readable output |

> **Note**
>
> **`preview` will not upgrade anything.** It never runs `brew upgrade` and
> never blocks or delays an update — it will not get between you and your
> package manager.
>
> It does run `brew`, though. In cask mode — the default — every invocation
> shells out to `brew outdated --cask --json=v2`; only if that comes back with
> something outdated does a second call to `brew info --cask --json=v2` follow,
> so on an up-to-date machine you pay for `outdated` alone. Neither call is
> timed out. `--fetch` adds `brew fetch --cask <token>`, which downloads the
> incoming artifact into Homebrew's cache. And it exits 0 on success but 2 on
> failure, including when Homebrew isn't installed at all. Account for both
> before you wire it into a shell prompt or a pre-upgrade hook.

### The `--fetch` caveat

With `--fetch`, an incoming build is analysed *before* Gatekeeper has assessed
it. A freshly downloaded artifact can therefore show a one-off "notarization"
difference that is an artefact of the download rather than a real change in the
app. The output flags this where it applies — read it before drawing
conclusions.

`.dmg` and `.zip` cask artifacts are understood. `.pkg` is skipped.
