fix(supervise): reach the queue over RPC, get bot-bottle.db off the data plane
lint / lint (push) Failing after 57s
tracker-policy-pr / check-pr (pull_request) Successful in 14s
test / unit (pull_request) Failing after 37s
test / integration-docker (pull_request) Successful in 38s
test / integration-firecracker (pull_request) Successful in 3m16s
test / coverage (pull_request) Has been skipped
test / publish-infra (pull_request) Has been skipped
lint / lint (push) Failing after 57s
tracker-policy-pr / check-pr (pull_request) Successful in 14s
test / unit (pull_request) Failing after 37s
test / integration-docker (pull_request) Successful in 38s
test / integration-firecracker (pull_request) Successful in 3m16s
test / coverage (pull_request) Has been skipped
test / publish-infra (pull_request) Has been skipped
PRD 0070's rule — only the orchestrator opens bot-bottle.db; the data plane reaches state through the control-plane RPC — was not in force. Three data-plane daemons held a direct read-write handle on the shared SQLite file: the supervise MCP server, the egress DLP addon (the most attack-exposed process, TLS-bumping hostile traffic), and the git-gate pre-receive hook. An RCE in any of them could read every bottle's plaintext identity_token and forge attribution fleet-wide (issue #469). Add the agent half of the supervise flow to the control plane: POST /supervise/propose -> queue a proposal, 201 {proposal_id} POST /supervise/poll -> non-blocking decision poll, 200 {status,...} Both attribute the caller by (source_ip, identity_token) exactly like /resolve — never a caller-supplied slug — so a bottle can only ever queue or read its own proposals even if the data plane is compromised. A decided poll archives server-side, preserving the archive-after-read contract. Data plane: the supervise server, egress addon, and git-gate hook now queue/poll through PolicyResolver.propose_supervise / poll_supervise instead of opening the DB. supervise_server keeps its ~30s grace window by polling the RPC; egress keeps its safelist keyed by resolved bottle; the git-gate hook gets (source_ip, identity_token) from the CGI env. Packaging: drop the DB bind-mount and SUPERVISE_DB_PATH from the data-plane containers/VMs (docker gateway + infra, macOS infra, firecracker infra). The orchestrator remains the sole opener of the one file via BOT_BOTTLE_ROOT / host_db_path(). Update PRD 0070: the rule is now in force; remove the transitional caveat. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -124,13 +124,11 @@ class TestDockerGateway(unittest.TestCase):
|
||||
src = ca_mounts[0].rsplit(":", 1)[0]
|
||||
self.assertTrue(src.endswith("/" + GATEWAY_CA_DIRNAME), src)
|
||||
self.assertTrue(Path(src).is_absolute(), src)
|
||||
# Shares the ONE host DB: the supervise daemon queues into the same
|
||||
# file the orchestrator + operator (over HTTP) use.
|
||||
self.assertTrue(any(
|
||||
a.startswith("SUPERVISE_DB_PATH=") and a.endswith("/run/supervise/bot-bottle.db")
|
||||
for a in runs[0]))
|
||||
self.assertTrue(any(
|
||||
a.endswith(":/run/supervise") for a in runs[0]))
|
||||
# No DB handle on the data plane: the supervise queue is reached over
|
||||
# the control-plane RPC, so the gateway container carries neither the
|
||||
# DB bind-mount nor SUPERVISE_DB_PATH (PRD 0070 / issue #469).
|
||||
self.assertFalse(any(a.startswith("SUPERVISE_DB_PATH=") for a in runs[0]))
|
||||
self.assertFalse(any(a.endswith(":/run/supervise") for a in runs[0]))
|
||||
# Data plane resolves policy against the orchestrator control plane.
|
||||
self.assertIn(f"BOT_BOTTLE_ORCHESTRATOR_URL={_ORCH_URL}", runs[0])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user