fix(mission_runtime): per-mission auto-pair via container log scrape (C3 auth)
ci / gates (push) Successful in 10s
ci / rust (push) Failing after 23s
ci / frontend (push) Successful in 38s
ci / e2e (push) Skipped
ci / publish (push) Skipped

The seed-mount approach didnt work: even with the shared runtimes
data dir bind-mounted, a fresh gateway instance mints a new pairing
key and requires re-pairing. The topology_worker connect returned
401 forever.

New approach — per-mission gateways self-pair:
- Provisioner tails container logs after start, extracts the
  X-Pairing-Code from the boot banner
- Persists it on missions.runtime_pairing_code (migration 0059)
- topology_worker constructs ZeroClawDriveExecutor with THAT code
  via from_env_for_gateway_with_code, which triggers the lazy
  /pair handshake on first turn and caches the returned bearer

Drops the shared-runtime data-dir mount — each per-mission gateway
now owns its own state, restoring the C3 isolation guarantee.
This commit is contained in:
Omar Sobh
2026-07-22 13:06:25 -07:00
parent 0210f5bf51
commit b569688e04
7 changed files with 173 additions and 44 deletions
+11 -6
View File
@@ -152,8 +152,11 @@ async fn run_job(
// the missions row; else fall back to the shared env-derived
// gateway (pre-C3 missions + non-mission runs). This is what
// isolates agents' workspace filesystem to that mission's repo.
let mission_endpoint: Option<String> = sqlx::query_scalar::<_, Option<String>>(
"SELECT m.runtime_endpoint
let mission_binding: Option<(Option<String>, Option<String>)> = sqlx::query_as::<
_,
(Option<String>, Option<String>),
>(
"SELECT m.runtime_endpoint, m.runtime_pairing_code
FROM topology_runs r
JOIN missions m ON m.id = r.mission_id
WHERE r.id = $1",
@@ -162,11 +165,13 @@ async fn run_job(
.fetch_optional(pool)
.await
.ok()
.flatten()
.flatten();
let leaf_result = match mission_endpoint {
Some(url) => ZeroClawDriveExecutor::from_env_for_gateway(url),
None => ZeroClawDriveExecutor::from_env(),
let leaf_result = match mission_binding {
Some((Some(url), Some(code))) => {
ZeroClawDriveExecutor::from_env_for_gateway_with_code(url, code)
}
Some((Some(url), None)) => ZeroClawDriveExecutor::from_env_for_gateway(url),
_ => ZeroClawDriveExecutor::from_env(),
};
let leaf = match leaf_result {
Ok(e) => e,