Skip to content

v0.9.8: status ribbon, deeper security, audit + pricing overrides#7

Closed
codehippie1 wants to merge 23 commits into
release/v0.9.2from
release/v0.9.x
Closed

v0.9.8: status ribbon, deeper security, audit + pricing overrides#7
codehippie1 wants to merge 23 commits into
release/v0.9.2from
release/v0.9.x

Conversation

@codehippie1

Copy link
Copy Markdown
Contributor

Cumulative changes on the v0.9.x line (since v0.9.2). Continues from #6 (closed when the head branch was renamed release/v0.9.3release/v0.9.x).

Cost

  • Local ~/.burnwall/pricing.toml overrides + signed remote pricing cards (pricing list / update / sign / verify).
  • burnwall savings — your own measured cache savings + models underusing caching.
  • Per-session / swarm budget ceiling (budget.per_session, opt-in via an x-burnwall-session request header).

Status surfaces

  • burnwall statusline — ribbon for Claude Code's customizable status line (model · ↑↓ tokens · msg/session/today cost · context bar), with an honest context gauge (exact / estimated / hidden).
  • burnwall watch — live cross-tool ribbon for a spare terminal pane.
  • status protection heartbeat + per-session breakdown.

Security

  • Catastrophic-command detection by shape — recursive-force deletes, disk destruction (dd of=/dev/…, mkfs), destructive SQL — caught regardless of flag order/spacing/target expansion.
  • Data-exfiltration technique detection (DNS exfil, secret-file-piped-to-network), opt-in under security.dlp.
  • Whitespace-normalized command matching; MCP firewall validated against published attack PoCs.

Resilience & install

  • Graceful-degradation layers: BURNWALL_BYPASS kill-switch, panic-catching wrapper, per-platform crash-loop bounds, self-rollback, and a sourced env-file activation model.
  • enable-routing / disable-routing, install-service / uninstall-service (Windows uses a no-admin HKCU\…\Run entry), /healthz, and an extended init.
  • burnwall sidecar — run the proxy as a co-located egress point for an agent that executes off your laptop (self-hosted sandbox / CI).

Trust & audit

  • Release binaries carry GitHub Artifact Attestations (SLSA Build L2); SECURITY.md documents integrity + TLS handling (rustls, no CA injection), with verify recipes.
  • burnwall audit pack — bundled signed receipts + CycloneDX AIBOM + SARIF, mapped to common frameworks.
  • burnwall share — opt-in, signed, screenshot-friendly value card.

Tests pass offline (495); clippy -D warnings clean; lean build OK.

… hardening

- Migrate to the Rust 2024 edition; declare an MSRV; move lint policy into Cargo.toml.
- Add optional build features (audit/mcp/observe/logscrape/waste), all default-on;
  `cargo build --no-default-features` now produces a lean core-proxy build.
- Make path/command security rules case- and separator-insensitive so `~/.SSH`
  and mixed-separator Windows paths cannot bypass a `~/.ssh` deny rule.
- Forward --upstream-google and --rewrite-anthropic-cache through `start --daemon`.
- Add opt-in cost-spiral enforcement via [loop_detection].cost_spiral_enforce (off by default).
- Harden SQLite (WAL + busy_timeout, poisoned-lock recovery, response-path writes off the async runtime).
- Deduplicate repository.rs row-mappers.
Pricing
- Load ~/.burnwall/pricing.toml to override or add model rates without a
  release; entries take precedence over the built-in card and tolerate
  date-suffixed model IDs. Loaded once at startup, fail-open on a bad file.
- `burnwall pricing list/path` to inspect the effective card and scaffold
  the override file; status surfaces the active-override count.
- Signed remote cards: `burnwall pricing update` fetches a card over HTTPS
  and installs it only if its detached Ed25519 signature verifies against a
  trusted [pricing].publishers key (verify-before-parse, no fail-open).
  `pricing sign/verify` cover the publisher and offline-check sides.

Resilience + install
- Five-layer graceful degradation so a bad release can't break AI tools:
  BURNWALL_BYPASS kill-switch, panic-catching wrapper (502 + hint),
  per-platform crash-loop circuit breakers, `self-rollback`, and a sourced
  env-file activation model with one-place revert.
- `enable-routing`/`disable-routing` (env file + rc hook + eval activation),
  `install-service`/`uninstall-service` (launchd/systemd/Scheduled Task),
  `/healthz` probe, and an extended two-step `init` flow.
… service

Bump version to 0.9.4 across Cargo.toml/lock, the VS Code extension, and the
MCP server manifest; date the CHANGELOG section.
Status ribbon
- New `burnwall statusline`: renders the Burnwall ribbon for Claude Code's
  customizable status line from its per-turn stdin JSON, enriched with
  cross-tool spend and security-block counts from the proxy DB. One-line
  settings.json wiring; fail-open on bad input.
- Canonical ribbon renderer (src/ribbon.rs) with an honest context gauge:
  exact when the tool reports it, ~marked when estimated, — when untrusted,
  omitted when the tool shows its own. Reused by upcoming surfaces.
