From e2422c20a05c8363cd37d6cbeb80d669f7b4895a Mon Sep 17 00:00:00 2001 From: didericis Date: Sat, 6 Jun 2026 16:10:30 -0400 Subject: [PATCH 1/3] docs: document egress matches, dlp fields, and detector defaults --- README.md | 26 ++++++++++++++++++++++++-- examples/bottles/claude.md | 7 ++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 559ac42..97c28b3 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,21 @@ skills: You help maintain Gitea-hosted projects. ```` +**Egress route fields:** + +| Field | Required | Description | +|---|---|---| +| `host` | yes | Hostname to allowlist. One entry per host. | +| `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`). | + 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..219d0db 100644 --- a/examples/bottles/claude.md +++ b/examples/bottles/claude.md @@ -5,10 +5,15 @@ agent_provider: egress: routes: - host: api.anthropic.com - role: claude_code_oauth + role: claude_code_oauth # wires Claude Code OAuth; do not change auth: scheme: Bearer token_ref: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN + # dlp is omitted → all detectors on by default (token_patterns, + # known_secrets outbound; naive_injection_detection inbound). + # To disable inbound scanning for this route: + # dlp: + # inbound_detectors: false --- Common Claude provider boundary. Drop this file into -- 2.52.0 From c41751f3b9970119ef64150014dfe7afe5b70487 Mon Sep 17 00:00:00 2001 From: claude Date: Mon, 22 Jun 2026 18:31:32 +0000 Subject: [PATCH 2/3] docs: add role and git.fetch to egress route fields table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both fields were missing from the reference table added in the preceding commit — `role` is visible in examples/bottles/claude.md and `git.fetch` is documented in PRD 0052 but neither appeared in the README table. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 97c28b3..415b915 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ You help maintain Gitea-hosted projects. | Field | Required | Description | |---|---|---| | `host` | yes | Hostname to allowlist. One entry per host. | +| `role` | no | Provider-specific role string (e.g. `claude_code_oauth`). Wires built-in auth flows; set by provider templates, not manually. | | `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. | @@ -147,6 +148,7 @@ You help maintain Gitea-hosted projects. | `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`. -- 2.52.0 From 31cde11b0da1b0daac13352a9b6d237f0d7fd793 Mon Sep 17 00:00:00 2001 From: didericis Date: Tue, 23 Jun 2026 17:53:18 -0400 Subject: [PATCH 3/3] docs: correct stale role field and claude provider auth example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The egress route fields table described `role` as a functional field that wires built-in auth flows. PRD 0029 removed the `claude_code_oauth` role; the manifest parser now rejects any `role` value as reserved-for-future-use. Provider auth routes are injected from `agent_provider.auth_token`. - README: fix the `role` row to state it is reserved and any value is rejected at load. - examples/bottles/claude.md: the manual `api.anthropic.com` route used the rejected `role` key and, even without it, would be silently dropped (provider-injected routes win for a provisioned host) — so its auth never took effect and the dlp comments described a route that never exists in the plan. Replace it with the canonical `agent_provider.auth_token` shape. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01YcU7nerbg8cVj9R4EkpfLJ --- README.md | 2 +- examples/bottles/claude.md | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 415b915..f2ad087 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ You help maintain Gitea-hosted projects. | Field | Required | Description | |---|---|---| | `host` | yes | Hostname to allowlist. One entry per host. | -| `role` | no | Provider-specific role string (e.g. `claude_code_oauth`). Wires built-in auth flows; set by provider templates, not manually. | +| `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. | diff --git a/examples/bottles/claude.md b/examples/bottles/claude.md index 219d0db..9f9670b 100644 --- a/examples/bottles/claude.md +++ b/examples/bottles/claude.md @@ -1,19 +1,14 @@ --- agent_provider: template: claude - -egress: - routes: - - host: api.anthropic.com - role: claude_code_oauth # wires Claude Code OAuth; do not change - auth: - scheme: Bearer - token_ref: BOT_BOTTLE_CLAUDE_OAUTH_TOKEN - # dlp is omitted → all detectors on by default (token_patterns, - # known_secrets outbound; naive_injection_detection inbound). - # To disable inbound scanning for this route: - # dlp: - # inbound_detectors: false + # 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 -- 2.52.0