Skip to content

Commit 6ae7d78

Browse files
committed
v0.9.2: integration cookbook, external audit verifier, compliance docs, MCP manifest, Scorecard CI
- docs/INTEGRATIONS.md: 'use Burnwall with anything' — base-URL recipes for coding tools, agent SDKs, and any OpenAI/Anthropic-compatible gateway. - External audit verification: docs/COMPLIANCE.md (receipt -> ISO 42001 / EU AI Act / SOC 2 mapping, as evidence not certification) + tools/verify_receipts.py, a standalone Ed25519 chain-verifier over the audit export bundle (no Burnwall needed). Verified end-to-end: OK on a real export, TAMPERED on a flipped hash. - packaging/mcp/server.json + docs/MCP_REGISTRY.md: MCP registry manifest/listing. - .github/workflows/scorecard.yml: OpenSSF Scorecard supply-chain trust signal. - README: '100% local, zero telemetry' headline + 'works with' pointer. - Bump to 0.9.2; CHANGELOG entries for [0.9.1] and [0.9.2].
1 parent d860990 commit 6ae7d78

9 files changed

Lines changed: 294 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,42 @@
22

33
All notable changes to Burnwall.
44

5+
## [0.9.2] — 2026-05-28
6+
7+
### Added
8+
9+
- **"Use Burnwall with anything" cookbook** (`docs/INTEGRATIONS.md`) — one-line
10+
base-URL recipes to put Burnwall in front of your coding tools, agent SDKs, and
11+
any OpenAI-/Anthropic-compatible gateway (e.g. OpenRouter). Burnwall runs *in
12+
front of* your existing setup; nothing else changes.
13+
- **Independent audit verification.** `burnwall audit export --format json` emits a
14+
self-contained, signed receipt bundle, and `tools/verify_receipts.py` re-walks the
15+
hash chain and verifies every Ed25519 signature **without trusting the Burnwall
16+
binary**. `docs/COMPLIANCE.md` maps the receipts to EU AI Act Art. 12 / ISO 42001
17+
A.6.2.8 / SOC 2 / NIST AI RMF (as *evidence*, not certification).
18+
- **MCP registry manifest** (`packaging/mcp/server.json`) + `docs/MCP_REGISTRY.md`
19+
so the local MCP firewall can be listed/discovered.
20+
- **OpenSSF Scorecard CI** (supply-chain trust signal) and a clearer
21+
"100% local, zero telemetry" README headline.
22+
23+
## [0.9.1] — 2026-05-28
24+
25+
### Added
26+
27+
- **`burnwall cost-per-pr [--base main] [--json]`** — approximate cost of the
28+
current git branch / PR, by attributing local cross-tool session-log spend to the
29+
branch's active window (oldest commit on `base..HEAD`). Local + git metadata only;
30+
never reads prompt content. Approximate (time-bucketed) and labelled as such.
31+
- **MCP permission auto-policy**`[mcp].auto_approve` and `[mcp].auto_deny` glob
32+
lists (matched against `"<server>/<tool>"`). Auto-deny always blocks; auto-approve
33+
skips the approval gate in enforce mode — cutting approval fatigue. Both opt-in.
34+
- **VS Code inline panel** — the status-bar item now opens a panel
35+
(`Burnwall: Open Panel`) summarising cost-by-model, security blocks, and MCP tools
36+
from the local CLI JSON.
37+
- **Soft budget alert**`burnwall status` shows a non-blocking heads-up once
38+
today's spend crosses the configured warn threshold but is still under the hard
39+
daily limit.
40+
541
## [0.9.0] — 2026-05-28
642

743
### Added

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "burnwall"
3-
version = "0.9.0"
3+
version = "0.9.2"
44
edition = "2021"
55
description = "Local proxy for AI coding tools (Claude Code, Codex CLI, Aider): cache-aware cost tracking, path/command security checks, daily budget enforcement. Zero telemetry."
66
# FSL-1.1-MIT is not an SPDX identifier; crates.io rejects it as `license`,

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22

33
**Track what your AI coding agent costs. Block what it shouldn't touch.**
44

5+
**100% local. Zero telemetry.** No data leaves your machine except the API call you already make. Burnwall is a single binary that runs *in front of* your existing tools — not a hosted gateway your traffic routes through.
6+
57
Burnwall is a local proxy for AI coding tools — Claude Code, Codex CLI, Aider, OpenCode, Cline. It combines cache-aware cost accounting, path-and-command security checks on every tool call, cross-tool spend aggregation, and zero telemetry — without sending your prompts to a SaaS dashboard.
68

