import assert from "node:assert/strict"; import { chmod, readFile, writeFile } from "node:fs/promises"; import path from "node:path"; import { startManagerServer } from "../../mgr/server.js"; import { MemoryAgentRunStore } from "../../mgr/store.js"; import { ManagerClient } from "../../mgr/client.js"; import type { JsonRecord } from "../../common/types.js"; import { assertNoSecretLeak, type SelfTestCase } from "../harness.js"; const secretText = "sk-selftest-provider-profile-secret"; const selfTest: SelfTestCase = async (context) => { const gitopsRenderer = await readFile(path.join(context.root, "scripts/src/gitops-render.ts"), "utf8"); assert.equal(gitopsRenderer.includes("agentrun-v01-mgr-provider-secret-manager"), true); assert.equal(gitopsRenderer.includes('verbs: ["create", "get", "patch", "update"]'), true); assert.equal(gitopsRenderer.includes('resourceNames: ["agentrun-v01-provider-codex", "agentrun-v01-provider-deepseek", "agentrun-v01-provider-minimax-m3", "agentrun-v01-provider-dsflash-go"]'), true); for (const profile of ["codex", "deepseek", "minimax-m3", "dsflash-go"]) { assert.equal(gitopsRenderer.includes(`agentrun-v01-provider-${profile}`), true); } const fakeKubectl = path.join(context.tmp, "fake-provider-kubectl.js"); const replacedSecretPath = path.join(context.tmp, "provider-secret-replace.json"); const createdSecretPath = path.join(context.tmp, "provider-secret-create.json"); const cleanupPatchPath = path.join(context.tmp, "provider-secret-cleanup-patch.json"); const createdJobPath = path.join(context.tmp, "provider-validation-job.json"); const secretStateDir = path.join(context.tmp, "provider-secret-state"); await writeFile(fakeKubectl, `#!/usr/bin/env bun const args = Bun.argv.slice(2); const secretStateDir = ${JSON.stringify(secretStateDir)}; const secretStatePath = (name) => secretStateDir + "/" + name + ".json"; const fixtureSecret = (name) => ({ apiVersion: "v1", kind: "Secret", metadata: { name, namespace: "agentrun-v01", resourceVersion: "rv-selftest", creationTimestamp: "2026-06-05T00:00:00.000Z" }, data: { "auth.json": Buffer.from(JSON.stringify({ token: "redacted-fixture" })).toString("base64"), "config.toml": Buffer.from("model = \\\"fixture\\\"\\n").toString("base64") } }); const readStdin = async () => { const chunks = []; for await (const chunk of Bun.stdin.stream()) chunks.push(Buffer.from(chunk)); return Buffer.concat(chunks).toString("utf8"); }; if (args[0] === "get" && args[1] === "secret") { const name = args[2]; const stateFile = Bun.file(secretStatePath(name)); if (await stateFile.exists()) { console.log(await stateFile.text()); process.exit(0); } if (name === "agentrun-v01-provider-dsflash-go") { console.error('Error from server (NotFound): secrets "' + name + '" not found'); process.exit(1); } console.log(JSON.stringify(fixtureSecret(name))); process.exit(0); } if (args[0] === "apply") { console.error("provider credential updates must not use kubectl apply"); process.exit(1); } if (args[0] === "patch" && args[1] === "secret" && args.includes("--patch-file")) { console.error("provider credential updates must not use kubectl patch --patch-file"); process.exit(1); } if (args[0] === "patch" && args[1] === "secret") { const patchArg = args[args.indexOf("-p") + 1] ?? "{}"; const patch = JSON.parse(patchArg); await Bun.write(${JSON.stringify(cleanupPatchPath)}, JSON.stringify({ args, patch }, null, 2)); if (patch.metadata?.annotations?.["kubectl.kubernetes.io/last-applied-configuration"] !== null) { console.error("provider credential patch may only remove last-applied annotation"); process.exit(1); } console.log(JSON.stringify({ apiVersion: "v1", kind: "Secret", metadata: { name: args[2], namespace: "agentrun-v01", resourceVersion: "rv-cleaned", annotations: { "agentrun.pikastech.local/provider-profile-updated-at": "2026-06-05T00:00:01.000Z" } }, data: { "auth.json": "REDACTED", "config.toml": "REDACTED" } })); process.exit(0); } if (args[0] === "replace") { const text = await readStdin(); const manifest = JSON.parse(text); if (manifest.metadata?.name === "agentrun-v01-provider-dsflash-go") { const stateFile = Bun.file(secretStatePath(manifest.metadata.name)); if (!(await stateFile.exists())) { console.error('Error from server (NotFound): secrets "' + manifest.metadata.name + '" not found'); process.exit(1); } } await Bun.write(${JSON.stringify(replacedSecretPath)}, JSON.stringify({ args, manifest }, null, 2)); const annotations = manifest.metadata?.annotations ?? {}; await Bun.write(secretStatePath(manifest.metadata.name), JSON.stringify({ ...manifest, metadata: { ...(manifest.metadata ?? {}), resourceVersion: "rv-replaced", annotations } })); console.log(JSON.stringify({ apiVersion: "v1", kind: "Secret", metadata: { name: manifest.metadata.name, namespace: manifest.metadata.namespace, resourceVersion: "rv-replaced", annotations } })); process.exit(0); } if (args[0] === "create") { const text = await readStdin(); const manifest = JSON.parse(text); if (manifest.kind === "Secret") { const annotations = manifest.metadata?.annotations ?? {}; await Bun.write(${JSON.stringify(createdSecretPath)}, JSON.stringify({ args, manifest }, null, 2)); await Bun.write(secretStatePath(manifest.metadata.name), JSON.stringify({ ...manifest, metadata: { ...(manifest.metadata ?? {}), resourceVersion: "rv-created", annotations } })); console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { name: manifest.metadata.name, namespace: manifest.metadata.namespace, resourceVersion: "rv-created", annotations } })); process.exit(0); } await Bun.write(${JSON.stringify(createdJobPath)}, text); console.log(JSON.stringify({ apiVersion: manifest.apiVersion, kind: manifest.kind, metadata: { uid: "job-provider-validation", resourceVersion: "rv-job", name: manifest.metadata.name, namespace: manifest.metadata.namespace } })); process.exit(0); } console.error("unsupported fake kubectl args: " + JSON.stringify(args)); process.exit(1); `); await chmod(fakeKubectl, 0o755); const store = new MemoryAgentRunStore(); const server = await startManagerServer({ port: 0, host: "127.0.0.1", sourceCommit: "self-test", store, providerProfileOptions: { namespace: "agentrun-v01", kubectlCommand: fakeKubectl }, runnerJobDefaults: { namespace: "agentrun-v01", managerUrl: "http://agentrun-mgr.agentrun-v01.svc.cluster.local:8080", image: "127.0.0.1:5000/agentrun/agentrun-mgr@sha256:2222222222222222222222222222222222222222222222222222222222222222", kubectlCommand: fakeKubectl, }, }); try { const client = new ManagerClient(server.baseUrl); const list = await client.get("/api/v1/provider-profiles") as JsonRecord; assert.equal(list.count, 4); assert.equal(JSON.stringify(list).includes("auth.json"), true); assert.equal(JSON.stringify(list).includes("redacted-fixture"), false); const listItems = (list.items as JsonRecord[]) ?? []; const dsflashStatus = listItems.find((item) => item.profile === "dsflash-go") as JsonRecord | undefined; assert.equal(dsflashStatus?.configured, false); assert.equal(dsflashStatus?.failureKind, "secret-unavailable"); const config = await client.get("/api/v1/provider-profiles/deepseek/config") as JsonRecord; assert.equal(config.profile, "deepseek"); assert.equal(config.configToml, "model = \"fixture\"\n"); assert.equal(config.configTomlPrinted, true); assert.equal(JSON.stringify(config).includes("redacted-fixture"), false); const updatedConfigToml = "model = \"fixture-updated\"\n"; const updatedConfig = await client.put("/api/v1/provider-profiles/deepseek/config", { configToml: updatedConfigToml, delegatedBy: { system: "hwlab-v02", userId: "u1", username: "tester", requestId: "req-config-selftest" }, reason: "self-test", }) as JsonRecord; assert.equal(updatedConfig.profile, "deepseek"); assert.equal(updatedConfig.configTomlPrinted, false); assert.equal(JSON.stringify(updatedConfig).includes(updatedConfigToml), false); const configReplaceRecord = JSON.parse(await readFile(replacedSecretPath, "utf8")) as JsonRecord; const configSecretManifest = configReplaceRecord.manifest as JsonRecord; const configData = configSecretManifest.data as JsonRecord; assert.equal(Buffer.from(String(configData["auth.json"]), "base64").toString("utf8").includes("redacted-fixture"), true); assert.equal(Buffer.from(String(configData["config.toml"]), "base64").toString("utf8"), updatedConfigToml); const updated = await client.put("/api/v1/provider-profiles/deepseek/credential", { apiKey: secretText, delegatedBy: { system: "hwlab-v02", userId: "u1", username: "tester", requestId: "req-selftest" }, reason: "self-test", }) as JsonRecord; assert.equal(updated.profile, "deepseek"); assert.equal(updated.resourceVersion, "rv-cleaned"); assert.equal(updated.requiresExternalBridgeUpdate, true); assert.equal(JSON.stringify(updated).includes(secretText), false); assertNoSecretLeak(updated); const replaceRecord = JSON.parse(await readFile(replacedSecretPath, "utf8")) as JsonRecord; const replaceArgs = replaceRecord.args as string[]; assert.deepEqual(replaceArgs, ["replace", "-f", "-", "-o", "json"]); const secretManifest = replaceRecord.manifest as JsonRecord; assert.equal(secretManifest.kind, "Secret"); assert.equal(((secretManifest.metadata as JsonRecord).name), "agentrun-v01-provider-deepseek"); assert.equal(((secretManifest.metadata as JsonRecord).namespace), "agentrun-v01"); const annotations = (secretManifest.metadata as JsonRecord).annotations as JsonRecord; assert.equal(Object.hasOwn(annotations, "kubectl.kubernetes.io/last-applied-configuration"), false); const cleanupRecord = JSON.parse(await readFile(cleanupPatchPath, "utf8")) as JsonRecord; const cleanupArgs = cleanupRecord.args as string[]; assert.deepEqual(cleanupArgs, ["patch", "secret", "agentrun-v01-provider-deepseek", "-n", "agentrun-v01", "--type", "merge", "-p", JSON.stringify({ metadata: { annotations: { "kubectl.kubernetes.io/last-applied-configuration": null } } }), "-o", "json"]); const cleanupPatch = cleanupRecord.patch as JsonRecord; assert.deepEqual(cleanupPatch, { metadata: { annotations: { "kubectl.kubernetes.io/last-applied-configuration": null } } }); const data = secretManifest.data as JsonRecord; const authJson = Buffer.from(String(data["auth.json"]), "base64").toString("utf8"); const configToml = Buffer.from(String(data["config.toml"]), "base64").toString("utf8"); assert.equal(authJson.includes(secretText), true); assert.equal(authJson.includes("OPENAI_API_KEY"), true); assert.equal(configToml.includes("hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local"), true); assert.equal(configToml.includes("hyueapi.com"), false); const dsflashCreated = await client.put("/api/v1/provider-profiles/dsflash-go/credential", { apiKey: secretText, delegatedBy: { system: "hwlab-v02", userId: "u2", username: "tester2", requestId: "req-dsflash-create-selftest" }, reason: "self-test-dsflash-create", }) as JsonRecord; assert.equal(dsflashCreated.profile, "dsflash-go"); assert.equal(dsflashCreated.resourceVersion, "rv-created"); assert.equal(dsflashCreated.requiresExternalBridgeUpdate, true); const createRecord = JSON.parse(await readFile(createdSecretPath, "utf8")) as JsonRecord; const createArgs = createRecord.args as string[]; assert.deepEqual(createArgs, ["create", "-f", "-", "-o", "json"]); const createdSecretManifest = createRecord.manifest as JsonRecord; assert.equal(((createdSecretManifest.metadata as JsonRecord).name), "agentrun-v01-provider-dsflash-go"); const createdData = createdSecretManifest.data as JsonRecord; const createdAuthJson = Buffer.from(String(createdData["auth.json"]), "base64").toString("utf8"); const createdConfigToml = Buffer.from(String(createdData["config.toml"]), "base64").toString("utf8"); assert.equal(createdAuthJson.includes(secretText), true); assert.equal(createdAuthJson.includes("OPENAI_API_KEY"), true); assert.equal(createdConfigToml.includes("deepseek-v4-flash"), true); assert.equal(createdConfigToml.includes("hwlab-deepseek-proxy.hwlab-v02.svc.cluster.local"), true); const dsflashShown = await client.get("/api/v1/provider-profiles/dsflash-go") as JsonRecord; assert.equal(dsflashShown.configured, true); assert.equal(dsflashShown.failureKind, null); assertNoSecretLeak(dsflashCreated); await assert.rejects( () => client.put("/api/v1/provider-profiles/deepseek/credential", { apiKey: secretText, config: { baseUrl: "https://hyueapi.com/v1" } }), (error) => error instanceof Error && error.message.includes("not hyueapi.com"), ); const validation = await client.post("/api/v1/provider-profiles/deepseek/validate", {}) as JsonRecord; assert.equal(validation.profile, "deepseek"); assert.equal(validation.status, "running"); assert.equal(typeof validation.validationId, "string"); const validationId = String(validation.validationId); const validationRun = await store.getRun(String(validation.runId)) as JsonRecord; assert.equal((validationRun.workspaceRef as JsonRecord).path, "/home/agentrun/agentrun-source"); const jobManifest = JSON.parse(await readFile(createdJobPath, "utf8")) as JsonRecord; assert.equal(JSON.stringify(jobManifest).includes("agentrun-v01-provider-deepseek"), true); assert.equal(JSON.stringify(jobManifest).includes(secretText), false); assertNoSecretLeak(validation); await client.post(`/api/v1/runs/${encodeURIComponent(String(validation.runId))}/events`, { type: "assistant_message", payload: { commandId: validation.commandId, text: "AGENTRUN_PROVIDER_PROFILE_OK_DEEPSEEK", final: true, replyAuthority: true } }); await client.patch(`/api/v1/commands/${encodeURIComponent(String(validation.commandId))}/status`, { terminalStatus: "completed", failureKind: null, failureMessage: null }); const finalValidation = await client.get(`/api/v1/provider-profiles/deepseek/validations/${encodeURIComponent(validationId)}`) as JsonRecord; assert.equal(finalValidation.status, "completed"); assert.equal(JSON.stringify(finalValidation).includes(secretText), false); assertNoSecretLeak(finalValidation); return { name: "provider-profile-management", tests: ["provider-profiles-list-redacted", "provider-profile-config", "provider-profile-set-key-redacted", "provider-profile-secret-replace-annotation-cleanup", "provider-profile-secret-create-upsert", "provider-profile-deepseek-moon-bridge", "provider-profile-manager-secret-rbac", "provider-profile-validation-runner-job"] }; } finally { await new Promise((resolve) => server.server.close(() => resolve())); } }; export default selfTest;