Commit Graph

3 Commits

Author SHA1 Message Date
didericis f77023db1d refactor(gateway): move the data-plane daemons into a bot_bottle.gateway package
test / integration-docker (pull_request) Successful in 11s
test / unit (pull_request) Successful in 43s
lint / lint (push) Successful in 56s
test / integration-firecracker (pull_request) Successful in 3m19s
test / coverage (pull_request) Successful in 19s
test / publish-infra (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Successful in 7s
Separate the gateway (data plane) from the orchestrator (control plane) at the
module level. The gateway runtime files move out of the package root — and the
backend-neutral Gateway lifecycle ABC + GATEWAY_* constants move out of
orchestrator/ — into a new bot_bottle/gateway/ package:

  gateway/__init__.py      (was orchestrator/gateway.py: Gateway ABC + consts
                            + rotate_gateway_ca)
  gateway/gateway_init.py  (the PID-1 daemon supervisor)
  gateway/egress_addon.py, egress_addon_core.py, egress_dlp_config.py,
          dlp_detectors.py            (the egress mitmproxy daemon)
  gateway/git_http_backend.py         (the git-http daemon)
  gateway/git_gate_render.py          (the git-gate pre-receive rendering)
  gateway/supervise_server.py         (the supervise MCP daemon)
  gateway/policy_resolver.py          (the data-plane control-plane RPC client)

orchestrator/ now holds only control-plane files. The shared plan/types/auth
layer (egress.py=EgressPlan, git_gate.py=GitGatePlan, supervise.py,
supervise_types.py, control_auth.py) and the launch-time git-gate provisioning
helpers stay at root, so orchestrator/ and backend/ still own them.

Because these daemons are invoked as `python3 -m bot_bottle.<name>`, loaded flat
by mitmproxy, and referenced in Dockerfile.gateway, the move updates more than
Python imports: the `-m` invocations (firecracker/macOS infra scripts), the
Dockerfile.gateway addon shim + ENTRYPOINT, gateway_init's _DAEMONS module
paths, and the git-gate CGI heredocs all now point at bot_bottle.gateway.*.

No behavior change; full unit suite green (2251).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 13:25:10 -04:00
didericis c839cee319 test(orchestrator): skip multitenant isolation under act_runner
test / unit (pull_request) Successful in 1m3s
test / integration (pull_request) Successful in 20s
test / coverage (pull_request) Successful in 1m13s
lint / lint (push) Successful in 2m17s
test / unit (push) Successful in 1m5s
test / integration (push) Successful in 31s
test / coverage (push) Successful in 1m22s
Update Quality Badges / update-badges (push) Successful in 1m15s
The test brings up the orchestrator container, which bind-mounts the repo
path into a container on the host daemon. Under the Gitea act_runner the job
runs in a container sharing the host docker socket, so that path
(/workspace/...) doesn't exist on the host daemon and the mount fails
('mkdir /workspace: read-only file system'). Same host-bind-mount constraint
that already skips test_sandbox_escape and the other bottle-bringup tests, so
gate it the same way (GITEA_ACTIONS). Runs for real on a normal docker host.

This unblocks the integration + coverage CI jobs, which failed only because
this test errored (coverage.sh runs under set -e; no percentage gate tripped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
2026-07-14 03:15:26 -04:00
didericis ea75fab3b4 fix(orchestrator): supersede a prior active bottle at the same source IP
test / unit (pull_request) Successful in 1m4s
test / integration (pull_request) Failing after 30s
test / coverage (pull_request) Failing after 1m17s
register() used INSERT OR REPLACE keyed on bottle_id, so re-registering an
existing source_ip with a new bottle_id left TWO active rows for that IP.
by_source_ip fail-closes on ambiguity (>1 active -> None), so the reused IP
was then bricked to a 403 on egress resolve — even for hosts its own policy
allowed. Happy path (fresh IPs, teardown on stop) never hit it, but IP reuse,
crash recovery, or a persisted registry DB across an orchestrator restart
(now that ensure_running always recreates the container) all could.

register() now deletes any other active row at the same source_ip before
insert; the fail-closed ambiguity guard stays as defense in depth. Adds a
unit test for the supersede, and a docker integration test
(test_multitenant_isolation) that drives two bottles through one shared
gateway and asserts each gets only its own injected token and its own
allowlist — the core PRD 0070 multi-tenancy invariant, previously only
verified by hand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WBMWTEtQdJ4W5UrWuLHCck
2026-07-14 02:38:20 -04:00