Documentation
Everything on this page covers the open-source CLI, licensed Apache 2.0. It is complete: nothing below requires an account, a key, or a server.
Install
pip install attestral
attestral --version
Python 3.10+. The core has two dependencies (click, pyyaml). Optional LLM elicitation adds the anthropic package: pip install "attestral[llm]".
Try the full loop on the bundled demo:
git clone https://github.com/attestral-labs/attestral && cd attestral
attestral scan examples/demo-project
attestral compile examples/demo-project -o policy.yaml
attestral drift policy.yaml examples/demo-project/runtime-events.jsonl
The loop
Attestral treats the design review, the runtime policy, and the audit evidence as one artifact in three forms:
- Attest.
scanbuilds a system model from Terraform and MCP configs and reviews it against typed rules. Findings are committed to a hash chain. - Enforce.
compileturns the reviewed model into a default-deny mcp-guard policy, stamped with the model hash and the review chain head. Your threat model stops being a document and becomes the configuration itself. - Prove.
driftdiffs runtime telemetry against the compiled policy. Anything the review never saw (a new server, a denied capability, an out-of-scope path) is drift, andverifyproves nobody edited the record afterward.
attestral scan
attestral scan PATH [-o STEM] [--format md|json|both] [--llm] [--fail-on SEVERITY]
| Flag | Behavior |
|---|---|
-o, --output | Output file stem (default attestral-report). |
--format | md for the human report, json for the chained evidence, both (default). |
--llm | Adds LLM threat elicitation on top of the deterministic layer. Requires ANTHROPIC_API_KEY. LLM findings are tagged origin: llm and never mixed silently with rule findings. |
--fail-on | Exit non-zero if findings at or above this severity exist. Works as a fail-closed CI gate. |
Ingestion is automatic: *.tf files feed the cloud model; mcp.json, *.mcp.json, and claude_desktop_config.json feed the agent-runtime model.
attestral verify
attestral verify report.json
Recomputes the hash chain offline and exits 0 (VALID) or 1 (INVALID). No network, no server, no account. An auditor can verify a two-year-old report on an air-gapped laptop.
attestral compile
attestral compile PATH [-o mcp-guard-policy.yaml]
Compilation is fail-closed by construction:
default: deny, so a server absent from the reviewed design is never allowed.- A critical finding against a server compiles to
allow: falsewith the rule id as the recorded reason. - Filesystem servers are narrowed to their attested roots; broad roots (
/,~,/home) deny until the design is re-scoped. - TLS-constrained servers observed with
http://URLs deny. - The policy header carries the model hash and review chain head, which binds the policy cryptographically to the review that produced it.
attestral drift
attestral drift POLICY_FILE EVENTS_FILE [--fail-on-drift]
| Rule | Severity | Fires when |
|---|---|---|
DRF-001 | critical | A server appears in telemetry that is not in the attested design. |
DRF-002 | critical | A server the review denied is invoked at runtime. |
DRF-003 | high | A filesystem path outside the attested roots is accessed. |
DRF-004 | high | A TLS-constrained server is observed over plaintext. |
--fail-on-drift exits non-zero on any finding, so drift checks run as a CI step or a cron job against yesterday's telemetry.
Writing rules
Rules are YAML with structured matchers. There is no eval anywhere, and an unknown matcher fails closed: the rule simply never matches.
rules:
- id: ORG-001
title: Internal ALB missing auth attribute
severity: high
target: aws_lb # component type prefix, or "model"
match: { attr_missing: auth }
description: ...
recommendation: ...
frameworks: ["NIST AC-3", "SOC2 CC6.1"]
| Matcher | Semantics |
|---|---|
attr_equals | Attribute equals value exactly. |
attr_in | Attribute is one of the listed values. |
attr_missing | Attribute is absent from the ingested design. |
attr_starts_with / attr_contains | String prefix / substring on the attribute. |
attr_list_contains / attr_list_any_of | Membership tests over list attributes. |
attr_any_contains | Any of several needles across one or more attributes. |
model_has_both | Model-level: both component type prefixes exist in the design. |
Load custom packs alongside the core pack via RuleEngine(["org_rules.yaml"]).
Evidence chain
Every run commits its findings to a SHA-256 hash chain: entry N hashes the canonical JSON of finding N together with the hash of entry N−1, starting from a zero genesis. The final hash (the chain head) appears in the report header and in every compiled policy.
The consequence: altering, inserting, or deleting any past entry changes every subsequent hash. A reviewer who records the chain head (in a PR comment, a ticket, an email) has permanently committed the whole review.
Telemetry format
drift reads JSONL, one event per line. mcp-guard emits this format natively, and anything else can adapt to it in a few lines:
{"ts": "2026-07-10T14:01:02Z", "server": "docs", "tool": "read_file", "args": ["/srv/docs/design.md"]}
| Field | Required | Meaning |
|---|---|---|
server | yes | MCP server name as configured. |
tool | yes | Tool invoked. |
args | no | Arguments; paths are checked against attested roots. |
url | no | Transport endpoint; checked against TLS constraints. |
ts | no | ISO-8601 timestamp, carried into drift findings. |
GitHub Action
Run drift checks on a schedule so conformance is continuous, not annual:
- uses: attestral-labs/attestral@v1
with:
policy: policy.yaml
events: events.jsonl
A complete nightly workflow (pull telemetry, re-compile the policy from the reviewed main branch, drift-check) ships in examples/github-actions/drift-schedule.yml. The mcp-guard telemetry emitter lives in integrations/mcp-guard/.
Terraform extra
The core ships a dependency-free Terraform scanner. For full-fidelity HCL parsing (nested blocks, correct types), install the extra. Attestral picks it up automatically and falls back gracefully on malformed files:
pip install "attestral[terraform]"
Roadmap
Attestral is an open-source project. Everything documented above is the complete, current surface. Next up, roughly in order: a full HCL expression evaluator, more rule packs (Kubernetes, GCP, Azure), PR design-diffing, and import from legacy threat modeling exports. Issues and contributions are welcome on GitHub.