5f1d3fbd15e1498cc37c8a46d975e3e65679f965
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5f1d3fbd15 |
feat(orchestrator): durable launch-broker secret via TrustDomain (#468)
prd-number-check / require-numbered-prds (pull_request) Failing after 11s
tracker-policy-pr / check-pr (pull_request) Successful in 16s
test / integration-docker (pull_request) Failing after 45s
test / unit (pull_request) Successful in 56s
test / coverage (pull_request) Has been skipped
lint / lint (push) Failing after 14m57s
Chunk 2 of the host-control-server stack: close the PRD's **durable secret** gap and replace chunk 1's BOT_BOTTLE_BROKER_SECRET stopgap. - trust_domain.py: two new domains. LAUNCH_BROKER holds the durable HS256 key both the orchestrator (signer) and the host control server (verifier) share for the broker's launch JWT — a host-canonical key file minted 0600 on first use, so a restarted orchestrator re-verifies against the same key. HOST_CONTROLLER is the separate domain for the controller's own lifecycle endpoints, keyed by a key the orchestrator never holds (its role is `host`, deliberately outside control-plane ROLES). LaunchBrokerProvisioning is the fail-closed seam. - orchestrator_auth.py: ROLE_HOST, outside ROLES. - paths.py: key-file + env-var constants for both domains. Key resolution is split by owner (addresses codex review on #497): broker_secret(allow_host_file=...) — the host controller / dev-harness (True) may mint/read the durable host key file it owns; the GUEST orchestrator (--broker http, default False) must be *injected* the key and fails closed if it isn't. A guest that fell back to the host file would mint a process-local key unrelated to the host controller's, so startup would succeed but every launch would 401 — this prevents that silent divergence. Tested: domain boundary + separation, provisioning fail-closed, and broker_secret env-only (guest) vs host-file (host) resolution. pyright clean; pylint 9.86. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
1553a98275 |
fix(orchestrator): address review on host control server transport (#468)
prd-number-check / require-numbered-prds (pull_request) Failing after 11s
test / integration-docker (pull_request) Successful in 20s
lint / lint (push) Successful in 59s
test / unit (pull_request) Failing after 52s
test / coverage (pull_request) Has been skipped
tracker-policy-pr / check-pr (pull_request) Failing after 11m18s
Codex review on #496: - **High — ambiguous delivery no longer orphans a launched bottle.** A timeout / dropped response from the host controller is now the ambiguous BrokerUnavailableError (distinct from the definite BrokerAuthError / BrokerClientError). OrchestratorCore.launch_bottle keeps the registry row on the ambiguous case instead of deregistering — deregistering would orphan a running container with no record (reconcile reaps rows, never containers). The row is left for reconcile to reap iff the bottle is not actually live. Definite failures still roll back, so a real failure leaves no orphan row. - **Medium — the privileged endpoint bounds request bodies.** The host server rejects an oversized Content-Length with 413 before reading it, and sets a per-request socket timeout, so a caller that can merely reach the socket (no signed token) can't exhaust memory or a handler thread. Tests: ambiguous-keep vs definite-rollback in the launch path; the BrokerUnavailableError/BrokerClientError split in BrokerClient; the 413 body cap + handler error paths (driven in-thread, since daemon request threads lose coverage) plus a deterministic real-socket check that declares an oversized Content-Length but sends a sliver (rejection on the header, no unread-body reset race); and the __main__ entrypoint broker selection. Diff-coverage 98%; pyright clean; pylint 9.8. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
79dd4926bb |
feat(orchestrator): host control server transport (#468)
prd-number-check / require-numbered-prds (pull_request) Failing after 6s
test / integration-docker (pull_request) Successful in 15s
tracker-policy-pr / check-pr (pull_request) Successful in 20s
lint / lint (push) Successful in 57s
test / unit (pull_request) Successful in 47s
test / coverage (pull_request) Failing after 16s
Chunk 1 of the host-control-server stack: close the PRD's **transport** gap. Today LaunchBroker.submit(token) is an in-process method call from OrchestratorCore; this makes it a real out-of-process service reached over HTTP. - host_server.py: the host control server. A pure dispatch() (POST /broker verifies a signed token via the existing verify_request + _launch/_teardown path, GET /health) wrapped by a thin http.server adapter, mirroring orchestrator/server.py. Only the signed token crosses the wire; provenance/schema failures are fail-closed 401s that never touch the backend, a backend launch failure is a 502. - broker_client.py: BrokerClient — a drop-in submit(token) that POSTs the signed token to the host controller. A 401 re-raises as BrokerAuthError so the launch path's rollback is identical local or remote. - broker.py: SubmitBroker Protocol — the one method OrchestratorCore depends on, satisfied by both LaunchBroker and BrokerClient, so the core is unchanged (service.py annotation only). - __main__.py: wire `--broker http` behind the shared-secret env var (BOT_BOTTLE_BROKER_SECRET, hex) — a chunk-1 stopgap the durable TrustDomain key (chunk 2, #476) replaces. Tested: pure-dispatch cases, BrokerClient with HTTP mocked, and a real-socket sign -> POST -> verify -> act round-trip (incl. fail-closed forged token). pyright clean; pylint 9.86. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |