Security posture
RAC is offline by design. The rac CLI and the editor extension model
product knowledge from local Markdown files and emit local files and exit codes;
they make no network calls and send no telemetry. This document records that
posture as a control a security office can verify and sign — not a marketing
claim — and points at the artifacts that prove it.
The posture is self-attestable: it is backed by the package's own deterministic behaviour, a committed SBOM, and a runnable network-isolation test. It is not a hosted service or a third-party certification (see Scope).
The no-egress guarantee
- No network access.
racreads and writes the local filesystem only. None of its analysis paths — validation, relationships, review, the unified gate, search, and export — open a socket. This is enforced as an architectural invariant (ADR-002): RAC is deterministic and AI-optional, so the core never depends on a remote call. - No telemetry. RAC collects no usage analytics in its default operation. The optional MCP server and any AI-assisted authoring are explicitly opt-in and bring-your-own-credentials (ADR-035); nothing phones home on your behalf.
- Deterministic, local-only data flow. The same corpus state yields byte-identical JSON and SARIF output, with no timestamps and stable ordering (ADR-002). Nothing leaves the machine: input is local Markdown, output is local text and an exit code.
Data flow
local Markdown (rac/) -> rac (pure, in-process analysis) -> local output
(stdout: human / JSON / SARIF,
files, exit code)
There is no intermediate service, no upload, and no callback. A CI gate uploads SARIF to your GitHub Code Scanning from your runner — that egress is your CI's, configured by you, not RAC's.
Dependency surface
RAC declares three runtime dependencies (pyproject.toml, [project].dependencies):
| Dependency | Purpose |
|---|---|
markdown-it-py |
Markdown parsing (the artifact source format). |
pyyaml |
Frontmatter and .rac/config.yaml parsing. |
mcp |
The optional Model Context Protocol server surface. |
The full, machine-readable dependency list — including resolved versions — is the
committed sbom.json
at the repository root.
How to verify
You can re-derive every part of this posture yourself, offline:
- SBOM. Regenerate and diff the Bill of Materials:
bash
python scripts/generate_sbom.py --stdout
It emits a deterministic CycloneDX 1.5 JSON document
for the package and its runtime dependencies (no timestamps, stable ordering).
tests/test_sbom.py guards the committed sbom.json against drift from the
declared dependencies, so the SBOM can never silently fall behind.
- No-egress test. Run the network-isolation test, which patches
socket.socket/socket.create_connectionto raise on use, then exercises validation, relationships, review, the gate, search, and export over a fixture corpus — failing if any path attempts a socket:
bash
python -m pytest tests/test_no_egress.py -q
This is the runnable control backing the no-egress claim.
- Audit the dependency tree. The three runtime dependencies above are the entire surface; there is no transitive network client in RAC's own code.
Scope and non-goals
This posture is self-attestable and offline-first. It deliberately does not include:
- a hosted control plane or any server-side component;
- per-user analytics or usage tracking;
- a third-party security certification.
The guarantee is that RAC runs locally with no egress and no telemetry, and that this is verifiable from the repository. Anything beyond a self-attestable, offline posture is out of scope for the project (v0.21.14 Non-Goals).
See also
- Governance — the
enforcement:policy andrac gate. - Validation — the write-time gate and SARIF output.
- ADR-002 — deterministic, AI-optional core.
- ADR-035 — bring-your-own AI credentials.