9+
**Works with** Claude Code, Cursor, Codex, Aider, OpenRouter, and any OpenAI/Anthropic-compatible gateway — point its base URL at Burnwall. See [`docs/INTEGRATIONS.md`](docs/INTEGRATIONS.md).
10+
711
If you've ever woken up to a four-figure API bill from an agent loop, or wondered whether your agent has been quietly `cat`-ing `~/.ssh/id_rsa` into the context window: Burnwall is the seatbelt.
812

913
```

docs/COMPLIANCE.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Compliance & audit evidence
2+
3+
Burnwall produces **local, metadata-only, tamper-evident** records of what an AI
4+
agent did and was blocked from — useful as *evidence* for AI-governance frameworks.
5+
It is **not** a compliance product and does not make you compliant on its own; it
6+
furnishes artifacts an auditor or underwriter can verify.
7+
8+
## The artifacts
9+
10+
- **Audit receipts** (`burnwall audit seal` / `verify`) — Ed25519-signed,
11+
hash-chained, metadata-only records of every forwarded/blocked action. Each
12+
receipt hashes the source row's contents, so `verify` detects edits to the
13+
underlying data, and the chain detects insertion/deletion/reordering.
14+
- **CycloneDX AI-BOM** (`burnwall audit aibom`) — machine-readable session bill of
15+
materials (models, MCP servers, security activity).
16+
- **SARIF** (`burnwall audit sarif`) — security blocks for GitHub code scanning.
17+
- **OWASP / EU-AI-Act mapping** — see `docs/SECURITY_FRAMEWORKS.md`.
18+
19+
None of these contain prompt content.
20+
21+
## Framework mapping (evidence, not certification)
22+
23+
| Framework / control | What it asks for | Burnwall artifact |
24+
|---|---|---|
25+
| **EU AI Act, Art. 12** (record-keeping / automatic logging) | Automatic, traceable logs of system events over the lifecycle | Audit receipts (`seal`) — signed, chained, per-action |
26+
| **EU AI Act, Art. 19 / 26** (log retention) | Keep logs (≥6 months for deployers) | Retained receipt chain; `audit verify` reports count + oldest sealed date |
27+
| **ISO/IEC 42001, A.6.2.8** (AI event logging) | Immutable, attributable who/what/when records | Audit receipts + `verify` |
28+
| **SOC 2** (CC-series: logging, change/integrity) | Tamper-evident activity + control-enforcement evidence | Receipts (forward/block) + SARIF security events |
29+
| **NIST AI RMF** (Measure/Manage) | Evidence that runtime controls operated | Blocked-action receipts + security events |
30+
31+
Honest caveat: Burnwall is a deployer-side control plane, so it provides
32+
*proof-of-controls evidence*, not full compliance with any framework.
33+
34+
## Independent verification (no Burnwall required)
35+
36+
`burnwall audit export --format json` emits a self-contained bundle:
37+
38+
```json
39+
{
40+
"public_key": "<hex Ed25519 verifying key>",
41+
"count": <n>,
42+
"receipts": [
43+
{
44+
"seq": 1, "sealed_at": "...", "source": "request|security_event",
45+
"source_id": 1, "timestamp": "...", "action": "forward|block|security",
46+
"provider": "...", "model": "...", "detail": "...",
47+
"content_hash": "<sha256 hex of the source row>",
48+
"prev_hash": "<hex>", "hash": "<sha256(prev_hash \\n content_hash) hex>",
49+
"signature": "<ed25519(hash) hex>"
50+
}
51+
]
52+
}
53+
```
54+
55+
A third party (auditor/underwriter) can re-walk the chain and verify every
56+
signature **without trusting the Burnwall binary** using `tools/verify_receipts.py`:
57+
58+
```
59+
burnwall audit export --format json > receipts.json
60+
python tools/verify_receipts.py receipts.json
61+
# → OK — N receipt(s) verified against <pubkey>… (or TAMPERED at seq X)
62+
```
63+
64+
The external verifier checks the chain links + signatures from the export alone
65+
(proving the exported receipts weren't forged, reordered, edited, or deleted after
66+
export). Re-deriving each `content_hash` from the *live* source rows — proving the
67+
underlying data hasn't changed — is what `burnwall audit verify` does locally.

docs/INTEGRATIONS.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Use Burnwall with anything
2+
3+
Burnwall is a **local proxy**: your AI coding agent points its API base URL at
4+
Burnwall (`http://localhost:4100`), Burnwall enforces security + budget and tracks
5+
cost, then forwards to the real provider — or to any **OpenAI- or
6+
Anthropic-compatible** gateway you already use. It runs *in front of* your existing
7+
setup; nothing else changes, and no data leaves your machine beyond the API call you
8+
already make.
9+
10+
Start the proxy:
11+
12+
```
13+
burnwall start # listens on http://localhost:4100
14+
```
15+
16+
Routes: `/anthropic/*`, `/openai/*`, `/google/*`. Your agent's `Authorization` /
17+
`x-api-key` header is forwarded unchanged to the upstream.
18+
19+
## Point an agent or SDK at Burnwall
20+
21+
Most tools and SDKs honour an HTTP base-URL override — usually a single environment
22+
variable. Set it to the matching Burnwall route:
23+
24+
| Tool / SDK | Set | To |
25+
|---|---|---|
26+
| Claude Code / Anthropic SDK / Claude Agent SDK | `ANTHROPIC_BASE_URL` | `http://localhost:4100/anthropic` |
27+
| Codex CLI / OpenAI SDK / OpenAI Agents SDK | `OPENAI_BASE_URL` (or `OPENAI_API_BASE`) | `http://localhost:4100/openai` |
28+
| Google Gemini SDK / ADK | Gemini base URL | `http://localhost:4100/google` |
29+
| LangChain / CrewAI / LlamaIndex | the model's `base_url` | the route for that provider above |
30+
| Cursor / Windsurf / Aider / OpenCode | the tool's "custom API base / OpenAI-compatible URL" setting | the matching route |
31+
32+
The keys stay yours — Burnwall passes the auth header straight through to the
33+
upstream and never logs it.
34+
35+
## Put Burnwall in front of a gateway/router
36+
37+
Already routing through an OpenAI-compatible gateway, router, or proxy? Point
38+
Burnwall's *upstream* at it and keep the local firewall + budget on top:
39+
40+
```
41+
# OpenRouter (OpenAI-compatible): agent → Burnwall → OpenRouter → models
42+
burnwall start --upstream-openai https://openrouter.ai/api/v1
43+
# point the agent at http://localhost:4100/openai with your OpenRouter key
44+
```
45+
46+
```
47+
# Any OpenAI-compatible gateway/proxy (self-hosted or hosted):
48+
burnwall start --upstream-openai https://your-gateway.example/v1
49+
```
50+
51+
```
52+
# Any Anthropic-compatible upstream:
53+
burnwall start --upstream-anthropic https://your-upstream.example
54+
```
55+
56+
The upstream URL is **your config**, not something a request can change. Burnwall
57+
forwards your request unchanged and adds, on the local side: blocking dangerous
58+
file-path / command / secret-exfiltration tool calls before they leave the machine,
59+
hard daily/monthly budget stops, runaway-loop detection, and one local cost view
60+
across every tool — none of which a hosted router can do for you.
61+
62+
## Failover to multiple upstreams
63+
64+
If you run more than one base URL for a provider, configure `[resilience]` so
65+
Burnwall retries the same request against the next endpoint on a connection error
66+
or 5xx. See `docs/SPEC.md`.

