import { readFileSync, rmSync } from "node:fs"; import { describe, expect, test } from "bun:test"; import { parseAgentRunClientConfigYaml, resolveAgentRunAuth, runAgentRunCommand, stripAgentRunResourceWrapperArgs } from "./agentrun"; import { resolveAgentRunLaneTarget } from "./agentrun-lanes"; import { agentRunToolCredentialRefs } from "./agentrun/config"; import { placeholderAgentRunImage, renderAgentRunGitopsFiles } from "./agentrun-manifests"; import { collectLaneSecretSources, secretSyncScript } from "./agentrun/secrets"; function renderedTextOf(value: unknown): string { if (typeof value !== "object" || value === null) throw new Error("expected rendered CLI result"); const text = (value as { renderedText?: unknown }).renderedText; if (typeof text !== "string") throw new Error("expected renderedText string"); return text; } function renderedContentTypeOf(value: unknown): string { if (typeof value !== "object" || value === null) throw new Error("expected rendered CLI result"); const contentType = (value as { contentType?: unknown }).contentType; if (typeof contentType !== "string") throw new Error("expected contentType string"); return contentType; } const agentRunClientYaml = [ "version: 1", "kind: AgentRunConfig", "metadata:", " name: agentrun", "manager:", " baseUrl: https://agentrun.127-0-0-1.nip.io/", " timeoutMs: 15000", "publicExposure:", " enabled: true", " proxyName: agentrun-v01-frpc", " remotePort: 22880", " publicBaseUrl: https://agentrun.127-0-0-1.nip.io/", " masterBaseUrl: http://127.0.0.1:22880", " masterFrps:", " configPath: /opt/hwlab-frp/frps.dev.toml", " containerName: hwlab-frps-dev", " masterCaddy:", " enabled: true", " domain: agentrun.127-0-0-1.nip.io", " configPath: /etc/caddy/Caddyfile", " serviceName: caddy", " upstreamBaseUrl: http://127.0.0.1:22880", " responseHeaderTimeoutSeconds: 60", "auth:", " env: HWLAB_API_KEY", " file: /tmp/hwlab-api-key.env", " header: Authorization", " scheme: Bearer", "client:", " role: render-only", " transport: direct-http", " sessionPolicy:", " tenantId: unidesk", " projectId: test", " providerId: NC01", " backendProfile: codex", " workspaceRef:", " kind: opaque", " executionPolicy:", " sandbox: workspace-write", " approval: never", " timeoutMs: 900000", " network: enabled", " secretScope:", " allowCredentialEcho: false", ].join("\n"); const agentRunMinimalClientYaml = [ "version: 1", "kind: AgentRunConfig", "metadata:", " name: agentrun", "manager:", " baseUrl: http://agentrun.example.local:8080", " timeoutMs: 15000", "auth:", " env: HWLAB_API_KEY", " file: /tmp/hwlab-api-key.env", " header: Authorization", " scheme: Bearer", "client:", " role: render-only", " transport: direct-http", " sessionPolicy:", " tenantId: unidesk", " projectId: test", " providerId: NC01", " backendProfile: codex", " workspaceRef:", " kind: opaque", " executionPolicy:", " sandbox: workspace-write", " approval: never", " timeoutMs: 900000", " network: enabled", " secretScope:", " allowCredentialEcho: false", ].join("\n"); describe("AgentRun resource bridge argv", () => { test("does not forward UniDesk output flags to create task prompt argv", () => { expect(stripAgentRunResourceWrapperArgs([ "--aipod", "Artificer", "--prompt-stdin", "-o", "json", "--idempotency-key", "case-262", "--dry-run", ])).toEqual([ "--aipod", "Artificer", "--prompt-stdin", "--idempotency-key", "case-262", "--dry-run", ]); }); test("strips wrapper display flags while preserving official apply arguments", () => { expect(stripAgentRunResourceWrapperArgs([ "-f", "-", "--output=yaml", "--raw", "--full", "--input", "--full-text", "--dry-run", ])).toEqual([ "-f", "-", "--dry-run", ]); }); }); describe("AgentRun render-only REST client config", () => { test("parses explicit YAML config for direct REST render-only client", () => { const config = parseAgentRunClientConfigYaml(agentRunClientYaml, "config/agentrun.yaml"); expect(config.manager.baseUrl).toBe("https://agentrun.127-0-0-1.nip.io/"); expect(config.publicExposure?.publicBaseUrl).toBe("https://agentrun.127-0-0-1.nip.io/"); expect(config.publicExposure?.masterCaddy.domain).toBe("agentrun.127-0-0-1.nip.io"); expect(config.auth.env).toBe("HWLAB_API_KEY"); expect(config.auth.header).toBe("Authorization"); expect(config.auth.scheme).toBe("Bearer"); expect(config.client.role).toBe("render-only"); expect(config.client.transport).toBe("direct-http"); }); test("uses env auth before configured file auth without exposing the key", () => { const config = parseAgentRunClientConfigYaml(agentRunClientYaml, "config/agentrun.yaml"); const auth = resolveAgentRunAuth(config, { HWLAB_API_KEY: "secret-value" }); expect(auth.source).toBe("env"); expect(auth.value).toBe("secret-value"); }); test("requires explicit render-only direct-http client contract", () => { expect(() => parseAgentRunClientConfigYaml(agentRunClientYaml.replace(" transport: direct-http", " transport: ssh-bridge"), "config/agentrun.yaml")).toThrow("client.transport must be direct-http"); expect(() => parseAgentRunClientConfigYaml(agentRunClientYaml.replace(" role: render-only", " role: proxy"), "config/agentrun.yaml")).toThrow("client.role must be render-only"); }); }); describe("AgentRun default transport contract", () => { test("server-facing compatibility groups use REST dispatcher, not official SSH CLI wrapper", () => { const source = readFileSync(new URL("./agentrun/entry.ts", import.meta.url), "utf8"); const commandRouter = source.slice(source.indexOf("export async function runAgentRunCommand"), source.indexOf("function isAgentRunRestCompatGroup")); expect(commandRouter).toContain("runAgentRunRestCompatCommand"); expect(commandRouter).not.toContain("runOfficialAgentRunCli"); expect(commandRouter).not.toContain("runPreparedOfficialAgentRunCli"); }); test("resource verbs can use direct REST without UniDesk SSH config", async () => { const server = Bun.serve({ port: 0, fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); expect(url.pathname).toBe("/api/v1/queue/tasks"); expect(url.searchParams.get("queue")).toBe("commander"); expect(url.searchParams.get("state")).toBe("running"); return Response.json({ ok: true, data: { items: [ { id: "qt_1", state: "queued", queue: "commander" }, ], }, }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(process.env.AGENTRUN_CLIENT_CONFIG, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const result = await runAgentRunCommand(null, ["get", "tasks", "--queue", "commander", "-o", "json"]); expect(result.ok).toBe(true); expect("renderedText" in result).toBe(true); if ("renderedText" in result) { expect(result.renderedText).toContain("\"kind\": \"TaskList\""); expect(result.renderedText).toContain("\"name\": \"qt_1\""); } } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); test("task input drill-down is bounded, reconstructable, and SecretRef-only", async () => { const taskId = "qt_artificer_input"; const hiddenCredential = "HIDDEN_CREDENTIAL_VALUE_MUST_NOT_BE_PRINTED"; const task = { id: taskId, tenantId: "unidesk", projectId: "pikasTech/unidesk", queue: "commander", lane: "v0.1", title: "Artificer input fixture", priority: 50, state: "completed", version: 7, backendProfile: "sub2api", providerId: "G14", workspaceRef: { kind: "opaque", path: ".", repo: "pikasTech/unidesk", branch: "master" }, sessionRef: { sessionId: "ses_fixture", conversationId: "conv_fixture", metadata: { credential: hiddenCredential } }, executionPolicy: { sandbox: "workspace-write", approval: "never", timeoutMs: 1_800_000, network: "enabled", secretScope: { allowCredentialEcho: false, providerCredentials: [{ profile: "sub2api", secretRef: { name: "agentrun-provider", keys: ["auth.json"], value: hiddenCredential }, value: hiddenCredential, }], toolCredentials: [{ tool: "github", purpose: "github-pr", secretRef: { name: "agentrun-github", keys: ["GH_TOKEN"], token: hiddenCredential }, projection: { kind: "env", envName: "GH_TOKEN", secretKey: "GH_TOKEN", value: hiddenCredential }, }], }, }, resourceBundleRef: { kind: "gitbundle", repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/unidesk.git`, ref: "master", bundles: [{ name: "unidesk-skills", subpath: ".agents/skills", targetPath: ".agents/skills" }], requiredSkills: [{ name: "unidesk-gh" }], credentialRef: { name: "agentrun-resource-git", keys: ["username", "password"], value: hiddenCredential }, submodules: false, lfs: false, }, payload: { prompt: "Inspect the existing sentinel configuration.", model: "gpt-5.5" }, payloadHash: "sha256:fixture", references: [{ kind: "github-issue", url: "https://github.com/pikasTech/unidesk/issues/1819" }], metadata: { aipod: "Artificer", source: "config/aipods/artificer.yaml", aipodSpecHash: "sha256:aipod-fixture", aipodImageRef: { kind: "env-image-dockerfile", repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/agentrun.git`, commitId: "a".repeat(40), dockerfilePath: "deploy/container/Containerfile", }, credential: hiddenCredential, }, idempotencyKey: "artificer-input-fixture", latestAttempt: { attemptId: "qat_fixture", state: "completed", runId: "run_fixture", commandId: "cmd_fixture", runnerJobId: "rjob_fixture", sessionId: "ses_fixture" }, supervisor: { verboseDiagnostic: "x".repeat(20_000), credential: hiddenCredential }, valuesPrinted: false, }; let requests = 0; const server = Bun.serve({ port: 0, fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); expect(url.pathname).toBe(`/api/v1/queue/tasks/${taskId}`); requests += 1; return Response.json({ ok: true, data: task }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-input-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const invalidCombinations = [ { args: ["--input", "--full"], contentType: "text/plain" }, { args: ["--full", "--input", "-o", "json"], contentType: "application/json" }, { args: ["--input", "--full", "-o", "yaml"], contentType: "application/yaml" }, { args: ["--input", "--raw"], contentType: "application/json" }, ]; for (const invalid of invalidCombinations) { const rejected = await runAgentRunCommand(null, ["describe", `task/${taskId}`, ...invalid.args]); const rejectedText = renderedTextOf(rejected); expect(rejected.ok).toBe(false); expect(renderedContentTypeOf(rejected)).toBe(invalid.contentType); expect(rejectedText).toContain("validation-failed"); expect(rejectedText).toContain("cannot be combined with complete resource disclosure"); expect(rejectedText).not.toContain(hiddenCredential); expect(rejectedText).not.toContain("supervisor"); expect(Buffer.byteLength(rejectedText, "utf8")).toBeLessThan(2400); } expect(requests).toBe(0); const summaryText = renderedTextOf(await runAgentRunCommand(null, ["describe", `task/${taskId}`])); expect(summaryText).toContain(`agentrun describe task/${taskId} --input -o json`); expect(summaryText).not.toContain(hiddenCredential); const compact = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `task/${taskId}`, "-o", "json"]))) as { next?: { input?: string } }; expect(compact.next?.input).toContain("--input -o json"); const inputText = renderedTextOf(await runAgentRunCommand(null, ["describe", `task/${taskId}`, "--input"])); const input = JSON.parse(inputText) as { kind?: string; spec?: Record; aipodSpec?: Record; provenance?: Record; redaction?: Record; valuesPrinted?: boolean; }; expect(input.kind).toBe("TaskInput"); expect(input.spec?.payload?.prompt).toBe(task.payload.prompt); expect(input.spec?.idempotencyKey).toBe(task.idempotencyKey); expect(input.spec?.metadata?.aipod).toBe("Artificer"); expect(input.aipodSpec?.specHash).toBe("sha256:aipod-fixture"); expect(input.provenance?.sourceTaskId).toBe(taskId); expect(input.spec?.executionPolicy?.secretScope?.providerCredentials?.[0]?.secretRef).toEqual({ name: "agentrun-provider", keys: ["auth.json"], valuesPrinted: false, }); expect(input.spec?.resourceBundleRef?.credentialRef).toEqual({ name: "agentrun-resource-git", keys: ["username", "password"], valuesPrinted: false, }); expect(input.spec?.resourceBundleRef?.repoUrl).toBe("https://github.com/pikasTech/unidesk.git"); expect(input.aipodSpec?.imageRef?.repoUrl).toBe("https://github.com/pikasTech/agentrun.git"); expect(input.redaction?.credentialValues).toBe("omitted"); expect(input.valuesPrinted).toBe(false); expect(inputText).not.toContain(hiddenCredential); expect(Buffer.byteLength(inputText, "utf8")).toBeLessThan(10_240); const full = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `task/${taskId}`, "--full", "-o", "json"]))) as { resource?: typeof task }; expect(full.resource?.executionPolicy.secretScope.providerCredentials[0]?.secretRef.value).toBe(hiddenCredential); const raw = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `task/${taskId}`, "--raw"]))) as { data?: typeof task }; expect(raw.data?.resourceBundleRef.credentialRef.value).toBe(hiddenCredential); expect(requests).toBe(5); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); test("aipodspec describe is bounded and homologous while full and raw stay complete", async () => { const aipodName = "Artificer"; const hiddenCredential = "HIDDEN_AIPOD_CREDENTIAL_VALUE_MUST_NOT_BE_PRINTED"; const providerCredential = { profile: "sub2api", name: "agentrun-provider", namespace: null, keys: ["auth.json", "config.toml"], value: hiddenCredential, valuesPrinted: false, }; const toolCredentials = [ { tool: "github", purpose: "github-pr", name: "agentrun-github", namespace: null, keys: ["GH_TOKEN"], projection: { kind: "env", envName: "GH_TOKEN", secretKey: "GH_TOKEN", value: hiddenCredential }, token: hiddenCredential, valuesPrinted: false, }, { tool: "ssh", purpose: "remote-workspace", name: "agentrun-ssh", namespace: null, keys: ["config", "key"], projection: { kind: "mount", mountPath: "/run/secrets/ssh", value: hiddenCredential }, valuesPrinted: false, }, { tool: "provider", purpose: "model-auth", name: "agentrun-provider", namespace: null, keys: ["auth.json"], projection: { kind: "mount", mountPath: "/run/secrets/provider", value: hiddenCredential }, valuesPrinted: false, }, ]; const data = { action: "show", item: { name: aipodName, displayName: "Artificer", description: "x".repeat(20_000), specHash: "sha256:aipod-fixture", source: "config/aipods/artificer.yaml", backendProfile: "sub2api", model: { model: "gpt-5.5", reasoningEffort: "high" }, imageRef: { kind: "env-image-dockerfile", repoUrl: "https://github.com/pikasTech/agentrun.git", commitId: "a".repeat(40), dockerfilePath: "deploy/container/Containerfile", sourceIdentity: "agentrun@aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", valuesPrinted: false, }, queue: "commander", lane: "v0.1", providerId: "NC01", providerCredentials: { count: 1, profiles: ["sub2api"], items: [providerCredential], valuesPrinted: false }, toolCredentials: { count: 3, tools: ["github", "ssh", "provider"], items: toolCredentials, valuesPrinted: false }, resourceBundleRef: { kind: "gitbundle", repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/unidesk.git`, ref: "master", commitId: null, bundles: { count: 6, items: [{ name: "unidesk-skills", targetPath: ".agents/skills" }], valuesPrinted: false }, requiredSkills: { count: 11, names: ["unidesk-gh"], valuesPrinted: false }, promptRefs: { count: 0, names: [], valuesPrinted: false }, valuesPrinted: false, }, createdAt: "2026-07-12T00:00:00.000Z", updatedAt: "2026-07-12T01:00:00.000Z", valuesPrinted: false, }, spec: { apiVersion: "agentrun.pikastech.local/v1alpha1", kind: "AipodSpec", metadata: { name: aipodName, displayName: "Artificer", description: "x".repeat(20_000) }, spec: { queue: "commander", lane: "v0.1", providerId: "NC01", backendProfile: "sub2api", model: { model: "gpt-5.5", reasoningEffort: "high" }, workspaceRef: { kind: "opaque", path: "." }, executionPolicy: { secretScope: { allowCredentialEcho: false, providerCredentials: [{ profile: "sub2api", secretRef: { name: "agentrun-provider", keys: ["auth.json"], value: hiddenCredential } }], toolCredentials: [{ tool: "github", secretRef: { name: "agentrun-github", keys: ["GH_TOKEN"], token: hiddenCredential } }], }, }, resourceBundleRef: { kind: "gitbundle", repoUrl: `https://fixture:${hiddenCredential}@github.com/pikasTech/unidesk.git`, ref: "master", bundles: [{ name: "unidesk-skills", subpath: ".agents/skills", targetPath: ".agents/skills" }], requiredSkills: [{ name: "unidesk-gh" }], }, metadata: { aipod: aipodName, source: "config/aipods/artificer.yaml" }, }, }, valuesPrinted: false, }; let requests = 0; const server = Bun.serve({ port: 0, fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); expect(url.pathname).toBe(`/api/v1/aipod-specs/${aipodName}`); requests += 1; return Response.json({ ok: true, data }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-aipodspec-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const text = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`])); expect(text).toContain(`Name: aipodspec/${aipodName}`); expect(text).toContain("Hash: sha256:aipod-fixture"); expect(text).toContain("Kind: opaque path=. branch=-"); expect(text).toContain("References: bundles=6 requiredSkills=11 promptRefs=0"); expect(text).toContain("Credentials: provider=1 tool=3 total=4"); expect(text).toContain("secret=agentrun-provider keys=auth.json,config.toml"); expect(text).toContain(`agentrun describe aipodspec/${aipodName} --full -o json`); expect(Buffer.byteLength(text, "utf8")).toBeLessThan(10_240); expect(text).not.toContain(hiddenCredential); const jsonText = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "-o", "json"])); const json = JSON.parse(jsonText) as Record; const yamlText = renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "-o", "yaml"])); const yaml = Bun.YAML.parse(yamlText) as Record; expect(yaml).toEqual(json); expect(json.kind).toBe("AipodSpec"); expect(json.identity.specHash).toBe("sha256:aipod-fixture"); expect(json.runtime).toMatchObject({ lane: "v0.1", backendProfile: "sub2api", providerId: "NC01" }); expect(json.workspaceRef).toMatchObject({ kind: "opaque", path: ".", valuesPrinted: false }); expect(json.resourceBundleRef.sourceIdentity.repoUrl).toBe("https://github.com/pikasTech/unidesk.git"); expect(json.resourceBundleRef).toMatchObject({ bundleCount: 6, requiredSkillCount: 11, promptRefCount: 0 }); expect(json.credentialRefs).toMatchObject({ totalCount: 4, valuesPrinted: false }); expect(json.credentialRefs.provider.items[0].secretRef).toEqual({ namespace: null, name: "agentrun-provider", keys: ["auth.json", "config.toml"], valuesPrinted: false, }); expect(json.redaction).toEqual({ credentialValues: "omitted", secretRefsOnly: true, valuesPrinted: false }); expect(json.valuesPrinted).toBe(false); for (const bounded of [jsonText, yamlText]) { expect(Buffer.byteLength(bounded, "utf8")).toBeLessThan(10_240); expect(bounded).not.toContain(hiddenCredential); expect(bounded).not.toContain("x".repeat(200)); } const full = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "--full", "-o", "json"]))) as { resource?: typeof data }; expect(full.resource?.item.description).toBe("x".repeat(20_000)); expect(full.resource?.spec.kind).toBe("AipodSpec"); const raw = JSON.parse(renderedTextOf(await runAgentRunCommand(null, ["describe", `aipodspec/${aipodName}`, "--raw"]))) as { data?: typeof data }; expect(raw.data?.item.description).toBe("x".repeat(20_000)); expect(raw.data?.spec.kind).toBe("AipodSpec"); expect(requests).toBe(5); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); test("retry dry-run is server-validated and attempts use the formal resource API", async () => { const taskId = "qt_failed_1"; const attempt = { attemptId: "qat_retry_1", taskId, retryIndex: 1, state: "reserved", idempotencyKey: "retry-key-1", reason: "dependency repaired", payloadHash: "sha256:payload", previousAttemptId: "qat_initial_0", runId: "run_retry_1", commandId: "cmd_retry_1", runnerJobId: "rjob_retry_1", sessionId: "ses_retry_1", sessionPath: "/api/v1/sessions/ses_retry_1", failureKind: "infra-failed", failureMessage: "kubectl create runner job failed before materialization", createdAt: "2026-07-12T00:00:00.000Z", updatedAt: "2026-07-12T00:00:01.000Z", activatedAt: "2026-07-12T00:00:01.000Z", terminalAt: null, }; let retryRequests = 0; let attemptRequests = 0; const server = Bun.serve({ port: 0, async fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); if (url.pathname === `/api/v1/queue/tasks/${taskId}/retry`) { retryRequests += 1; expect(request.method).toBe("POST"); expect(await request.json()).toEqual({ idempotencyKey: "retry-key-1", reason: "dependency repaired", dryRun: true, }); return Response.json({ ok: true, data: { action: "queue-retry", mutation: false, idempotentReplay: false, task: { id: taskId, state: "failed", queue: "commander", payloadHash: "sha256:payload" }, attempt: null, previousAttempt: { ...attempt, attemptId: "qat_initial_0", retryIndex: 0, state: "failed", previousAttemptId: null }, run: null, command: null, runnerJob: null, allowedTransition: { from: "failed", to: "running", retryIndex: 1, previousAttemptId: "qat_initial_0", payloadHash: "sha256:payload", valuesPrinted: false }, pollActions: [], }, }); } if (url.pathname === `/api/v1/queue/tasks/${taskId}/attempts`) { attemptRequests += 1; expect(request.method).toBe("GET"); expect(url.searchParams.get("cursor")).toBe("1"); expect(url.searchParams.get("limit")).toBe("10"); return Response.json({ ok: true, data: { taskId, items: [attempt], count: 1, cursor: null } }); } return new Response("not found", { status: 404 }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-retry-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const retryResult = await runAgentRunCommand(null, ["retry", `task/${taskId}`, "--idempotency-key", "retry-key-1", "--reason", "dependency repaired", "--dry-run"]); expect(retryResult.ok).toBe(true); expect("renderedText" in retryResult).toBe(true); if ("renderedText" in retryResult) { expect(retryResult.renderedText).toContain(`Task retry validated: task/${taskId}`); expect(retryResult.renderedText).toContain("Transition: failed -> running retryIndex=1"); expect(retryResult.renderedText).toContain("Attempt: planned"); } const attemptsResult = await runAgentRunCommand(null, ["get", "attempts", "--task", taskId, "--cursor", "1", "--limit", "10", "-o", "json"]); expect(attemptsResult.ok).toBe(true); expect("renderedText" in attemptsResult).toBe(true); if ("renderedText" in attemptsResult && typeof attemptsResult.renderedText === "string") { const payload = JSON.parse(attemptsResult.renderedText) as { kind?: string; taskId?: string; count?: number; items?: Array> }; expect(payload.kind).toBe("AttemptList"); expect(payload.taskId).toBe(taskId); expect(payload.count).toBe(1); expect(payload.items?.[0]?.name).toBe(attempt.attemptId); expect(payload.items?.[0]?.retryIndex).toBe(1); expect(payload.items?.[0]?.failureMessage).toBe(attempt.failureMessage); } const attemptsHumanResult = await runAgentRunCommand(null, ["get", "attempts", "--task", taskId, "--cursor", "1", "--limit", "10"]); expect("renderedText" in attemptsHumanResult ? attemptsHumanResult.renderedText : "").toContain("infra-failed: kubectl create runner job failed before materialization"); expect(retryRequests).toBe(1); expect(attemptRequests).toBe(2); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); test("retry and attempt resource help stays scoped to the controlled commands", async () => { const retryHelp = await runAgentRunCommand(null, ["retry", "--help"]); const attemptHelp = await runAgentRunCommand(null, ["get", "attempts", "--help"]); const describeHelp = await runAgentRunCommand(null, ["describe", "--help"]); expect("renderedText" in retryHelp ? retryHelp.renderedText : "").toContain("agentrun retry task/ --idempotency-key --reason "); expect("renderedText" in attemptHelp ? attemptHelp.renderedText : "").toContain("agentrun get attempts --task "); expect("renderedText" in describeHelp ? describeHelp.renderedText : "").toContain("agentrun describe task/qt_... --input -o json"); const rootHelp = Bun.spawnSync(["bun", "scripts/cli.ts", "agentrun", "--help"], { cwd: new URL("../..", import.meta.url).pathname, stdout: "pipe", stderr: "pipe", }); const rootHelpText = rootHelp.stdout.toString(); expect(rootHelp.exitCode).toBe(0); expect(rootHelpText).toContain("Verbs: get, describe, events, logs, result, ack, cancel, retry,"); expect(rootHelpText).toContain("Resources: task/qt, attempt, run,"); expect(rootHelpText).toContain("agentrun retry task/ --idempotency-key --reason --dry-run"); expect(rootHelpText).toContain("agentrun get attempts --task --limit 20"); expect(rootHelpText.split("\n").length).toBeLessThan(40); }); test("local resource validation preserves bounded human and machine errors", async () => { const cases = [ { args: ["retry", "task/qt_failed_1", "--reason", "dependency repaired"], message: "retry requires --idempotency-key ", }, { args: ["retry", "task/qt_failed_1", "--idempotency-key", "retry-key-1"], message: "retry requires --reason ", }, { args: ["get", "attempts"], message: "get attempts requires --task ", }, { args: ["retry", "run/run_invalid", "--idempotency-key", "retry-key-1", "--reason", "dependency repaired"], message: "retry supports task/", }, { args: ["retry"], message: "retry requires task/", }, ]; for (const item of cases) { const human = await runAgentRunCommand(null, item.args); const humanText = renderedTextOf(human); expect(human.ok).toBe(false); expect(humanText).toContain("Error: validation-failed"); expect(humanText).toContain(item.message); expect(humanText.length).toBeLessThan(1600); for (const outputArgs of [["-o", "json"], ["--raw"]]) { const machine = await runAgentRunCommand(null, [...item.args, ...outputArgs]); const machineText = renderedTextOf(machine); const payload = JSON.parse(machineText) as { ok?: boolean; failureKind?: string; message?: string }; expect(machine.ok).toBe(false); expect(renderedContentTypeOf(machine)).toBe("application/json"); expect(payload.ok).toBe(false); expect(payload.failureKind).toBe("validation-failed"); expect(payload.message).toBe(item.message); expect(machineText.length).toBeLessThan(2400); } } for (const cliArgs of [ ["retry", "run/run_invalid", "--idempotency-key", "retry-key-1", "--reason", "dependency repaired", "-o", "json"], ["get", "attempts", "--raw"], ["describe", "task/qt_sensitive", "--input", "--full", "-o", "json"], ["describe", "task/qt_sensitive", "--input", "--raw"], ]) { const cli = Bun.spawnSync(["bun", "scripts/cli.ts", "agentrun", ...cliArgs], { cwd: new URL("../..", import.meta.url).pathname, stdout: "pipe", stderr: "pipe", }); const payload = JSON.parse(cli.stdout.toString()) as { ok?: boolean; failureKind?: string }; expect(cli.exitCode).toBe(1); expect(payload.ok).toBe(false); expect(payload.failureKind).toBe("validation-failed"); expect(cli.stdout.toString().length).toBeLessThan(2400); expect(cli.stdout.toString()).not.toContain('"resource":'); expect(cli.stdout.toString()).not.toContain('"data":'); } }); test("server retry validation errors stay bounded in human and JSON output", async () => { const taskId = "qt_completed_1"; const longMessage = `queue task ${taskId} cannot be retried from state completed: ${"x".repeat(6000)}`; const longDiagnostic = `server diagnostic: ${"y".repeat(9000)}`; let requests = 0; const server = Bun.serve({ port: 0, async fetch(request) { const url = new URL(request.url); expect(url.pathname).toBe(`/api/v1/queue/tasks/${taskId}/retry`); expect(request.method).toBe("POST"); expect(await request.json()).toEqual({ idempotencyKey: "retry-key-terminal", reason: "operator requested retry", dryRun: true }); requests += 1; return Response.json({ ok: false, failureKind: "schema-invalid", message: longMessage, details: { allowedStates: ["failed", "blocked"], diagnostic: longDiagnostic, valuesPrinted: false }, valuesPrinted: false, }, { status: 409 }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-retry-error-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const baseArgs = ["retry", `task/${taskId}`, "--idempotency-key", "retry-key-terminal", "--reason", "operator requested retry", "--dry-run"]; const human = await runAgentRunCommand(null, baseArgs); const humanText = renderedTextOf(human); expect(human.ok).toBe(false); expect(humanText).toContain(`queue task ${taskId} cannot be retried from state completed`); expect(humanText).not.toContain("x".repeat(500)); expect(humanText.length).toBeLessThan(1800); const json = await runAgentRunCommand(null, [...baseArgs, "-o", "json"]); const jsonText = renderedTextOf(json); const payload = JSON.parse(jsonText) as { ok?: boolean; failureKind?: string; message?: string; agentrun?: { details?: { diagnostic?: string } } }; expect(json.ok).toBe(false); expect(renderedContentTypeOf(json)).toBe("application/json"); expect(payload.failureKind).toBe("validation-failed"); expect(payload.message?.length).toBeLessThanOrEqual(400); expect(payload.agentrun?.details?.diagnostic?.length).toBeLessThanOrEqual(400); expect(jsonText.length).toBeLessThan(5000); expect(requests).toBe(2); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); test("session send plan and typed partial-write errors stay homologous and bounded", async () => { const sessionId = "sess_artificer_fixture"; const runId = "run_partial_fixture"; const commandId = "cmd_partial_fixture"; const hiddenKubernetesPayload = "HIDDEN_KUBERNETES_PAYLOAD_MUST_NOT_BE_PRINTED"; let postRequests = 0; const server = Bun.serve({ port: 0, async fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); if (request.method === "GET" && url.pathname === `/api/v1/sessions/${sessionId}`) { return Response.json({ ok: true, data: { sessionId, tenantId: "unidesk", projectId: "test", providerId: "NC01", backendProfile: "codex", conversationId: sessionId, metadata: { title: "Artificer fixture" }, }, }); } if (request.method === "POST" && url.pathname === `/api/v1/sessions/${sessionId}/send`) { postRequests += 1; const body = await request.json() as Record; if (body.payload?.prompt === "plan fixture") { expect(body.dryRun).toBe(true); return Response.json({ ok: true, data: { action: "session-send-plan", dryRun: true, mutation: false, sessionId, decision: "turn", internalCommandType: "turn", activeBefore: null, reusedIdleRun: null, request: { method: "POST", path: `/api/v1/sessions/${sessionId}/send`, commandType: "turn", createRunnerJob: true, valuesPrinted: false }, next: { confirm: { action: "send-session", operation: "send", resourceKind: "session", resourceName: sessionId, sessionId, inputKind: "prompt", valuesPrinted: false }, note: "Remove --dry-run to perform the mutation.", }, valuesPrinted: false, }, }); } return Response.json({ ok: false, failureKind: "infra-failed", message: "kubectl get jobs failed with code 1", traceId: "trc_session_send_fixture", error: { name: "AgentRunError", failureKind: "infra-failed", message: "kubectl get jobs failed with code 1", details: { code: "runner-admission-failed", reason: "runner-retention-observation-failed", phase: "runner-admission", sessionId, runId, commandId, mutation: true, partialWrite: true, durable: true, resources: { session: { id: sessionId, state: "running" }, run: { id: runId, status: "queued" }, command: { id: commandId, state: "pending", type: "turn" }, }, recoveryActions: [ { operation: "describe", resourceKind: "session", resourceName: sessionId }, { operation: "events", resourceKind: "run", resourceName: runId, runId, afterSeq: 0, limit: 100 }, ], stderr: hiddenKubernetesPayload, rawKubernetesObject: { secret: hiddenKubernetesPayload }, valuesPrinted: false, }, }, }, { status: 502 }); } return new Response("not found", { status: 404 }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-session-send-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const planArgs = ["send", `session/${sessionId}`, "--prompt", "plan fixture", "--dry-run"]; const planHuman = renderedTextOf(await runAgentRunCommand(null, planArgs)); expect(planHuman).toContain("Session send plan"); expect(planHuman).toContain("Decision: turn"); expect(planHuman).toContain("ReuseRun: false"); expect(planHuman).toContain("CreateRunner: true"); expect(planHuman).toContain("Mutation: false"); expect(planHuman).not.toContain("[object Object]"); const planJsonText = renderedTextOf(await runAgentRunCommand(null, [...planArgs, "-o", "json"])); const planYamlText = renderedTextOf(await runAgentRunCommand(null, [...planArgs, "-o", "yaml"])); const planJson = JSON.parse(planJsonText) as Record; const planYaml = Bun.YAML.parse(planYamlText) as Record; expect(planYaml).toEqual(planJson); expect(planJson).toMatchObject({ kind: "SessionSendPlan", decision: "turn", dryRun: true, mutation: false, partialWrite: false, reuseRun: false, createRunner: true }); expect(planJson.resources.session).toEqual({ kind: "session", id: sessionId }); expect(planJson.next.actions[0]).toMatchObject({ mutation: true }); expect(planJson.next.actions[0].command).not.toContain("--dry-run"); const failureArgs = ["send", `session/${sessionId}`, "--prompt", "failure fixture"]; const failureHumanResult = await runAgentRunCommand(null, failureArgs); const failureHuman = renderedTextOf(failureHumanResult); expect(failureHumanResult.ok).toBe(false); expect(failureHuman).toContain("Session send failed"); expect(failureHuman).toContain("Error: validation-failed"); expect(failureHuman).toContain("TypedFailure: infra-failed"); expect(failureHuman).toContain("Code: runner-admission-failed"); expect(failureHuman).toContain("Reason: runner-retention-observation-failed"); expect(failureHuman).toContain("Mutation: true"); expect(failureHuman).toContain("PartialWrite: true"); expect(failureHuman).toContain(`session/${sessionId} state=running`); expect(failureHuman).toContain(`run/${runId} status=queued`); expect(failureHuman).toContain(`command/${commandId} state=pending type=turn`); expect(failureHuman).not.toContain(hiddenKubernetesPayload); expect(failureHuman).not.toContain("agentrun send"); const failureJsonResult = await runAgentRunCommand(null, [...failureArgs, "-o", "json"]); const failureYamlResult = await runAgentRunCommand(null, [...failureArgs, "-o", "yaml"]); const failureJsonText = renderedTextOf(failureJsonResult); const failureYamlText = renderedTextOf(failureYamlResult); const failureJson = JSON.parse(failureJsonText) as Record; const failureYaml = Bun.YAML.parse(failureYamlText) as Record; expect(failureJsonResult.ok).toBe(false); expect(failureYamlResult.ok).toBe(false); expect(failureYaml).toEqual(failureJson); expect(failureJson).toMatchObject({ kind: "SessionSendError", mutation: true, partialWrite: true, error: { failureKind: "validation-failed", typedFailureKind: "infra-failed", code: "runner-admission-failed", reason: "runner-retention-observation-failed", traceId: "trc_session_send_fixture", }, }); for (const bounded of [planHuman, planJsonText, planYamlText, failureHuman, failureJsonText, failureYamlText]) { expect(Buffer.byteLength(bounded, "utf8")).toBeLessThan(7000); expect(bounded).not.toContain(hiddenKubernetesPayload); expect(bounded).not.toContain("rawKubernetesObject"); } expect(postRequests).toBe(6); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); }); describe("AgentRun YAML tool credential binding", () => { test("aggregates managed GitHub SSH source keys into one volume credential and one sync target", () => { const { spec } = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }); const githubSsh = agentRunToolCredentialRefs(spec).filter((credential) => credential.tool === "github" && credential.purpose === "github-ssh"); expect(githubSsh).toEqual([{ sourceId: "github-ssh", tool: "github", purpose: "github-ssh", secretRef: { namespace: "agentrun-v02", name: "agentrun-v01-tool-github-ssh", keys: ["id_ed25519", "known_hosts"], }, projection: { kind: "volume", mountPath: "/home/agentrun/.ssh" }, valuesPrinted: false, }]); const sources = collectLaneSecretSources(spec).filter((source) => source.targetRef.name === "agentrun-v01-tool-github-ssh"); expect(sources.map((source) => ({ id: source.id, sourceMode: source.sourceMode, sourceRef: source.sourceRef, targetRef: source.targetRef }))).toEqual([ { id: "tool-github-ssh-private-key", sourceMode: "file", sourceRef: "deploy-ssh/github.com/id_ed25519", targetRef: { namespace: "agentrun-v02", name: "agentrun-v01-tool-github-ssh", key: "id_ed25519" }, }, { id: "tool-github-ssh-known-hosts", sourceMode: "file", sourceRef: "deploy-ssh/github.com/known_hosts", targetRef: { namespace: "agentrun-v02", name: "agentrun-v01-tool-github-ssh", key: "known_hosts" }, }, ]); const syncScript = secretSyncScript(spec, sources.map((source, index) => ({ targetRef: source.targetRef, value: `fixture-${index}` }))); const payloadMatch = syncScript.match(/^payload_b64='([^']+)'$/mu); expect(payloadMatch).not.toBeNull(); const syncManifest = JSON.parse(Buffer.from(payloadMatch?.[1] ?? "", "base64").toString("utf8")) as Array<{ targetRef: { namespace: string; name: string; key: string } }>; expect(syncManifest.map((item) => item.targetRef)).toEqual(sources.map((source) => source.targetRef)); expect(new Set(syncManifest.map((item) => `${item.targetRef.namespace}/${item.targetRef.name}`))).toEqual(new Set(["agentrun-v02/agentrun-v01-tool-github-ssh"])); expect(syncScript).toContain("groups.setdefault(key"); expect(JSON.stringify({ githubSsh, sources })).not.toContain("/root/.ssh"); }); test("preserves explicit credential subsets across Aipod admission and rejects unknown identities or conflicts", async () => { const renderBodies: Record[] = []; const submittedBodies: Record[] = []; let credentialMode: "all" | "subset" | "conflict" | "unknown" = "all"; const renderedToolCredentials = (): Record[] => { const credentials = [ { tool: "github", purpose: "github-pr", secretRef: { name: "agentrun-v01-tool-github-pr", keys: ["GH_TOKEN"] }, projection: { kind: "env", envName: "GH_TOKEN", secretKey: "GH_TOKEN" }, }, { tool: "unidesk-ssh", purpose: "ssh-passthrough", secretRef: { name: "agentrun-v01-tool-unidesk-ssh", keys: ["UNIDESK_SSH_CLIENT_TOKEN"] }, projection: { kind: "env", envName: "UNIDESK_SSH_CLIENT_TOKEN", secretKey: "UNIDESK_SSH_CLIENT_TOKEN" }, }, { tool: "github", purpose: "github-ssh", secretRef: { name: "agentrun-v01-tool-github-ssh", keys: credentialMode === "conflict" ? ["id_ed25519", "known_hosts", "config"] : ["id_ed25519", "known_hosts"], }, projection: { kind: "volume", mountPath: "/home/agentrun/.ssh" }, }, ]; if (credentialMode === "subset") return credentials.slice(0, 1); if (credentialMode === "unknown") { return [{ tool: "artifact-store", purpose: "publish", secretRef: { name: "agentrun-artifact-store", keys: ["TOKEN"] }, projection: { kind: "env", envName: "ARTIFACT_TOKEN", secretKey: "TOKEN" }, }]; } return credentials; }; const renderedTask = () => ({ tenantId: "unidesk", projectId: "pikasTech/unidesk", queue: "commander", lane: "v0.1", backendProfile: "codex", providerId: "NC01", workspaceRef: { kind: "opaque", path: "." }, executionPolicy: { sandbox: "workspace-write", approval: "never", timeoutMs: 1_800_000, network: "enabled", secretScope: { allowCredentialEcho: false, providerCredentials: [{ profile: "codex", secretRef: { name: "agentrun-v01-provider-codex", keys: ["auth.json", "config.toml"] }, }], toolCredentials: renderedToolCredentials(), }, }, payload: { prompt: "fixture" }, }); const server = Bun.serve({ port: 0, async fetch(request) { const url = new URL(request.url); expect(request.headers.get("authorization")).toBe("Bearer secret-value"); if (url.pathname === "/api/v1/aipod-specs/Artificer/render") { renderBodies.push(await request.json() as Record); return Response.json({ ok: true, data: { queueTask: renderedTask() } }); } if (url.pathname === "/api/v1/queue/tasks") { submittedBodies.push(await request.json() as Record); return Response.json({ ok: true, data: { id: "qt_fixture", state: "queued" } }); } return new Response("not found", { status: 404 }); }, }); const previousConfig = process.env.AGENTRUN_CLIENT_CONFIG; const previousKey = process.env.HWLAB_API_KEY; process.env.HWLAB_API_KEY = "secret-value"; const tempConfigPath = `/tmp/unidesk-agentrun-tool-credential-test-${process.pid}-${Date.now()}.yaml`; try { process.env.AGENTRUN_CLIENT_CONFIG = tempConfigPath; await Bun.write(tempConfigPath, agentRunMinimalClientYaml.replace("http://agentrun.example.local:8080", server.url.href.replace(/\/$/u, ""))); const accepted = await runAgentRunCommand(null, ["create", "task", "--aipod", "Artificer", "--prompt", "fixture", "--model", "gpt-explicit", "--reasoning-effort", "high", "-o", "json"]); expect(accepted.ok).toBe(true); expect(renderBodies).toHaveLength(1); expect(submittedBodies).toHaveLength(1); expect(renderBodies[0]?.backendProfile).toBeUndefined(); expect(renderBodies[0]?.executionPolicy).toBeUndefined(); expect(renderBodies[0]?.model).toBe("gpt-explicit"); expect(renderBodies[0]?.reasoningEffort).toBe("high"); expect(submittedBodies[0]).toEqual(renderedTask()); credentialMode = "subset"; const subsetAccepted = await runAgentRunCommand(null, ["create", "task", "--aipod", "Artificer", "--prompt", "fixture", "-o", "json"]); expect(subsetAccepted.ok).toBe(true); expect(renderBodies).toHaveLength(2); expect(submittedBodies).toHaveLength(2); expect(submittedBodies[1]).toEqual(renderedTask()); credentialMode = "conflict"; const rejected = await runAgentRunCommand(null, ["create", "task", "--aipod", "Artificer", "--prompt", "fixture", "-o", "json"]); expect(rejected.ok).toBe(false); expect(submittedBodies).toHaveLength(2); expect(renderedTextOf(rejected)).toContain("github/github-ssh keys conflict"); credentialMode = "unknown"; const unknownRejected = await runAgentRunCommand(null, ["create", "task", "--aipod", "Artificer", "--prompt", "fixture", "-o", "json"]); expect(unknownRejected.ok).toBe(false); expect(submittedBodies).toHaveLength(2); expect(renderedTextOf(unknownRejected)).toContain("artifact-store/publish is not declared by YAML lane"); } finally { server.stop(true); if (previousConfig === undefined) delete process.env.AGENTRUN_CLIENT_CONFIG; else process.env.AGENTRUN_CLIENT_CONFIG = previousConfig; if (previousKey === undefined) delete process.env.HWLAB_API_KEY; else process.env.HWLAB_API_KEY = previousKey; rmSync(tempConfigPath, { force: true }); } }); }); describe("AgentRun runner API key SecretRef", () => { test("renders manager runtime authority from the YAML runner SecretRef", () => { const { spec } = resolveAgentRunLaneTarget({ node: "NC01", lane: "nc01-v02" }); const files = renderAgentRunGitopsFiles(spec, { sourceCommit: "a".repeat(40), image: placeholderAgentRunImage(spec, "a".repeat(40)) }); const managerFile = files.find((file) => file.path.endsWith("/mgr.yaml")); expect(managerFile).toBeDefined(); const resources = (managerFile?.content ?? "").split(/\n---\n/u).map((document) => Bun.YAML.parse(document) as Record); const deployment = resources.find((resource) => resource.kind === "Deployment") as { spec?: { template?: { spec?: { containers?: Array<{ env?: Array<{ name?: string; value?: string }> }> } } } } | undefined; const env = deployment?.spec?.template?.spec?.containers?.[0]?.env ?? []; const values = new Map(env.map((item) => [item.name, item.value])); expect(values.get("AGENTRUN_RUNNER_API_KEY_SECRET_NAME")).toBe(spec.deployment.runner.apiKeySecretRef.name); expect(values.get("AGENTRUN_RUNNER_API_KEY_SECRET_KEY")).toBe(spec.deployment.runner.apiKeySecretRef.key); expect(spec.secrets.some((secret) => secret.targetRef.name === "agentrun-v01-api-key")).toBe(false); }); });