fix(code-queue): add workdirs contract checks

This commit is contained in:
Codex
2026-05-19 02:07:41 +00:00
parent 49cf1e57bb
commit 6006017393
9 changed files with 611 additions and 9 deletions
@@ -395,6 +395,7 @@ function codeQueueK3sServiceIdForRequest(method: string, targetPath: string): st
function codeQueueMasterControlPath(method: string, targetPath: string): boolean {
const normalizedMethod = method.toUpperCase();
if (targetPath === "/" || targetPath === "/health" || targetPath === "/live" || targetPath === "/logs") return true;
if (targetPath === "/api/workdirs" || /^\/api\/workdirs\/[^/]+\/[^/]+\/.+$/u.test(targetPath)) return true;
if (targetPath === "/api/queue-claim-move/self-test") return true;
if (targetPath === "/api/queues" || targetPath === "/api/queues/merge") return true;
if (/^\/api\/queues\/[^/]+(?:\/merge)?$/u.test(targetPath)) return true;
@@ -404,6 +405,38 @@ function codeQueueMasterControlPath(method: string, targetPath: string): boolean
return false;
}
function codeQueueCompatWorkdirsResponse(service: MicroserviceConfig, status: number, contentType: string, bodyText: string): Response | null {
if (status !== 404) return null;
let body: any = null;
try {
body = JSON.parse(bodyText);
} catch {
return null;
}
if (body?.path !== "/api/workdirs") return null;
const providerId = "D601";
return jsonResponse({
ok: true,
workdirs: [{
providerId,
executionMode: "default",
path: "/workspace",
createdAt: null,
updatedAt: null,
source: "backend-core-compat",
}],
defaultProviderId: providerId,
defaultWorkdir: "/workspace",
remoteDefaultWorkdir: "/home/ubuntu",
source: "backend-core-compat-code-queue-workdirs",
compat: {
reason: "code-queue-mgr version does not yet expose /api/workdirs",
upstreamStatus: status,
upstreamContentType: contentType,
},
}, 200);
}
// ---------------------------------------------------------------------------
// Cache helpers
// ---------------------------------------------------------------------------
@@ -1026,7 +1059,24 @@ async function fetchMicroserviceUpstreamResponse(
): Promise<Response> {
if (service.id === "code-queue" && codeQueueMasterControlPath(method, targetPath)) {
const mgr = microserviceById("code-queue-mgr");
if (mgr !== null) return directMicroserviceResponse(mgr, method, targetPath, proxyOptions, requestHeaders, bodyText, abortSignal);
if (mgr !== null) {
const response = await directMicroserviceResponse(mgr, method, targetPath, proxyOptions, requestHeaders, bodyText, abortSignal);
if (method.toUpperCase() === "GET" && targetPath === "/api/workdirs") {
const contentType = response.headers.get("content-type") ?? "text/plain; charset=utf-8";
const responseBody = await response.text();
const compat = codeQueueCompatWorkdirsResponse(service, response.status, contentType, responseBody);
if (compat !== null) return compat;
return new Response(responseBody, {
status: response.status,
headers: {
"content-type": contentType,
"x-unidesk-proxy-mode": response.headers.get("x-unidesk-proxy-mode") ?? "direct",
"x-unidesk-response-truncated": response.headers.get("x-unidesk-response-truncated") ?? "false",
},
});
}
return response;
}
logger("warn", "code_queue_mgr_missing_fallback_to_d601", { method, targetPath });
}
if (isK3sctlManagedMicroservice(service)) {
@@ -154,6 +154,47 @@ fn code_queue_scheduler_only_path(method: &Method, target_path: &str) -> bool {
&& !(target_path == "/" || target_path == "/health")
}
fn code_queue_fallback_workdirs_response(
service: &MicroserviceConfig,
status: u16,
content_type: &str,
body_text: &str,
) -> Option<Response> {
if status != 404 {
return None;
}
let body = serde_json::from_str::<Value>(body_text).ok()?;
if body.get("path").and_then(Value::as_str) != Some("/api/workdirs") {
return None;
}
let provider_id = service.provider_id.clone();
let fallback = json!({
"ok": true,
"workdirs": [{
"providerId": provider_id,
"executionMode": "default",
"path": "/workspace",
"createdAt": null,
"updatedAt": null,
"source": "backend-core-compat"
}],
"defaultProviderId": provider_id,
"defaultWorkdir": "/workspace",
"remoteDefaultWorkdir": "/home/ubuntu",
"source": "backend-core-compat-code-queue-workdirs",
"compat": {
"reason": "code-queue-mgr version does not yet expose /api/workdirs",
"upstreamStatus": status,
"upstreamContentType": content_type
}
});
Some(response_with_body(
200,
"application/json; charset=utf-8",
Body::from(serde_json::to_string(&fallback).unwrap_or_else(|_| "{\"ok\":true,\"workdirs\":[]}".to_string())),
))
}
fn path_matches_task_detail(path: &str) -> bool {
path.strip_prefix("/api/tasks/")
.is_some_and(|rest| !rest.is_empty() && !rest.contains('/'))
@@ -926,7 +967,7 @@ async fn fetch_microservice_upstream_response(
)
.await;
}
return direct_microservice_response(
let response = direct_microservice_response(
&direct_code_queue_mgr_service(service, None),
method,
target_path,
@@ -935,6 +976,18 @@ async fn fetch_microservice_upstream_response(
body_text,
)
.await;
if method == Method::GET && target_path == "/api/workdirs" {
let (status, content_type, response_body) = response_to_text(response).await.unwrap_or((
502,
"text/plain".to_string(),
"failed to read code-queue workdirs response".to_string(),
));
if let Some(fallback) = code_queue_fallback_workdirs_response(service, status, &content_type, &response_body) {
return fallback;
}
return response_with_body(status, &content_type, Body::from(response_body));
}
return response;
}
if is_k3sctl_managed_microservice(service) {
return k3sctl_adapter_microservice_response(