{"id":50221452,"url":"https://github.com/demirelo/mac-posture-audit","last_synced_at":"2026-05-26T12:05:17.561Z","repository":{"id":357012631,"uuid":"1234173915","full_name":"demirelo/mac-posture-audit","owner":"demirelo","description":"Read-only macOS security posture audit — 23 sections, stable JSON with --diff, severity profiles, single-file Bash 3.2 script.","archived":false,"fork":false,"pushed_at":"2026-05-10T22:05:44.000Z","size":104,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T00:21:05.559Z","etag":null,"topics":["audit","bash","macos","posture","read-only","security"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/demirelo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"docs/AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-09T20:58:05.000Z","updated_at":"2026-05-10T22:05:46.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/demirelo/mac-posture-audit","commit_stats":null,"previous_names":["demirelo/mac-posture-audit"],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/demirelo/mac-posture-audit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demirelo%2Fmac-posture-audit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demirelo%2Fmac-posture-audit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demirelo%2Fmac-posture-audit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demirelo%2Fmac-posture-audit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/demirelo","download_url":"https://codeload.github.com/demirelo/mac-posture-audit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/demirelo%2Fmac-posture-audit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33519231,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T03:12:49.672Z","status":"ssl_error","status_checked_at":"2026-05-26T03:12:47.976Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audit","bash","macos","posture","read-only","security"],"created_at":"2026-05-26T12:05:07.013Z","updated_at":"2026-05-26T12:05:17.555Z","avatar_url":"https://github.com/demirelo.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# mac-posture-audit\n\n[![Safety](https://github.com/demirelo/mac-posture-audit/actions/workflows/safety.yml/badge.svg?branch=main)](https://github.com/demirelo/mac-posture-audit/actions/workflows/safety.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Bash 3.2 compatible](https://img.shields.io/badge/bash-3.2%20compatible-blue)](#compatibility)\n\nA read-only, single-file shell script that audits a macOS machine's security posture and prints a colored report. Runs in seconds, makes no changes, and needs nothing beyond what ships with macOS.\n\n## Inspect before running\n\nDon't run security tooling on trust alone — it's one shell script, so read it first.\n\n```bash\ngit clone https://github.com/demirelo/mac-posture-audit\ncd mac-posture-audit\n\nless mac-posture-audit.sh          # 1. Read it — the whole tool is one file.\n/bin/bash -n mac-posture-audit.sh  # 2. Syntax-check on stock macOS Bash 3.2.\n./scripts/check-read-only.sh       # 3. CI-enforced tripwire: fails on any mutating\n                                   #    command or un-opted-in network call.\nshasum -a 256 mac-posture-audit.sh # 4. Pin a checksum for later re-pulls.\n```\n\nThe tripwire is itself regression-tested (`tests/check-read-only/should_{pass,fail}/`), so the safety check has teeth. Tags and commits are SSH-signed; `git tag -v` only means something once you've trusted the signer's key out-of-band (GitHub publishes pubkeys at `/\u003cuser\u003e.keys`). See [SECURITY.md](./SECURITY.md) for the full read-only guarantee and the narrow `sqlite3 -readonly` / read-only-verb `osascript` exceptions.\n\n## What it checks\n\n30 sections, 183 checks, by theme:\n\n- **System integrity** — SIP, Gatekeeper, FileVault, Apple Silicon Secure Boot, third-party kernel extensions.\n- **Login \u0026 privacy** — auto-login, screen-lock delay, Touch ID for sudo, Apple ads/analytics, Lockdown Mode.\n- **Network** — firewall \u0026 stealth, sharing services, AirDrop/Bluetooth/Wi-Fi exposure, DNS/DoH \u0026 VPN (incl. killswitch), proxies/PAC/WPAD, `/etc/hosts`, 16 AV/EDR engines, outbound monitors (Little Snitch / LuLu).\n- **Browsers \u0026 extensions** — installed/default browser, bundle-version staleness, profile counts, plus a Chromium/Safari/Firefox extension inventory that flags protective, wallet, and transaction-simulator add-ons.\n- **Developer \u0026 supply chain** — npm/yarn/pnpm `ignore-scripts`, supply-chain scanners, `.npmrc` and registry rewrites, `gh` / git credential helpers, `extra-index-url` dependency-confusion risk, Homebrew taps, IDE workspace trust + folder-open task autorun + trusted-folder sprawl, plaintext registry tokens on disk (npm/PyPI/cargo/gem), and a `supply.blast_radius` composite that answers \"if a malicious dependency install runs code here, how far can it reach?\"\n- **Credentials \u0026 secrets** — credential patterns in shell rc files, `.env` and sensitive dotfiles, SSH key encryption + agent, git signing.\n- **Crypto \u0026 2FA** — hardware wallets (Ledger / Trezor / Keystone / GridPlus), password managers, YubiKey / FIDO2, and a wallet-isolation composite.\n- **Backups \u0026 cloud** — Time Machine destinations / recency / encryption, third-party backup tools, iCloud sync, and sensitive data (`.ssh` / `.aws` / wallets) leaking into cloud-sync roots.\n- **Persistence \u0026 access** — LaunchAgents/Daemons (incl. webhook/exfil-shaped destinations), login items, crontab, TCC permission holders, remote-access apps, sandboxes, MDM enrollment, clipboard managers.\n- **Agents \u0026 MCP** — MCP servers (Cursor / Claude / Windsurf / Gemini): server count, `@latest`/`:latest` unpinned launchers, remote HTTP/SSE transports, dynamic launchers (npx/uvx/bunx/pipx/docker), filesystem-capable servers, and webhook/exfil destinations. MCP env values and key names are never read.\n- **AI agent instruction hygiene** — discovers the files that steer coding agents (`AGENTS.md` / `CLAUDE.md` / `GEMINI.md` / `.cursorrules` / `.cursor` rules, etc.) under your project roots and flags hidden/zero-width Unicode, suspicious directive-shaped phrases (prompt-injection / pipe-to-shell), and webhook destinations. Two-tier discovery with strict bounds (depth 3, ≤256 KB/file, ≤200 files, junk dirs pruned); matched lines, URLs, and tokens are never printed.\n- **Webhook / exfil shapes** — one-line exfil endpoints (Discord/Slack/Telegram/webhook.site/RequestBin/Pipedream/IFTTT/Zapier) detected across config surfaces that run automatically — shell rc, LaunchAgents, MCP configs, agent instruction files, `~/.npmrc` / `~/.pypirc` — aggregated into `config.webhook_exfil_shape`. Provider name only; never the URL or token.\n- **Inventory (catalog-driven)** — browser extensions, editor extensions (VS Code / Cursor / Windsurf / VSCodium), and MCP server IDs, each matchable against an exposure catalog of known-bad IDs.\n- **Attack chains** — named cross-section composites that fire only when a full attack path is assembled: `chain.fake_interview` (IDE auto-runs untrusted code + no sandbox), `chain.wallet_drain` (wallet + no isolation + no outbound monitor), `chain.agent_exposure` (a filesystem/remote MCP agent on the same machine as a wallet), `chain.cloud_exfil` (SSH keys / wallet data / dotfiles under a cloud-sync root), `chain.supply_to_wallet` (a poisoned dependency install reaching an unisolated wallet), `chain.agent_supply_chain` (an agent/IDE/MCP surface that can reach registry tokens, SSH keys, or a wallet).\n\nSeveral checks are composites that fold multiple rows into a single verdict (`system.theft_resistance`, `backup.recovery_path`, `ssh.posture`, `users.crypto_isolation_indicator`, the `chain.*` attack chains, …). The canonical check list is [tests/fixtures/expected_ids.txt](tests/fixtures/expected_ids.txt); composite patterns and agent-review guidance live in [docs/AGENTS.md](docs/AGENTS.md).\n\nEvery run ends with an **Executive Verdict** — a profile-aware one-line read plus an `Action priority:` level — and a **Top risks to address** list that ranks the findings that actually matter for your threat model (`urgent` \u003e `high` \u003e `medium` \u003e `low`) instead of dumping them in scan order. Both appear in the JSON too (`executive_verdict`, ranked `top_risks`). See [Top risks \u0026 verdict](#top-risks--verdict).\n\n## Usage\n\n```bash\n./mac-posture-audit.sh                                        # default: offline, read-only\nsudo ./mac-posture-audit.sh                                   # fuller audit; privileged probes skip without sudo\n./mac-posture-audit.sh --network                              # opt-in live checks (NextDNS routing, gh auth)\n./mac-posture-audit.sh --json --quick --redact \u003e posture.json # shareable machine-readable report\n```\n\n`--quick` skips privileged checks; `sudo` unlocks Secure Boot details, Remote Login, TCC permission holders, and sudoers. The default run is offline — `--network` is the only path to an external call.\n\n| Flag | Effect |\n|---|---|\n| `--quick` | Skip checks that require sudo |\n| `--json` | Machine-readable JSON output |\n| `--network` | Allow live external probes (NextDNS live-routing, `gh auth status`). Default off. |\n| `--offline` | Explicit no-external-calls (already the default) |\n| `--redact` | Mask hostname, emails, usernames, resolver IPs, `$HOME` paths, and brand names. Use when sharing. |\n| `--profile NAME` | Severity calibration: `normal` (default), `web3`, `paranoid`, `developer`, `founder`, `journalist`. `--profile auto` detects signals, recommends a profile, and exits. See [Profiles](#profiles). |\n| `--diff PATH` | Compare against a saved `--json` run; print one line per id whose status changed. |\n| `--exposure-catalog PATH` | Load a deny-list of known-bad extension/MCP/brew/bundle IDs. See [Exposure catalogs](#exposure-catalogs). |\n| `--summary-line` | Append one parseable summary line: `… pass=N warn=N fail=N skip=N`. Combines with `--json`. |\n| `--top N` | Cap the \"Top risks to address\" list to N items (default 7). `--top 0` hides the list but keeps the Executive Verdict. |\n| `--explain ID` | Print the threat rationale + per-profile severity for one check id (e.g. `chain.fake_interview`) and exit, without scanning. |\n| `--report md` | Render a shareable Markdown report (Executive Verdict + Top risks + full results table) instead of the terminal report. Honors `--redact`. |\n| `--snapshot` | Append a redacted JSON snapshot to `~/.mac-posture-audit/history/` (implies `--redact`). The only write the tool performs; default runs are read-only. |\n| `--trend` | Read-only: summarize how posture changed across stored snapshots (oldest vs newest). |\n| `--selftest` | Run a hermetic end-to-end smoke test and exit. Non-zero = the install can no longer detect what it should. |\n| `--version` / `--help` | Show version / usage and exit |\n\nExit code: `0` if no failures, `1` if any check fails, `2` if the script itself errors.\n\n### Profiles\n\n`--profile NAME` escalates specific checks past their default severity for a given threat model. The check still runs unchanged — only its resulting `status` is rewritten before being counted and printed, and a profile can never downgrade a `fail`.\n\n| Profile | Focus |\n|---|---|\n| `normal` | defaults — no escalation |\n| `web3` | wallet / key / supply-chain exposure → `fail` (wallet on main user, unencrypted SSH key, `ignore-scripts=false`, missing scanner or tx-simulator, wallet in cloud sync, remote-access app, stale browser, VPN killswitch off, IDE trust off) |\n| `paranoid` | everything in `web3`, plus Bluetooth/AirDrop exposure, weak firewall/stealth, stale or unencrypted Time Machine, missing auto-updates, plaintext Docker auth, `extra-index-url` |\n| `developer` | supply-chain + secret hygiene → `fail` (`ignore-scripts`, missing scanner, `extra-index-url`, shell-rc credentials) |\n| `founder` | union of `developer` + `web3` — solo founders shipping their own code who also custody crypto |\n| `journalist` | nation-state spyware lens — Lockdown Mode off is surfaced; Bluetooth/AirDrop, telemetry, remote access, browser debugging, VPN killswitch, and stale software all `fail` |\n| `auto` | not an escalation profile — detects signals (IDEs, dev toolchains, wallet apps/extensions), prints a recommended profile, and exits |\n\nThe exact override matrix is `PROFILE_OVERRIDES` in [mac-posture-audit.sh](mac-posture-audit.sh) — each entry is `profile|id|from_status|to_status` and only fires when the check actually emits `from_status`.\n\n### JSON output\n\nEach row carries a stable `id`, `status`, `label`, and `hint`. IDs are unique within a run and stable across runs, so consumers can diff successive scans by `id`:\n\n```json\n{\n  \"host\":\"\u003cHOST\u003e\",\"macos\":\"26.4.1\",\"arch\":\"arm64\",\n  \"summary\":{\"pass\":47,\"warn\":6,\"fail\":0,\"skip\":10,\"total\":63},\n  \"executive_verdict\":{\"profile\":\"founder\",\"tier\":\"high\",\"text\":\"…\",\"top_counts\":{\"urgent\":0,\"high\":4,\"medium\":2,\"low\":1}},\n  \"top_risks\":[\n    {\"rank\":1,\"id\":\"ext.wallet\",\"status\":\"warn\",\"tier\":\"high\",\"label\":\"Wallet extension(s) installed: …\",\"hint\":\"…\"}\n  ],\n  \"results\":[\n    {\"id\":\"system.sip.enabled\",\"status\":\"pass\",\"label\":\"SIP (System Integrity Protection) is enabled\",\"hint\":\"\"},\n    {\"id\":\"network.firewall.stealth\",\"status\":\"warn\",\"label\":\"Firewall stealth mode is off\",\"hint\":\"Firewall Options → Enable stealth mode\"}\n  ]\n}\n```\n\n`executive_verdict`, `top_risks`, and `summary.total` are additive (non-breaking) top-level fields. ID grammar is `\u003carea\u003e.\u003csubject\u003e.\u003cfact\u003e` (or `.\u003cinstance\u003e` for templated checks like `network.sharing.\u003cservice\u003e`). CI gates the full id set against [tests/fixtures/expected_ids.txt](tests/fixtures/expected_ids.txt) and dynamic patterns against [expected_id_patterns.txt](tests/fixtures/expected_id_patterns.txt). Full schema (field types, status enum, versioning) is in [docs/schema.md](docs/schema.md).\n\n`--diff PATH` compares the current run against a saved `--json` output and prints only the rows whose status changed (exit `0` if none differ, `1` if any, `2` on file/parse error). Combine with cron + `--profile` to track posture over time.\n\n```\n^ ext.wallet            warn -\u003e fail        (escalation)\nv ssh.keys.unencrypted  warn -\u003e pass        (resolved)\n+ persist.user.launchagents  (new)  warn    (new check or condition appeared)\n- av.engine.detected   (removed)  pass     (no longer emitted this run)\n```\n\n### Top risks \u0026 verdict\n\nThe audit doesn't just list findings — it tells you which ones can actually hurt you first. After the per-section rows and the flat Summary counts, every run prints:\n\n- an **Executive Verdict** — profile-aware, calm (it never cries \"compromised\" when nothing failed), with an `Action priority:` level derived from the highest-severity finding present and your concentration of risk;\n- **Top risks to address** — the warn/fail rows ranked by action priority, not scan order.\n\nTiers map to action, not drama:\n\n| Tier | Meaning |\n|---|---|\n| `urgent` | a `fail` on a high-blast row, or a fully-assembled `chain.*` |\n| `high` | any other `fail`, or a `warn` your profile cares about (wallet / dev / MCP / backup) |\n| `medium` | an ordinary `warn` |\n| `low` | optional / cosmetic hardening |\n\nEach risk also carries a remediation **effort** (`low` = flip a setting, `high` = structural work like a new user account or migrating a wallet), so high-impact / low-effort wins stand out — text shows `[tier · effort]`, JSON adds an `effort` field. The reorder is the point: on a `--profile founder` Mac, wallet exposure and a missing recovery path rise above \"firewall not in block-all mode.\" `--top N` caps the list (`--top 0` keeps just the verdict); `--explain \u003cid\u003e` prints the threat model behind a specific check. The same data is in the JSON (`executive_verdict`, ranked `top_risks`); the deeper per-finding narrative for an LLM reviewer stays in [docs/AGENTS.md](docs/AGENTS.md).\n\n### Sharing \u0026 trends\n\nThe audit is read-only by default, but a few opt-in companions make the report portable and longitudinal:\n\n```bash\n./mac-posture-audit.sh --report md \u003e posture.md            # shareable Markdown (honors --redact)\n./mac-posture-audit.sh --json --redact | python3 tools/render_report.py \u003e report.html   # self-contained HTML, no deps\n./mac-posture-audit.sh --snapshot                          # append a redacted JSON to ~/.mac-posture-audit/history/\n./mac-posture-audit.sh --trend                             # summarize improved/regressed checks across snapshots\n```\n\n`--snapshot` is the **only** write the tool ever performs (to its own data dir, redaction forced); everything else stays read-only. `tools/render_report.py` is a stdlib-only Python companion so the core stays a single shell file. For a maintained deny-list, point `--exposure-catalog` at [`catalog/known-bad.txt`](catalog/known-bad.txt) and refresh it via `git pull`.\n\n### Exposure catalogs\n\n`--exposure-catalog PATH` loads a deny-list of known-bad identifiers that the inventory checks (browser/editor extensions, MCP servers) consult. The catalog ships *separately from the script*, so a new wallet-drainer extension ID or compromised release can be added without rev'ing the audit:\n\n```\n# category|name|severity[|id]   (lines starting with # are comments)\nbrowser_extension_id|fakeextensionidaaaaaaaaaaaaaaaaaa|critical|drainer-2026-001\neditor_extension|malicious.publisher|warn|advisory-2026-042\nmcp_server|untrusted-remote-mcp|critical|campaign-x-2026\n```\n\n- **Categories**: `browser_extension_id`, `editor_extension`, `mcp_server`, `mcp_package`, `app_bundle_id`, `brew_formula`.\n- **Severity**: `info` (→ `skip`), `warn`, `critical` (→ `fail`).\n- Matching is case-insensitive on the name; unknown categories/severities are silently dropped; an unreadable catalog exits `2`.\n\nThe pipe-delimited format is heuristic by design — bash 3.2 portability ruled out a JSON parser, and a flat file is trivially hand-editable or generable from any threat-intel feed. The *collector* (this script, stable) / *threat-intel* (the catalog, versioned independently) split is borrowed from [perplexityai/bumblebee](https://github.com/perplexityai/bumblebee).\n\n### AI agent review\n\nThe audit is intentionally under-opinionated: it emits raw, stable signals and leaves the synthesis — which findings matter for *this user's* threat model, which combinations of low-signal SKIPs add up to a real gap — to whoever reads the report. Increasingly that reader is an LLM. Point any AI coding agent at [docs/AGENTS.md](docs/AGENTS.md) (or a saved JSON) and it can produce contextual recommendations rather than a generic checklist — backup-desert detection, wallet-without-isolation, plaintext-disk-on-theft, SSH risk surface, and more.\n\n### Sample output\n\n```\nmacOS Posture Audit\nRead-only. No changes will be made.\nHost: MacBook-Pro.local · macOS 26.4.1 · arch arm64\n\n━━━ 01 · System Integrity (Disk \u0026 Boot) ━━━\n  ✅ PASS SIP (System Integrity Protection) is enabled\n  ✅ PASS Gatekeeper is enabled\n  ✅ PASS FileVault is on (full-disk encryption active)\n  ✅ PASS Apple Silicon Secure Boot: Full Security\n  ✅ PASS Third-party kernel extensions disabled\n\n[…27 more sections…]\n\n━━━ Summary ━━━\n  ✅ Pass:  47\n  ⚠️  Warn:  6\n  ❌ Fail:  0\n  ⏭  Skip:  10\n```\n\n## Safety \u0026 privacy\n\n- **Read-only.** Never modifies any file or setting. The tripwire (`scripts/check-read-only.sh`) blocks command-position `rm`/`mv`/`cp`/`chmod`/`chown`/`defaults write`/`plutil -replace`/mutating `launchctl`, package installs (brew/npm/yarn/pnpm/pip/cargo/gem), `kill`, disk tooling, and `curl|bash` patterns, plus any network call outside `--network`. Two narrow allowlists — `sqlite3 -readonly` (TCC.db, §22) and read-only-verb `osascript` (login items, §22) — each have positive/negative fixtures.\n- **Offline by default.** `--network` is the only path to an external call (NextDNS routing, `gh auth status`).\n- **Bash 3.2 compatible.** Works on stock macOS without `brew install bash`, and makes no assumptions about your folder layout, email, or installed apps.\n- **Output is sensitive.** It maps which credential files live in `$HOME`, which TCC services have approved clients, which agents are installed, and which VPN/AV/wallet apps run — reading it tells someone what to attack. Use `--redact` before sharing; it masks hostnames, emails, usernames, IPs, `$HOME` paths, and brand names, and the credential check only ever prints filenames (`grep -l`). Redaction is asserted leak-free on every CI build ([tests/integration/redaction.bats](tests/integration/redaction.bats)).\n\nFor a one-line skim, this should only surface read-only probes, hint text, or the opt-in network checks:\n\n```bash\ngrep -En 'sudo|curl|gh |rm |mv |cp |chmod|chown|defaults|plutil|launchctl|kill|brew |npm |pip |osascript|sqlite3|diskutil|hdiutil' mac-posture-audit.sh\n```\n\n## Testing\n\n```bash\nbrew install bats-core shellcheck shfmt\n\nbash -n mac-posture-audit.sh\nshellcheck -S warning mac-posture-audit.sh scripts/check-read-only.sh tests/helpers.bash\nshfmt -d -i 2 mac-posture-audit.sh scripts/check-read-only.sh tests/helpers.bash\n./scripts/check-read-only.sh\nbats tests/sections tests/integration\n```\n\nThe Bats suite sources the script as a library with fixtures/mocked macOS CLIs for section-level tests; integration tests run the real script in `--quick` mode and assert JSON validity, redaction, argument handling, and summary-counter parity.\n\n## Compatibility\n\n\"Tested\" means an actual run against the listed environment; \"supported\" means the script should work and degrade to `skip` for any check that doesn't apply.\n\n| Type | Environment |\n|---|---|\n| Manual full run | macOS 26.5 (Tahoe), arm64, Bash 3.2.57 |\n| CI | GitHub Actions `macos-latest` — the exact `sw_vers` / `uname -m` / Bash version per release is printed in the Safety workflow's \"Print runtime versions\" step. |\n| Expected compatible | macOS Sequoia (15), Sonoma (14), Ventura (13). Older releases may use legacy `defaults` formats that some checks skip on cleanly. |\n| Architecture | Apple Silicon (primary, manually tested); Intel supported, with Apple-Silicon boot-security checks becoming n/a. |\n\n## What this isn't\n\n- Not a remediation tool — it reports what's wrong; it doesn't fix anything.\n- Not a malware scanner — use Bitdefender, Malwarebytes, or Objective-See for that.\n- Not a substitute for a real security audit — it's a self-check you can run weekly to track posture.\n\n## Roadmap\n\nv1.x is the public-release line. Possible directions:\n\n- **Evidence fields** in JSON rows so consumers get structured detail without scraping labels.\n- **`--deep` mode** — slower, opt-in scan across project directories with explicit excludes and redaction-safe output.\n- **Signed release artifacts** with published checksums.\n- **Continuous snapshot mode** that stores JSON locally and alerts on newly-introduced failures.\n- **Per-brand killswitch verification** for ProtonVPN / NordVPN (currently advisory) and broader messaging-app coverage (Signal, Discord, WhatsApp).\n\n## Contributing\n\nPull requests welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the four invariants: read-only probes, bash 3.2 compatibility, stable IDs, and hermetic tests via `*_ROOTS` overrides.\n\n## License\n\nMIT — see [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemirelo%2Fmac-posture-audit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdemirelo%2Fmac-posture-audit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdemirelo%2Fmac-posture-audit/lists"}