- Proxy touches <data dir>/watch.signal after each recorded turn (off the
  response path) — groundwork for event-driven refresh.

Fix
- Windows install-service no longer needs admin: default to a per-user
  HKCU\...\Run entry launching `burnwall start --daemon` at logon; `--task`
  opts into the elevated Scheduled-Task variant (crash-restart).
  uninstall-service removes whichever was installed.
- New `burnwall watch`: a live status ribbon for a spare terminal pane,
  rendering the same ribbon as the Claude Code status line but for every
  tool that routes through the proxy (Codex/Gemini/Aider), sourced from the
  local DB. --oneline / --once / --interval. Refreshes event-driven off the
  watch.signal marker with a periodic fallback. Headline = today's spend
  across all tools.
- Ribbon cost fields (sess/today) are now optional so the cross-tool view
  shows per-message + today without a misleading session figure; context
  gauge stays honest (estimate ~, or — when untrusted).
- storage::most_recent_request for the DB-sourced ribbon.
Security depth
- Data-exfiltration technique detection (opt-in under security.dlp): DNS
  exfil, secret-file piped to network, command-substituted uploads. Names
  the technique, never the data; conservative/high-signal.
- `burnwall security --summary`: a "what Burnwall caught" receipt grouped by
  type, so passive protection registers as ongoing value.
- MCP firewall validated against the published attacks (Invariant tool-
  poisoning/SSH exfil, MCPoison rug-pull, <IMPORTANT> shadowing) as a test
  corpus.

Governance
- `burnwall audit pack`: one-command evidence bundle (signed receipts +
  CycloneDX 1.6 AIBOM + SARIF 2.1.0 + a MANIFEST mapping artifacts to ISO
  42001 / EU AI Act / FINRA).

Docs
- README: Trust & privacy, defense-in-depth framing, and the built-in
  mcp-watch firewall in the MCP scope note.
…ITY.md)

- cargo-dist github-attestations=true + README verify recipes + SECURITY.md
- burnwall savings: self-measured cache savings + underused-cache opportunity
- status protection heartbeat (proxy-running self-test)
- TLS-integrity guard test (no cert-validation weakening / CA injection in src)
…dgets, session attribution)

- destructive-command detection by shape (recursive-force rm, disk destroy,
  drop/truncate) — catches reordered/spaced/expanded forms the literal
  deny-list misses
- command_matches whitespace-normalized so padding can't evade literal rules
- per-session/swarm budget ceiling (budget.per_session) keyed on opt-in
  x-burnwall-session header; enforced in handler, recorded off the response path
- per-session cost capture + 'by session' view in status
…ion, swarm budgets, attestations

Iter 1 (trust + ROI): cargo-dist attestations + SECURITY.md + README verify;
  burnwall savings (self-measured cache savings + opportunity); status
  protection heartbeat; TLS-integrity guard test.
Iter 2 (security depth): catastrophic-command detection by shape; exfil
  technique detection (opt-in); whitespace-normalized command matching;
  per-session/swarm budget ceiling + session attribution.
Iter 3 (frontier): burnwall sidecar (co-located egress for off-laptop
  sandboxes/CI); burnwall share (opt-in signed value card).
