Files
bot-bottle/docs/prds
didericis-claude 8a1b833aaa fix(gateway): persist mitmproxy CA on the host, not a named volume (#450)
The shared gateway self-generates a mitmproxy CA that every bottle installs
to trust its TLS interception. It was persisted on a Docker named volume,
which survives `docker rm` but is silently wiped by `docker volume prune` /
`docker system prune --volumes` during routine host maintenance. When that
happens the gateway mints a fresh CA on restart, and every already-running
bottle fails the TLS handshake even after it re-resolves and reconnects to
the moved gateway — a re-attachment blocker distinct from #443/#445.

Move CA persistence to a host bind-mount under the app-data root
(`bot_bottle_root()/gateway-ca`, via `host_gateway_ca_dir()`), mirroring how
the shared DB and control-plane token already live on the host. Docker never
prunes a path under the root, and it stays inspectable + rotatable from the
host. mitmproxy already adopts an existing CA and generates one only on first
run, so the bind-mount gives adopt-existing/generate-on-first-run for free.

Add an explicit rollover path: `rotate_gateway_ca()` clears the persisted CA
so the next start remints it, and `python -m bot_bottle.orchestrator.rotate_ca`
wires that together with dropping the running gateway container (whose
mitmproxy still holds the old CA in memory). Rotation stays an operator action
— it doesn't auto-re-provision running bottles, which re-attach to pick up the
new anchor.

Scope: the Docker infra/gateway path (the "infra container" in the report).
The macOS (`container`-only volume) and Firecracker (VM-attached ext4) backends
persist the CA differently and are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 15:01:38 -04:00
..
2026-05-07 22:45:36 -04:00

Product requirement docs

One PRD per feature: what to build, why, and how it's scoped. The PRD is the durable spec — it should stand on its own without a Gitea issue thread (see ../README.md for when a PRD is the right document vs. a research note or a decision record).

Naming and numbering

New PRDs use a prd-new-<kebab-title>.md placeholder name while the PR is open. On merge to main a CI workflow assigns the next sequential number (0024-…, 0025-…), renames the file, and updates the title header. Numbers are never reused; gaps are fine.

Once numbered, the filename stays fixed for the life of the doc.

Status

The Status: line near the top tracks the PRD's lifecycle:

  • Draft — proposed, not yet shipped.
  • Active — the design has shipped to main and is in effect.
  • Superseded by PRD NNNN — replaced by a later PRD; kept for history.
  • Retargeted by PRD NNNN — folded into a later PRD's scope.

Format

# PRD prd-new: <short title>    ← placeholder; CI fills in the number on merge

- **Status:** Draft
- **Author:** <who>
- **Created:** YYYY-MM-DD
- **Issue:** #<n>            # optional — convenience pointer only

## Summary
One paragraph: what this builds and the pain it solves.

## Problem
The current state and why it's inadequate.

## Goals / Success Criteria
Bullets a reviewer can check the finished work against.

## Non-goals
What this explicitly does not do — and won't, to head off scope creep.

## Scope
In scope / out of scope, when the boundary needs spelling out.

## Design
How it works: schema, data flow, diagrams, algorithms as needed.

## Implementation chunks
Ordered, mergeable steps (optional; for multi-PR features).

## Open questions
Unresolved decisions — resolve or fold into Design before shipping.

Sections are a guide, not a straitjacket: drop the ones a given PRD doesn't need (a small change rarely needs Scope or Implementation chunks) and add others where they help (e.g. Testing strategy, Alternatives considered, References). Keep the rationale self-contained — inline the reasoning rather than linking out to an issue thread, so the PRD survives a move off Gitea.