docs/MCP_REGISTRY.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Listing the Burnwall MCP firewall
2+
3+
Burnwall's MCP firewall (`burnwall mcp-watch`) is a local pass-through proxy that
4+
sits in front of your MCP servers: it detects tool-poisoning and silent
5+
"rug-pull" definition changes, enforces an approval workflow, and applies the
6+
path/command/secret denylist to `tools/call` arguments — all locally, never
7+
modifying responses.
8+
9+
## Run it
10+
11+
```
12+
burnwall mcp-watch --upstream <your-mcp-server-url> [--port 4101] [--require-approval]
13+
```
14+
15+
Point your MCP client at the watcher's local address instead of the upstream
16+
directly. Multiple servers can be fronted via `[[mcp.servers]]` in
17+
`~/.burnwall/config.toml`; auto-approve/deny globs go under `[mcp]` (see
18+
`docs/SPEC.md`).
19+
20+
## Registry manifest
21+
22+
`packaging/mcp/server.json` is the [MCP registry](https://registry.modelcontextprotocol.io/)
23+
manifest. To publish, install the registry CLI and run `mcp-publisher` from this
24+
repo against `packaging/mcp/server.json` (per the registry's current docs). The
25+
firewall is a security/observability proxy, not a tool server — the manifest
26+
points users at the `burnwall mcp-watch` invocation above.

packaging/mcp/server.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
3+
"name": "io.github.intbot/burnwall-mcp-firewall",
4+
"description": "Local MCP firewall: tool-poisoning + rug-pull detection, an approval workflow, and a path/command/secret denylist on tool-call arguments. Runs in front of your MCP servers; nothing leaves your machine.",
5+
"repository": {
6+
"url": "https://github.com/intbot/burnwall",
7+
"source": "github"
8+
},
9+
"version": "0.9.2",
10+
"packages": [
11+
{
12+
"registryType": "oci",
13+
"identifier": "burnwall",
14+
"transport": { "type": "stdio" },
15+
"comment": "Install the burnwall CLI (brew/cargo/npm/curl — see the repo). The firewall is a passthrough HTTP proxy started with `burnwall mcp-watch --upstream <your-mcp-server-url>`; point your MCP client at the watcher's local address. See docs/MCP_REGISTRY.md."
16+
}
17+
]
18+
}

tools/verify_receipts.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python3
2+
"""Independently verify a Burnwall audit-receipt export — no Burnwall required.
3+
4+
burnwall audit export --format json > receipts.json
5+
python tools/verify_receipts.py receipts.json
6+
7+
Re-walks the Ed25519 hash chain in the export and verifies every signature
8+
against the embedded public key. This proves the exported receipts were not
9+
forged, reordered, edited, or deleted after export — without trusting the
10+
burnwall binary. (Re-deriving each content_hash from the live source rows —
11+
proving the underlying data is unchanged — is `burnwall audit verify`'s job.)
12+
13+
Chain definition (must match src/audit/mod.rs):
14+
hash = SHA-256( prev_hash_hex || "\\n" || content_hash_hex ) # ASCII bytes
15+
signature = Ed25519(hash_hex_bytes) # over the hex string
16+
genesis prev_hash = 64 zeros
17+
18+
Requires: pip install cryptography
19+
Exit code: 0 = intact, 1 = tampered, 2 = usage/format error.
20+
"""
21+
22+
import hashlib
23+
import json
24+
import sys
25+
26+
try:
27+
from cryptography.exceptions import InvalidSignature
28+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
29+
except ImportError:
30+
sys.exit("error: needs `pip install cryptography`")
31+
32+
GENESIS = "0" * 64
33+
34+
35+
def fail(seq, why):
36+
print(f"TAMPERED at seq {seq}: {why}", file=sys.stderr)
37+
sys.exit(1)
38+
39+
40+
def main():
41+
if len(sys.argv) != 2:
42+
print("usage: verify_receipts.py <export.json>", file=sys.stderr)
43+
sys.exit(2)
44+
45+
with open(sys.argv[1], encoding="utf-8") as fh:
46+
data = json.load(fh)
47+
48+
pub_hex = data.get("public_key")
49+
if not pub_hex:
50+
print("error: export has no public_key", file=sys.stderr)
51+
sys.exit(2)
52+
pub = Ed25519PublicKey.from_public_bytes(bytes.fromhex(pub_hex))
53+
54+
receipts = sorted(data.get("receipts", []), key=lambda r: r["seq"])
55+
prev = GENESIS
56+
for r in receipts:
57+
if r["prev_hash"] != prev:
58+
fail(r.get("seq"), "broken chain link (a receipt was inserted, deleted, or reordered)")
59+
digest = hashlib.sha256()
60+
digest.update(prev.encode("ascii"))
61+
digest.update(b"\n")
62+
digest.update(r["content_hash"].encode("ascii"))
63+
if digest.hexdigest() != r["hash"]:
64+
fail(r.get("seq"), "hash does not match its contents")
65+
try:
66+
pub.verify(bytes.fromhex(r["signature"]), r["hash"].encode("ascii"))
67+
except InvalidSignature:
68+
fail(r.get("seq"), "signature does not verify (forged or wrong key)")
69+
prev = r["hash"]
70+
71+
print(f"OK — {len(receipts)} receipt(s) verified against {pub_hex[:16]}…")
72+
73+
74+
if __name__ == "__main__":
75+
main()

0 commit comments

Comments
 (0)