One command to move to the latest release: stops the proxy (a running
burnwall.exe can't be overwritten on Windows), installs, restarts. On
Windows renames its own running binary aside so the installer can write the
new one (restores on failure). --dry-run / --no-restart. Mirror of
self-rollback.
- `burnwall init --apply` now merges a `statusLine` block into
  ~/.claude/settings.json when Claude Code is detected. Idempotent,
  preserves your other settings, writes the PATH-resolved
  `burnwall statusline` command, and never overwrites a status line you
  already configured.
- new `burnwall uninstall` reverses everything install + init set up: stops
  the proxy, removes the login service, the Claude Code status line, shell
  routing (env file + rc hook), and the binary. Cost history is kept unless
  `--purge`. Confirms first (skip with `--yes`); refuses non-interactive
  without `--yes`.
- bump 0.9.9 -> 0.9.10 (Cargo, vscode, mcp server.json, CHANGELOG).
…us + lint

- Subscription-aware status across every surface: the proxy reads Anthropic
  unified-* rate-limit headers and shows 5h/7d usage headroom on the statusline,
  burnwall watch, watch --title, and the IDE extension, instead of notional
  dollars for flat-rate plans. Auto-detected; API users keep the dollar view.
- Coverage transparency: per-tool readout (protected / installed-not-seen /
  bypasses) in init, status, watch, and the IDE extension; warns plainly when a
  ChatGPT-login Codex bypasses the proxy (with the cost-aware caveat).
- Ribbon wordmark; opus-4.8[1M] model-label fix.
- Official rule packs grown 4 -> 8 (added node, python, go, kubernetes; fleshed
  out django/react/infrastructure/data-science; ~61 rules).
- burnwall rules lint: registry-acceptance linter (forbidden/unknown keys and
  over-broad/uncompilable rules are hard errors; --sig, --json, non-zero exit);
  bundled official packs are gated by it in CI.
- Docs: README documents the coverage boundary; CLI design spec moved to private
  design notes.
- install.sh fetched `.tar.gz` but releases ship `.tar.xz`, extracted with gzip,
  and looked for the binary at the archive root — the documented `curl | sh`
  path was 404-ing. Now downloads `.tar.xz`, extracts with `-xJf`, and locates
  the binary inside the `burnwall-<target>/` subdir (verified against the v0.9.11
  archive layout). Also drops the stale Linux-arm64 guard — that target IS built
  and published.
- README manual-download list: `.tar.gz` -> `.tar.xz`, plus the Linux-arm64 archive.
- release.yml: retry build-provenance attestation up to 3x (Sigstore's tlog
  intermittently returns a transient "error fetching tlog entry" that failed the
  v0.9.11 build until a manual re-run). Attestation stays mandatory — the final
  attempt still fails the job if Sigstore is genuinely down.
The proxy scan applied every rule to every string leaf of the request,
so prose that merely mentioned a denied path or command - a system
prompt, chat text, a tool definition, a tool result - returned 403. A
project CLAUDE.md documenting its own deny list (e.g. ~/.ssh) made
every Claude Code request from that repo fail, surfacing as a bogus
"run /login" auth error.

scan_request() now applies path/command/mount/destructive/exfil rules
only inside tool-call argument subtrees (Anthropic tool_use.input incl.
server/mcp variants, OpenAI tool_calls / function_call / Responses-API
arguments, Gemini functionCall). Secret detection and DLP still scan
every leaf - a credential or card number is worth blocking wherever it
sits. MCP tools/call bodies and `rules test` keep the strict whole-body
scan via the unchanged scan().
`burnwall stop` left ANTHROPIC_BASE_URL/OPENAI_BASE_URL exported at the
stopped proxy, so every AI tool died with ConnectionRefused until the
user discovered disable-routing. Now:

- `stop` pauses routing: active env files become a paused stub (distinct
  from disable-routing's explicit stub), with a warning that already-
  open terminals keep the vars plus the exact unset command - one that
  does NOT flip the persistent state, unlike `disable-routing --eval`.
  Runs even when no proxy was found (a crashed daemon strands routing
  too). Opt out with --keep-routing.
- `start` resumes routing once the port is bound: paused/missing env
  files are re-enabled, active ones refreshed with the current proxy
  URL (picks up a port change), and an explicit disable-routing is
  respected and reported. Never wires up a never-configured shell.
  Opt out with --no-routing. A foreground start pauses routing again
  on its way out (Ctrl-C), mirroring stop.
- `start --daemon`: the launcher resumes routing after the child
  reports ready (the detached child gets --no-routing, its output goes
  nowhere).
- `upgrade` keeps routing across its transient stop/restart, but pauses
  it on every path that ends with the proxy still down (--no-restart or
  a failed restart). `sidecar` never touches local shell routing;
  `uninstall` skips the pause since it tears routing down fully anyway.
- `status`'s not-routed hint now points at `burnwall start` when
  routing is merely paused, instead of enable-routing.
…ound

Clients resend the full conversation on every request, so one (correctly)
blocked tool call re-triggered the 403 forever - the only escapes were a
new conversation, BURNWALL_BYPASS, or uninstalling. A block was a death
sentence for the session, which in practice trains users to turn the
firewall off.

scan_request now applies command-shaped rules only to the latest
assistant/model turn, and only while its round is in flight (followed by
nothing but tool results - the moment a forbidden read's output would
leave the machine). Once the user sends a new message the round is
adjudicated history: data checks (secrets, DLP) still cover every turn,
but the old call can't re-block. A new dangerous call in the latest turn
still blocks, so recovery is not a loophole. Covers Anthropic
(messages/tool_result), OpenAI (messages/role:tool), and Gemini
(contents/functionResponse) turn shapes; arrays without roles keep the
conservative scan-everything behavior.
Both released 2026-06-09. claude-fable-5 (the tier above Opus): $10/$50
per MTok, cache write $12.50 (1.25x), cache read $1.00 (0.1x), 1M
context. claude-opus-4-8: standard Opus $5/$25 rates.

Pricing lookup now also strips bracket variant tags: Claude Code requests
the 1M-context tier as `claude-fable-5[1m]`, which previously fell
through to "unknown model" and recorded cost as unknown.
…ells

The banner-only stub that uninstall left behind was residue on a machine
the user asked to clean, and because fish/PowerShell are detected as
"configured" by env-file presence, the stub made them count as wired
forever (e.g. start's routing resume kept reporting them). The rc hook is
removed in the same pass and is Test-Path-guarded anyway, so deleting the
file outright is safe - even a hook that survives (PowerShell profiles
are never auto-edited) sources nothing.

Uninstall also now states the one thing it cannot do - pull env vars out
of terminals that are already open - and prints the per-shell unset
command, instead of leaving those shells to fail with ConnectionRefused.
@codehippie1

Copy link
Copy Markdown
Contributor Author

Superseded: this release branch was reconciled onto main via #12 (merge commit 6b9e53e). Every commit from this branch is contained in main (verified by patch-id), so there is nothing left to merge here. Closing as landed-upstream.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant