diff --git a/README.md b/README.md index 559ac42..f2ad087 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ ## Features -- **Per-bottle egress allowlist** — TLS-bumped HTTP/HTTPS chokepoint with a per-manifest host allowlist and request-body DLP scanner; DoH and arbitrary hosts blocked by default. +- **Per-bottle egress allowlist** — TLS-bumped HTTP/HTTPS chokepoint with a per-manifest host allowlist; per-route path/method/header `matches` filtering; outbound DLP scanning for known tokens and secrets, inbound DLP scanning for prompt-injection attempts; DoH and arbitrary hosts blocked by default. - **Tokens the agent never sees** — host secrets live in a sidecar; the agent dials `http://sidecar:9099/` and the proxy strips inbound `Authorization` and injects the real token before forwarding. `printenv` in the agent shows proxy URLs only. - **Gitleaks-scanned push (git-gate)** — `bottle.git` remotes route through a per-bottle `git daemon` that gitleaks-scans incoming refs pre-receive and forwards clean refs upstream over SSH. The agent never holds the upstream credential. - **Manifest-scoped skills + secrets** — each bottle declares its skills, env, git identity, remotes, and egress routes; unknown keys die at load. @@ -106,8 +106,15 @@ egress: routes: - host: gitea.dideric.is auth: - scheme: token + scheme: token # Bearer | token token_ref: BOT_BOTTLE_GITEA_TOKEN + matches: # optional — restrict to specific paths/methods/headers + - paths: + - {type: prefix, value: /api/v1/} + methods: [GET, POST, PATCH, DELETE] + dlp: # optional — per-route detector overrides (default: all on) + outbound_detectors: [token_patterns, known_secrets] + inbound_detectors: false # disable response scanning for this host --- The `gitea-dev` bottle. Provider auth via the inherited Claude route; @@ -126,6 +133,23 @@ skills: You help maintain Gitea-hosted projects. ```` +**Egress route fields:** + +| Field | Required | Description | +|---|---|---| +| `host` | yes | Hostname to allowlist. One entry per host. | +| `role` | no | Reserved for future use. The key is recognised but any value is currently rejected at load. Provider auth routes (e.g. Claude's `api.anthropic.com`) are injected automatically from `agent_provider.auth_token`, not via `role`. | +| `auth.scheme` | when `auth` present | `Bearer` or `token`. Injected by the proxy; the agent never sees the value. | +| `auth.token_ref` | when `auth` present | Env-var name holding the secret on the host. | +| `matches` | no | Array of `{paths, methods, headers}` filters. A request must match at least one entry (if any are given) to be forwarded. | +| `matches[].paths` | no | Array of `{type, value}`. `type` is `prefix` (default), `exact`, or `regex`. | +| `matches[].methods` | no | Array of HTTP method strings, e.g. `[GET, POST]`. | +| `matches[].headers` | no | Array of `{name, value, type}`. `type` is `exact` (default) or `regex`. | +| `dlp` | no | Per-route DLP overrides. Omit to use defaults (all detectors on). | +| `dlp.outbound_detectors` | no | `false` disables outbound scanning; list restricts to named detectors (`token_patterns`, `known_secrets`). | +| `dlp.inbound_detectors` | no | `false` disables inbound scanning; list restricts to named detectors (`naive_injection_detection`). | +| `git.fetch` | no | `true` permits smart HTTP clone/fetch (`git-upload-pack`) for this host. Push (`git-receive-pack`) remains blocked. | + More examples in `examples/`. Full design lives under `docs/prds/`; the trust-boundary rationale is in `docs/prds/0011-per-file-md-manifest.md`. ## Trademarks diff --git a/examples/bottles/claude.md b/examples/bottles/claude.md index b7e5d8f..9f9670b 100644 --- a/examples/bottles/claude.md +++ b/examples/bottles/claude.md @@ -1,14 +1,14 @@ --- agent_provider: template: claude - -egress: - routes: - - host: api.anthropic.com - role: claude_code_oauth - auth: - scheme: Bearer - token_ref: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN + # auth_token names the host env var holding the Claude OAuth token. The + # provider injects a provider-owned api.anthropic.com egress route that + # re-injects this token as the Bearer header; the agent only ever sees a + # placeholder CLAUDE_CODE_OAUTH_TOKEN. DLP defaults (token_patterns, + # known_secrets outbound; naive_injection_detection inbound) apply to + # that route. To scan additional hosts, declare them under egress.routes + # with per-route matches/dlp (see README "Egress route fields"). + auth_token: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN --- Common Claude provider boundary. Drop this file into