From 213337e7fbef42e154debb450ae06d18e4ed5c62 Mon Sep 17 00:00:00 2001 From: adamXbot <111877622+adamXbot@users.noreply.github.com> Date: Sun, 9 Aug 2026 18:46:38 +1000 Subject: [PATCH] docs: restructure the README to the portfolio standard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reorders the README into the shared product layout (hero, badges, disclosure, overview, what it does, get it, docs, contributing, licence) and removes claims that could not be verified against the repo. Removed two dead relative links: * `ARCHITECTURE.md` — linked from "How it works" as `architecture.md`. No such file at the repo root; the real one is `.github/ARCHITECTURE.md`, which is now linked from the Docs section. * `docs/RELEASES.md` — linked from the Updates section. The file does not exist. The release pipeline lives in privacykey/gh-workflows, reached via `.github/workflows/release.yml`; CONTRIBUTING.md now says so. Corrected one wrong fact: * Sparkle was documented as "Up to Next Major from 2.9.0". The Xcode project pins minimumVersion 2.9.1. CONTRIBUTING.md now states 2.9.1. Badge row rebuilt to the standard set, keeping only badges that resolve: status, release (v0.1.5), licence, and CI. The CI badge points at app-ci.yml, which runs on pushes to main; a badge for ci.yml would render "no status" because that workflow only triggers on pull_request. The downloads, Homebrew and "macOS 13+" badges are dropped — the macOS requirement is now stated in prose under "Get it". The beta warning is replaced by the standard disclosure block. The tier name is not written as prose; it comes from the status badge. Content moved rather than deleted: * Build-from-source steps, the auditctl command-line reference and the contribution checklist -> CONTRIBUTING.md (new). * The privacy and telemetry posture -> docs/PRIVACY.md (new), corrected while moving: the app also holds an Apple Events entitlement for VM front-end enumeration, which the old text did not mention. * The "How it works" layer table -> dropped in favour of a link to `.github/ARCHITECTURE.md`, which already carries the same table plus the diagram and the data-flow narrative. Also dropped a stale placeholder note under Screenshots saying screenshots would arrive once the brand site is up, and a "Related products" list whose only entry was this repo. The existing screenshot is kept. No version claim above 0.1.5 anywhere: the pbxproj carries a stray MARKETING_VERSION = 1.0 alongside 0.1.5 and the latest release is v0.1.5. README 11630 -> 7146 bytes. Co-Authored-By: Claude Opus 5 --- CONTRIBUTING.md | 130 +++++++++++++++++++++++++++++++++++++ README.md | 169 ++++++++++++++---------------------------------- docs/PRIVACY.md | 51 +++++++++++++++ 3 files changed, 231 insertions(+), 119 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 docs/PRIVACY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5cba33a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,130 @@ +# Contributing to privacycommand + +Issues and pull requests are welcome. This file holds the setup detail that used +to sit in the top-level [`README.md`](README.md). + +## Two build paths + +The repository builds the same sources two ways. `Package.swift` and the Xcode +project both live under `privacycommand/`, not at the repository root. + +**Swift Package Manager** builds the headless pieces — the `privacycommandCore` +analyser, the `auditctl` CLI and its `auditctlKit` half, the guest agent, and the +shared guest protocol. This is the fast iteration loop and it is what CI runs: + +```sh +cd privacycommand +swift build +swift test +``` + +From the repository root, [`just`](https://github.com/casey/just) wraps the same +commands: `just build`, `just test`, `just clean`. + +**Xcode** is the only path that builds and ships the GUI app, because the SwiftUI +app target and the privileged-helper target exist only in the project file: + +```sh +cd privacycommand +open privacycommand.xcodeproj +``` + +On a fresh checkout you need to do two things once: + +1. **File → Add Package Dependencies…** → `https://github.com/sparkle-project/Sparkle`, + Up to Next Major from `2.9.1` (the version the project file pins). Tick the + `Sparkle` product on the `privacycommand` target. +2. Select the **privacycommand** and **privacycommandHelper** targets in turn → + Signing & Capabilities → set Team. Both must match, or the helper will refuse + the app's XPC connection at runtime. + +Then ⌘B. Everything else — the Copy Files phases that place the helper and its +LaunchDaemon plist inside the bundle, the entitlements, the target dependency — +is already wired in the project. + +Deeper references live next to the sources: + +- [`privacycommand/README.md`](privacycommand/README.md) — source-tree map, why + each target exists, signing and entitlements quick reference, troubleshooting. +- [`privacycommand/HELPER.md`](privacycommand/HELPER.md) — privileged helper + bundling, signing and the verification recipe. +- [`privacycommand/docs/GUEST_AGENT.md`](privacycommand/docs/GUEST_AGENT.md) — + building and deploying the in-VM guest agent. +- [`.github/ARCHITECTURE.md`](.github/ARCHITECTURE.md) — how the pieces fit + together and how data moves between them. + +## The auditctl CLI + +`auditctl` is a command-line front end over the same analyser, useful for +scripting and CI. Build it once, then call the binary directly: + +```sh +cd privacycommand +swift build -c release +BIN=.build/release/auditctl +``` + +A one-shot static audit takes a path or an installed-app name: + +```sh +$BIN /System/Applications/Calculator.app +$BIN slack --short # one-line verdict +$BIN slack --tree # frameworks / XPC / helpers / login-item tree +$BIN slack --json # machine-readable +$BIN slack --warnings # findings section only +$BIN slack --exact # exact name match instead of substring +$BIN slack --warn-exit # exit 1 when there are warn/error findings +``` + +Exit codes: `0` analysed cleanly · `1` analysis failed, or `--warn-exit` with +findings · `2` bad arguments or target not found · `4` ambiguous name. + +The `preview` command inspects app updates before you take them. With no +arguments it checks your outdated Homebrew casks: + +```sh +$BIN preview +$BIN preview --all-apps --only-noteworthy --min-tier warn +$BIN preview --json +$BIN preview --fetch firefox # download the incoming build and diff it +``` + +`preview` is inform-only: it never runs `brew`, never blocks an update, and +always exits 0. It understands `.dmg` and `.zip` cask artifacts; `.pkg` is +skipped. With `--fetch`, an incoming build is analysed *before* Gatekeeper has +cleared it, so a one-off notarization difference can simply be a fresh-download +artifact — the output flags this when it happens. + +Running `auditctl` with no arguments opens an interactive browser when stdin and +stdout are a terminal, and prints usage otherwise so CI callers do not hang. + +## What CI runs + +Two workflows run on every pull request against `main`: + +- [`ci.yml`](.github/workflows/ci.yml) — builds every SPM target, runs the full + test suite, then runs the built `auditctl` against `Calculator.app` as an + end-to-end smoke test of the analyser's exit-code contract. +- [`app-ci.yml`](.github/workflows/app-ci.yml) — an unsigned Xcode build and test + of the app target, through a reusable workflow in `privacykey/gh-workflows`. + This one also runs on pushes to `main`. + +Run `swift test` from `privacycommand/` before opening a pull request and confirm +it passes. + +## Before you open a pull request + +- For UI changes, attach a before/after screenshot. +- For a new analysis signal, add a Knowledge Base entry alongside the detector. + privacycommand explains what every finding means in plain English, and that + contract is worth keeping. +- Releases are cut by tagging: `just release `, where the tag must match + `MARKETING_VERSION` in the Xcode project. The pipeline itself lives in + `privacykey/gh-workflows`; [`.github/workflows/release.yml`](.github/workflows/release.yml) + is a thin caller and documents the secrets it needs. + +## Security issues + +Do not open a public issue for a vulnerability. [`.github/SECURITY.md`](.github/SECURITY.md) +has the reporting address, the response times I aim for, and what is in and out +of scope. diff --git a/README.md b/README.md index d1ff009..394309f 100644 --- a/README.md +++ b/README.md @@ -6,154 +6,85 @@ **drop an app. see everything it touches.** -Forensic permission audits for any macOS app — built for security teams, IT, and privacy-conscious users. +Forensic permission audits for any macOS app. -[![Latest release](https://img.shields.io/github/v/release/privacykey/privacycommand?style=flat-square&color=4338CA&label=release)](https://github.com/privacykey/privacycommand/releases/latest) -[![Downloads](https://img.shields.io/github/downloads/privacykey/privacycommand/total?style=flat-square&color=A5B4FC&label=downloads)](https://github.com/privacykey/privacycommand/releases) -[![Homebrew](https://img.shields.io/badge/homebrew-privacykey%2Ftap-FBBF24?style=flat-square&logo=homebrew&logoColor=white)](https://github.com/privacykey/homebrew-tap) -[![macOS 13+](https://img.shields.io/badge/macOS-13%2B-1E1B4B?style=flat-square&logo=apple&logoColor=white)](https://www.apple.com/macos) -[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat-square)](LICENSE) - -[Download](https://github.com/privacykey/privacycommand/releases/latest) · [Release notes](https://github.com/privacykey/privacycommand/releases) · [Report an issue](https://github.com/privacykey/privacycommand/issues) +[![Project status](https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fprivacykey%2F.github%2Fmain%2Fbadges%2Fprivacycommand.json)](https://github.com/privacykey/.github/blob/main/STATUS.md#privacycommand) +[![Release](https://img.shields.io/github/v/release/privacykey/privacycommand?label=release)](https://github.com/privacykey/privacycommand/releases/latest) +[![Licence](https://img.shields.io/github/license/privacykey/privacycommand?label=licence)](LICENSE) +[![CI](https://img.shields.io/github/actions/workflow/status/privacykey/privacycommand/app-ci.yml?branch=main&label=ci)](https://github.com/privacykey/privacycommand/actions/workflows/app-ci.yml) ---- - + > [!WARNING] -> **This is a beta — pre v1.0.** privacycommand is under active development. -> Expect occasional crashes, behaviour changes between releases, and -> a report format that may still shift. If you see any bugs, please -> attach the matching `.ips` from `~/Library/Logs/DiagnosticReports/` -> to a [new issue](https://github.com/privacykey/privacycommand/issues/new) -> or report a [security vulnerability](https://github.com/privacykey/privacycommand/security/advisories/new) through github or the security email. - -## What it does - -Drop a `.app` bundle (or a `.dmg`) onto privacycommand and it produces a full forensic report of what the app actually touches: - -- **Static analysis** — entitlements, code-signing (the 10-character signing Team ID expanded to the developer's name), notarization deep-dive (stapler / spctl / SHA-256), URL schemes, document types, hard-coded domains and URLs, embedded launch agents and helpers, third-party SDK fingerprints (LaunchDarkly, Firebase, Mixpanel, AdMob, …), feature flags and trial-state strings, secrets and license-key names, anti-analysis signals, dylib hijacking surface, and Apple's Privacy Manifest cross-checked against what the binary actually uses. -- **Forensic binary summary** — a plain-English read of what the main binary links and calls, including an **outbound network call-sites** map: which functions can open a connection, the networking symbols they reach for (BSD sockets, `getaddrinfo`, CFNetwork, Network.framework `nw_*`), and any host or URL literals sitting next to them. Any call site can be **decompiled on demand** (if you have Ghidra installed), and for relaunchable, non-hardened-runtime apps you can capture a **live call stack** that ties an actual outbound connection back to the function that opened it. -- **App Store privacy labels** — when the bundle was installed from the Mac App Store, privacycommand fetches the developer's declared Privacy Nutrition Labels from `apps.apple.com` and shows them next to its static-analysis findings, so you can see whether the developer's claims line up with what the binary contains. -- **Telemetry callout** — a Dashboard card flags how many analytics, advertising, and attribution SDKs the bundle ships, with a heat-graded count and per-category breakdown. -- **Background Task Management** — every login item, launch agent, daemon, and helper the app has registered, fetched via the privileged helper so there's no admin prompt. -- **Feature flags & trials** — the names of `isPro`, `isTrial`, `subscription_status`, `experiment_id`, and platform-specific switches (LaunchDarkly, Optimizely, Firebase Remote Config, PostHog, Statsig, Unleash) that the binary checks at runtime. -- **Monitored runs** — launch the inspected app under privacycommand and watch its file events (via an optional privileged helper running `fs_usage`), network destinations (reverse-DNS-labelled, with click-through IP lookups, row highlighting, and a highlighted-only filter), child processes, pasteboard / camera / microphone / screen-recording activity, USB device interactions, and resource usage in real time. -- **Network kill switch** — block the inspected app's outbound traffic system-wide via a `pf` anchor installed by the helper. Watch how the app handles being cut off. -- **VM mode** — a guest agent that runs inside a macOS VM (VirtualBuddy / UTM / Parallels) and ships observations back to the host across the VM boundary, for analysing apps you'd rather not run on your bare-metal machine. -- **Compare runs** — diff any two saved reports side by side from the History tab. Added and removed entitlements, domains, SDKs, login items, and findings are colour-cued, with a "show only changes" toggle — so you can see exactly what an app update introduced. -- **Batch scan** — point privacycommand at a folder (or all of `/Applications`) and triage many apps at once in a sortable, filterable table: risk tier, warning/error counts, and headline signals per app. The same analyzer runs on each; one click opens any app in the main window for the full deep-dive. -- **Reports** — every finding exports as JSON, HTML, or PDF. - -## Install +> **Pre-1.0 — no stable release yet.** Anything can change in any release, including a patch: APIs, CLI flags, config keys, file formats, and data already on disk. Keep your own backups. +> **Project status.** The badge above is generated from [the privacykey status list](https://github.com/privacykey/.github/blob/main/STATUS.md), which says what I promise for this project and every other one. + -### Homebrew (recommended) - -```sh -brew install privacykey/tap/privacycommand -``` +--- -That's it. The tap lives at [`privacykey/homebrew-tap`](https://github.com/privacykey/homebrew-tap); `brew upgrade --cask privacycommand` keeps it current. When privacycommand detects it's running from a Homebrew Caskroom, it disables in-app updates so `brew` stays in charge of the on-disk version. +privacycommand takes a `.app` bundle (or a `.dmg`) and reports what the app actually touches: the entitlements it claims, the permissions it will ask for, the domains and URLs compiled into its binary, the third-party SDKs it ships, the login items and helpers it registers — and, if you let it, what it does while it runs. -### Direct download +It is built for people who want evidence rather than a vendor's word: security teams, IT, and anyone deciding whether a download deserves a place in `/Applications`. Every finding carries a plain-English explanation from an in-app knowledge base, so a report is readable without a reverse-engineering background. -Grab the signed + notarized `.dmg` from the [latest release](https://github.com/privacykey/privacycommand/releases/latest) and drag the app to `/Applications`. In-app updates are handled by [Sparkle 2](https://sparkle-project.org); they're **off by default** — you opt in via Settings → Updates. +All analysis happens on your machine, and the app ships no analytics of its own. The exact list of network calls it makes is in [`docs/PRIVACY.md`](docs/PRIVACY.md). -### Build from source +privacycommand Dashboard -```sh -git clone https://github.com/privacykey/privacycommand.git -cd privacycommand/privacycommand -open privacycommand.xcodeproj -``` +## What it does -Then in Xcode: -1. **File → Add Package Dependencies…** → `https://github.com/sparkle-project/Sparkle` (Up to Next Major from `2.9.0`). Tick the `Sparkle` product on the `privacycommand` target. -2. Select the **privacycommandHelper** target → Signing & Capabilities → set Team to match the app. -3. ⌘B. +- **Static analysis** — entitlements, code signing (the 10-character Team ID expanded to the developer's name), a notarization deep-dive (stapler / spctl / SHA-256), URL schemes, document types, hard-coded domains, embedded launch agents and helpers, feature-flag and trial-state strings, secrets and licence-key names, anti-analysis signals, dylib hijacking surface, and Apple's Privacy Manifest checked against what the binary actually uses. +- **SDK fingerprints** — which analytics, advertising and attribution SDKs the bundle ships, with a heat-graded count and per-category breakdown. +- **Outbound call sites** — which functions can open a connection, the networking symbols they reach for (BSD sockets, `getaddrinfo`, CFNetwork, `nw_*`), and any host or URL literals sitting next to them. Any call site can be decompiled on demand if you have Ghidra installed. +- **App Store privacy labels** — for Mac App Store bundles, the developer's declared Privacy Nutrition Labels sit next to the static findings, so you can see whether the claims match the binary. +- **Background Task Management** — every login item, launch agent, daemon and helper the app has registered, read through the privileged helper. +- **Monitored runs** — launch the inspected app under privacycommand and watch, in real time, its file events (via the optional helper running `fs_usage`), network destinations with reverse-DNS labels, child processes, pasteboard / camera / microphone / screen-recording activity, USB device interactions and resource usage. +- **Network kill switch** — cut the app off from the destinations it is contacting, via a `pf` anchor installed by the helper, and watch how it copes. +- **VM mode** — a guest agent that runs inside a macOS VM (VirtualBuddy / UTM / Parallels) and ships observations back to the host, for apps you would rather not run on bare metal. +- **Compare runs** — diff any two saved reports from the History tab. Added and removed entitlements, domains, SDKs, login items and findings are colour-cued, with a "show only changes" toggle. +- **Batch scan** — point it at a folder, or at all of `/Applications`, and triage many apps at once in a sortable table of risk tiers, warning counts and headline signals. +- **Reports** — every finding exports as JSON, HTML or PDF. -The Swift Package Manager target builds with `swift build` from `privacycommand/`; tests run with `swift test`. +## Get it -## Command line +Requires macOS 13 or later. -The repo also builds `auditctl`, a small CLI over the same analyzer — handy for scripting and CI. Build it once with `swift build -c release` from `privacycommand/`, then: +**Homebrew** — the cask lives in [`privacykey/homebrew-tap`](https://github.com/privacykey/homebrew-tap): ```sh -# Full static report for a single app (pretty-printed; non-zero exit on parse failure) -swift run -c release auditctl /Applications/SomeApp.app - -# Privacy-preview apps *before* you update them. With no arguments, preview -# checks your outdated Homebrew casks; --all-apps scans everything installed. -swift run -c release auditctl preview -swift run -c release auditctl preview --all-apps --only-noteworthy --min-tier warn -swift run -c release auditctl preview --json - -# --fetch downloads each incoming cask build and diffs it against the version -# you have installed, so you can see what an update *adds* before you take it. -swift run -c release auditctl preview --fetch firefox +brew install --cask privacykey/tap/privacycommand ``` -`preview` is **inform-only**: it never runs `brew`, never blocks an update, and always exits 0. It reuses the same static analyzer and risk scoring as the app, and understands `.dmg` and `.zip` cask artifacts (`.pkg` is skipped). Heads-up: with `--fetch`, an incoming build is analyzed *before* Gatekeeper has cleared it, so a one-off "notarization" difference can just be a fresh-download artifact (the output flags this). +`brew upgrade --cask privacycommand` keeps it current. When privacycommand detects it is running from a Homebrew Caskroom it disables in-app updates, so `brew` stays in charge of the on-disk version. -## Screenshots +**Direct download** — take the signed and notarized `.dmg` from the [latest release](https://github.com/privacykey/privacycommand/releases/latest) and drag the app to `/Applications`. In-app updates use [Sparkle 2](https://sparkle-project.org) against an EdDSA-signed [appcast feed](https://privacykey.github.io/privacycommand/appcast.xml); automatic checks are **off by default** and you opt in under Settings → Updates. -> _Screenshots go here once the brand site is up. The Dashboard renders telemetry, App Store privacy labels, live probes, and a forensic findings list; the Static tab walks every signal we extract from the binary._ +**Command line** — the repo also builds `auditctl`, a CLI over the same analyser. Its `preview` command inspects Homebrew casks *before* you update them; it never runs `brew`, never blocks an update, and always exits 0. Building and using it is covered in [CONTRIBUTING.md](CONTRIBUTING.md#the-auditctl-cli). -CleanShot 2026-04-29 at 19 09 22 +## Docs +There is no docs site yet. What exists lives in the repo: -## How it works - -privacycommand is a SwiftUI app backed by a pure-Swift analyzer library and an optional privileged helper. The architecture is split deliberately: - -| Layer | Path | Notes | -|---|---|---| -| Analyzer logic | [`privacycommand/Sources/privacycommandCore/`](privacycommand/Sources/privacycommandCore/) | Headless, AppKit-free; runs from CLI, tests, GUI | -| App UI | [`privacycommand/Sources/privacycommand/`](privacycommand/Sources/privacycommand/) | SwiftUI views + view-models | -| Privileged helper | [`privacycommand/Sources/privacycommandHelper/`](privacycommand/Sources/privacycommandHelper/) | XPC service installed via `SMAppService.daemon` | -| Guest agent (VM) | [`privacycommand/Sources/privacycommandGuestAgent/`](privacycommand/Sources/privacycommandGuestAgent/) | Runs in-VM, ships observations to the host | - -Read [`architecture.md`](ARCHITECTURE.md) for the longer version. - -## Updates - -Updates ship through two channels that share the same DMG: - -1. **Direct downloads** receive in-app updates via Sparkle 2. Auto-checks are off by default — opt in via Settings → Updates. -2. **Homebrew** users update via `brew upgrade --cask privacycommand`. privacycommand detects Cask installs and disables Sparkle's installer to stay out of `brew`'s way. - -The appcast feed is hosted on `gh-pages` at `https://privacykey.github.io/privacycommand/appcast.xml` and signed with EdDSA — see [`docs/RELEASES.md`](docs/RELEASES.md) for the release flow. - -## Privacy & telemetry posture - -privacycommand is a privacy tool and behaves like one: - -- **No analytics.** privacycommand does not ship any analytics SDKs. There is no telemetry endpoint, no install counter, no crash-report bucket. -- **Network calls are explicit and bounded.** - - DNS reverse lookups for destinations the inspected app contacts (so the Network tab can label `8.8.8.8` as `dns.google`). - - Mac App Store privacy-label lookups against `itunes.apple.com` and `apps.apple.com` — keyed by the inspected app's bundle ID, never your data. - - Sparkle appcast fetch from `privacykey.github.io` when you check for updates. -- **All analysis runs locally.** The inspected app's contents never leave your machine. -- **The helper is opt-in.** Without the helper, privacycommand still works — file-event monitoring is unavailable and the Background Task Management audit asks before triggering an admin prompt. +- [`.github/ARCHITECTURE.md`](.github/ARCHITECTURE.md) — the targets, why they are separate, how data moves between them. +- [`privacycommand/README.md`](privacycommand/README.md) — source-tree map, signing and entitlements reference, troubleshooting. +- [`privacycommand/HELPER.md`](privacycommand/HELPER.md) — privileged helper bundling, signing and verification. +- [`privacycommand/docs/GUEST_AGENT.md`](privacycommand/docs/GUEST_AGENT.md) — VM guest-agent walkthroughs. +- [`docs/PRIVACY.md`](docs/PRIVACY.md) — every network call the app makes, and why. +- [`NOTICES.md`](NOTICES.md) — third-party notices. ## Contributing -Issues and PRs welcome. Before opening a PR: - -- Run `swift test` from `privacycommand/` and confirm it passes. -- For UI changes, attach a before/after screenshot. -- For new analysis signals, add a Knowledge Base entry alongside the detector — privacycommand explains what every finding means in plain English, and we want to keep that contract. - -## Security disclosures +Issues and pull requests are welcome. CI runs two workflows on every pull request: the SPM build and test suite plus an `auditctl` smoke test, and an unsigned Xcode build of the app target. Reproduce the first locally from `privacycommand/`: -If you find a security issue, please **don't** open a public issue. Email `security@privacykey.org` with the details. We aim to respond within 72 hours. - -## Related products +```sh +swift build +swift test +``` -privacycommand is a **privacykey** project +Or `just build` and `just test` from the repo root. Setup, the Xcode path, and what to include in a pull request are in [CONTRIBUTING.md](CONTRIBUTING.md). -- **[privacycommand](https://github.com/privacykey/privacycommand)** — macOS forensic permission auditor _(this repo)_ +Found a security issue? Please do not open a public issue — [`.github/SECURITY.md`](.github/SECURITY.md) has the reporting address and what is in scope. -## License +## Licence -Released under the [MIT License](LICENSE). +Released under the [MIT licence](LICENSE). diff --git a/docs/PRIVACY.md b/docs/PRIVACY.md new file mode 100644 index 0000000..a238bd6 --- /dev/null +++ b/docs/PRIVACY.md @@ -0,0 +1,51 @@ +# Privacy and telemetry posture + +privacycommand is a privacy tool and behaves like one. This page states exactly +what it sends and what it does not, so you can check the claim rather than take +it. This content used to live in the top-level [`README.md`](../README.md). + +## No analytics + +privacycommand ships no analytics SDKs. There is no telemetry endpoint, no +install counter, and no crash-report bucket. The Swift package manifest declares +no third-party dependencies at all, and the Xcode project adds exactly one — +[Sparkle 2](https://sparkle-project.org), for in-app updates. + +## All analysis runs locally + +The contents of the app you inspect never leave your machine. Static analysis, +disassembly, decompilation, monitoring and report generation all happen on the +host (or, in VM mode, inside your own virtual machine). + +## The network calls it does make + +They are explicit and bounded: + +- **Reverse DNS lookups** for the destinations the inspected app contacts, so the + Network tab can label `8.8.8.8` as `dns.google`. +- **Mac App Store privacy-label lookups** against `itunes.apple.com` and + `apps.apple.com`, keyed by the inspected app's bundle identifier — never by + anything about you. +- **The Sparkle appcast fetch** from `privacykey.github.io` when you check for + updates. Automatic checks are off by default; you opt in under + Settings → Updates. Homebrew Cask installs suppress the in-app updater + entirely. +- **Incoming-build downloads**, only when you explicitly ask for them: the + `auditctl preview --fetch` path retrieves a cask artifact from its own + publisher so it can be diffed against the version you have installed. + +`com.apple.security.network.client` is the only entitlement covering outbound +network access. The app also holds `com.apple.security.automation.apple-events`, +which is not network access: it lets the guest-agent panel ask installed VM +front-ends (VirtualBuddy, UTM, Parallels, VMware) over AppleScript which VMs +exist. The hardened-runtime escapes are deliberately absent — no `allow-jit`, no +`allow-dyld-environment-variables`, no `disable-library-validation`. + +## The privileged helper is opt-in + +Without the helper, privacycommand still works — you lose file-event monitoring, +and the Background Task Management audit asks before triggering an admin prompt. +The helper is a minimal XPC service installed through `SMAppService.daemon`; it +validates callers by Team ID on connect, and its whole job is to run +`fs_usage`, `sfltool` and `pfctl` on the app's behalf. See +[`privacycommand/HELPER.md`](../privacycommand/HELPER.md).