fix(mission_runtime): per-mission auto-pair via container log scrape (C3 auth)
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:
@@ -39,6 +39,10 @@ pub struct Mission {
|
||||
pub runtime_container_name: Option<String>,
|
||||
/// Gateway URL the topology_worker dials for this mission's runs.
|
||||
pub runtime_endpoint: Option<String>,
|
||||
/// One-time pairing code captured from the fresh gateway's startup
|
||||
/// log. topology_worker uses it to lazy-pair with this specific
|
||||
/// mission runtime instead of the shared-runtime env token.
|
||||
pub runtime_pairing_code: Option<String>,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
pub created_at: OffsetDateTime,
|
||||
#[serde(with = "time::serde::rfc3339")]
|
||||
@@ -186,7 +190,7 @@ pub async fn get(pool: &PgPool, id: Uuid, workspace_id: Uuid) -> Result<Option<M
|
||||
"SELECT id, workspace_id, title, template_kind, team_id,
|
||||
team_template_id, repo_id, schedule, status,
|
||||
description, config, runtime_kind, target_node_id,
|
||||
runtime_container_name, runtime_endpoint,
|
||||
runtime_container_name, runtime_endpoint, runtime_pairing_code,
|
||||
created_at, updated_at, completed_at
|
||||
FROM missions WHERE id = $1 AND workspace_id = $2",
|
||||
)
|
||||
@@ -227,7 +231,7 @@ pub async fn list_by_workspace(
|
||||
"SELECT id, workspace_id, title, template_kind, team_id,
|
||||
team_template_id, repo_id, schedule, status,
|
||||
description, config, runtime_kind, target_node_id,
|
||||
runtime_container_name, runtime_endpoint,
|
||||
runtime_container_name, runtime_endpoint, runtime_pairing_code,
|
||||
created_at, updated_at, completed_at
|
||||
FROM missions WHERE workspace_id = $1
|
||||
ORDER BY created_at DESC LIMIT $2",
|
||||
@@ -254,6 +258,7 @@ pub async fn list_by_workspace(
|
||||
target_node_id: r.get("target_node_id"),
|
||||
runtime_container_name: r.get("runtime_container_name"),
|
||||
runtime_endpoint: r.get("runtime_endpoint"),
|
||||
runtime_pairing_code: r.get("runtime_pairing_code"),
|
||||
created_at: r.get("created_at"),
|
||||
updated_at: r.get("updated_at"),
|
||||
completed_at: r.get("completed_at"),
|
||||
@@ -315,11 +320,13 @@ pub async fn set_runtime_binding(
|
||||
workspace_id: Uuid,
|
||||
container_name: Option<&str>,
|
||||
endpoint: Option<&str>,
|
||||
pairing_code: Option<&str>,
|
||||
) -> Result<(), DbError> {
|
||||
sqlx::query(
|
||||
"UPDATE missions
|
||||
SET runtime_container_name = $3,
|
||||
runtime_endpoint = $4,
|
||||
runtime_pairing_code = $5,
|
||||
updated_at = now()
|
||||
WHERE id = $1 AND workspace_id = $2",
|
||||
)
|
||||
@@ -327,6 +334,7 @@ pub async fn set_runtime_binding(
|
||||
.bind(workspace_id)
|
||||
.bind(container_name)
|
||||
.bind(endpoint)
|
||||
.bind(pairing_code)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user