Files
pikasTech-HWLAB/internal/cloud/provider-profile-management.test.ts
T
2026-07-09 13:57:35 +02:00

426 lines
22 KiB
TypeScript

import assert from "node:assert/strict";
import { createServer as createHttpServer } from "node:http";
import { test } from "bun:test";
import { createCloudApiServer } from "./server.ts";
const adminActor = { id: "usr_admin", username: "admin", displayName: "Admin", role: "admin", status: "active" };
const userActor = { id: "usr_user", username: "user", displayName: "User", role: "user", status: "active" };
test("provider profile management requires HWLAB admin auth before AgentRun delegation", async () => {
const calls: unknown[] = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: userActor })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles`, { headers: { cookie: "hwlab_session=user" } });
const body = await response.json();
assert.equal(response.status, 403);
assert.equal(body.error.code, "admin_required");
assert.equal(calls.length, 0);
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile catalog is readable to authenticated non-admin actors and redacts management-only fields", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: userActor })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/provider-profiles`, { headers: { cookie: "hwlab_session=user" } });
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.contractVersion, "provider-profile-management-v1");
assert.equal(body.count, 4);
const profiles = body.items.map((item: any) => item.profile);
assert.equal(profiles.includes("deepseek"), true);
assert.equal(profiles.includes("codex-api"), true);
assert.equal(profiles.includes("minimax-m3"), true);
assert.equal(profiles.includes("dsflash-go-cli-example"), true);
assert.equal(body.items[0].secretRef, undefined);
assert.equal(body.items[0].credentialHashSuffix, undefined);
assert.equal(body.items[0].bridge.route, "HWLAB Moon Bridge -> DeepSeek official upstream");
assert.equal(JSON.stringify(body).includes("auth.json"), false);
assert.equal(calls[0].method, "GET");
assert.equal(calls[0].path, "/api/v1/provider-profiles");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profiles collection delegates to AgentRun, rewrites codex profile, and preserves dynamic slugs", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles`, { headers: { cookie: "hwlab_session=admin" } });
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.contractVersion, "provider-profile-management-v1");
assert.equal(body.delegation.agentRunHost, "127.0.0.1");
const profiles = body.items.map((item: any) => item.profile);
assert.equal(body.count, 4);
assert.equal(profiles.includes("deepseek"), true);
assert.equal(profiles.includes("codex-api"), true);
assert.equal(profiles.includes("minimax-m3"), true);
assert.equal(profiles.includes("dsflash-go-cli-example"), true);
assert.equal(body.items[0].bridge.route, "HWLAB Moon Bridge -> DeepSeek official upstream");
assert.equal(JSON.stringify(body).includes("auth.json"), true);
assert.equal(JSON.stringify(body).includes("sk-test"), false);
assert.equal(calls[0].method, "GET");
assert.equal(calls[0].path, "/api/v1/provider-profiles");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile set-key delegates through HWLAB without echoing API key", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor, authMethod: "api-key" })
});
await listen(server);
const { port } = server.address() as { port: number };
const key = "sk-test-provider-secret-123456";
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/deepseek/credential`, {
method: "PUT",
headers: { "content-type": "application/json", authorization: "Bearer hwlab-test" },
body: JSON.stringify({ apiKey: key })
});
const body = await response.json();
const text = JSON.stringify(body);
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.status, "updated");
assert.equal(body.profile, "deepseek");
assert.equal(body.data.requiresExternalBridgeUpdate, true);
assert.equal(text.includes(key), false);
assert.equal(text.includes("Bearer hwlab-test"), false);
assert.equal(calls[0].method, "PUT");
assert.equal(calls[0].path, "/api/v1/provider-profiles/deepseek/credential");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[0].authorization?.includes(key), false);
assert.equal(calls[0].body.apiKey, key);
assert.equal(calls[0].body.delegatedBy.system, "hwlab-v02");
assert.equal(calls[0].body.delegatedBy.userId, "usr_admin");
assert.equal(calls[0].body.delegatedBy.authMethod, "api-key");
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile management accepts lane-specific AgentRun manager namespace", async () => {
const calls: Array<{ method?: string; path?: string; host?: string; authorization?: string }> = [];
const server = createCloudApiServer({
env: {
AGENTRUN_MGR_URL: "http://agentrun-mgr.agentrun-v02.svc.cluster.local:8080",
AGENTRUN_API_KEY: "test-agentrun-key",
HWLAB_ACCESS_CONTROL_REQUIRED: "1"
},
fetchImpl: async (url: string, init: any = {}) => {
const parsed = new URL(url);
calls.push({ method: init.method, path: parsed.pathname, host: parsed.hostname, authorization: init.headers?.authorization });
return new Response(JSON.stringify({ ok: true, data: { items: [], count: 0, valuesPrinted: false }, valuesPrinted: false }), { status: 200 });
},
accessController: fakeAccessController({ actor: adminActor })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles`, { headers: { cookie: "hwlab_session=admin" } });
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(calls[0].method, "GET");
assert.equal(calls[0].host, "agentrun-mgr.agentrun-v02.svc.cluster.local");
assert.equal(calls[0].path, "/api/v1/provider-profiles");
assert.equal(calls[0].authorization, "Bearer test-agentrun-key");
assert.equal(JSON.stringify(body).includes("test-agentrun-key"), false);
} finally {
await close(server);
}
});
test("provider profile auth-json delegates through HWLAB without echoing auth json", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor, authMethod: "api-key" })
});
await listen(server);
const { port } = server.address() as { port: number };
const authJson = `${JSON.stringify({ OPENAI_API_KEY: "sk-test-provider-secret-123456" })}\n`;
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/hy/credential`, {
method: "PUT",
headers: { "content-type": "application/json", authorization: "Bearer hwlab-test" },
body: JSON.stringify({ authJson })
});
const body = await response.json();
const text = JSON.stringify(body);
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.status, "updated");
assert.equal(body.profile, "hy");
assert.equal(text.includes("OPENAI_API_KEY"), false);
assert.equal(text.includes("sk-test-provider-secret-123456"), false);
assert.equal(calls[0].method, "PUT");
assert.equal(calls[0].path, "/api/v1/provider-profiles/hy/credential");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[0].body.authJson, authJson);
assert.equal(calls[0].body.apiKey, undefined);
assert.equal(calls[0].body.delegatedBy.system, "hwlab-v02");
assert.equal(calls[0].body.delegatedBy.authMethod, "api-key");
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile config reads and writes config.toml through AgentRun", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor })
});
await listen(server);
const { port } = server.address() as { port: number };
const configToml = 'model = "deepseek-chat"\nbase_url = "http://bridge/v1"\n';
try {
const read = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/deepseek/config`, { headers: { cookie: "hwlab_session=admin" } });
const readBody = await read.json();
assert.equal(read.status, 200);
assert.equal(readBody.ok, true);
assert.equal(readBody.profile, "deepseek");
assert.equal(readBody.data.configToml, configToml);
assert.equal(readBody.data.configTomlPrinted, true);
assert.equal(JSON.stringify(readBody).includes("sk-test"), false);
const write = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/deepseek/config`, {
method: "PUT",
headers: { "content-type": "application/json", cookie: "hwlab_session=admin" },
body: JSON.stringify({ configToml: `${configToml}# edited\n` })
});
const writeBody = await write.json();
assert.equal(write.status, 200);
assert.equal(writeBody.status, "updated");
assert.equal(JSON.stringify(writeBody).includes("# edited"), false);
assert.equal(calls[0].method, "GET");
assert.equal(calls[0].path, "/api/v1/provider-profiles/deepseek/config");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[1].method, "PUT");
assert.equal(calls[1].path, "/api/v1/provider-profiles/deepseek/config");
assert.equal(calls[1].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[1].body.configToml, `${configToml}# edited\n`);
assert.equal(calls[1].body.delegatedBy.system, "hwlab-v02");
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile remove delegates through HWLAB and preserves redaction", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor, authMethod: "api-key" })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/deepseek`, {
method: "DELETE",
headers: { authorization: "Bearer hwlab-test" }
});
const body = await response.json();
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.status, "removed");
assert.equal(body.profile, "deepseek");
assert.equal(body.data.removed, true);
assert.equal(body.data.builtinCapabilityRetained, true);
assert.equal(JSON.stringify(body).includes("sk-test"), false);
assert.equal(calls[0].method, "DELETE");
assert.equal(calls[0].path, "/api/v1/provider-profiles/deepseek");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[0].body, null);
} finally {
await close(server);
await close(agentRunServer);
}
});
test("provider profile real test delegates prompt and model through AgentRun validation", async () => {
const calls: Array<AgentRunCall> = [];
const agentRunServer = await startAgentRunServer(calls);
const { port: agentRunPort } = agentRunServer.address() as { port: number };
const server = createCloudApiServer({
env: testEnv(agentRunPort),
accessController: fakeAccessController({ actor: adminActor })
});
await listen(server);
const { port } = server.address() as { port: number };
try {
const response = await fetch(`http://127.0.0.1:${port}/v1/admin/provider-profiles/gpt.pika/test`, {
method: "POST",
headers: { "content-type": "application/json", cookie: "hwlab_session=admin" },
body: JSON.stringify({ model: "gpt-5.4-mini", prompt: "只回复 OK" })
});
const body = await response.json();
const text = JSON.stringify(body);
assert.equal(response.status, 200);
assert.equal(body.ok, true);
assert.equal(body.profile, "gpt.pika");
assert.equal(body.data.profile, "gpt.pika");
assert.equal(body.data.backendProfile, "gpt-pika");
assert.equal(body.data.model, "gpt-5.4-mini");
assert.equal(body.data.validationId, "val_1234567890abcdef1234567890abcdef");
assert.equal(text.includes("sk-test"), false);
assert.equal(calls[0].method, "POST");
assert.equal(calls[0].path, "/api/v1/provider-profiles/gpt-pika/validate");
assert.equal(calls[0].authorization, "Bearer test-agentrun-manager-key");
assert.equal(calls[0].body.model, "gpt-5.4-mini");
assert.equal(calls[0].body.prompt, "只回复 OK");
assert.equal(calls[0].body.delegatedBy.system, "hwlab-v02");
} finally {
await close(server);
await close(agentRunServer);
}
});
function testEnv(port: number) {
return {
HWLAB_CODE_AGENT_AGENTRUN_MGR_URL: `http://127.0.0.1:${port}`,
AGENTRUN_API_KEY: "test-agentrun-manager-key",
HWLAB_PROVIDER_PROFILE_AGENTRUN_ALLOW_NON_K3S_URL: "1",
HWLAB_ACCESS_CONTROL_REQUIRED: "1"
};
}
type AgentRunCall = { method?: string; path?: string; body?: any; authorization?: string };
function fakeAccessController({ actor, authMethod = "web-session" }: { actor: any; authMethod?: string }) {
return {
required: true,
async authenticate(request: any, { required = true } = {}) {
const hasAuth = Boolean(request.headers?.cookie || request.headers?.authorization);
if (!hasAuth && required) return { ok: false, status: 401, error: { code: "auth_required", message: "Authentication is required" } };
return { ok: true, actor, session: { id: "ses_test", userId: actor.id }, authMethod };
},
async handleAuthRoute() { throw new Error("not used"); },
async handleUserRoute() { throw new Error("not used"); },
async handleAccessStatusRoute() { throw new Error("not used"); },
async handleSetupRoute() { throw new Error("not used"); },
async handleAdminRoute() { throw new Error("provider profile route should bypass generic admin route"); },
configureCodeAgentWorkspaceContext() {}
};
}
async function startAgentRunServer(calls: Array<AgentRunCall>) {
const server = createHttpServer(async (request, response) => {
const url = new URL(request.url || "/", "http://127.0.0.1");
const chunks = [];
for await (const chunk of request) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf8")) : null;
calls.push({ method: request.method, path: url.pathname, body, authorization: request.headers.authorization });
response.writeHead(200, { "content-type": "application/json" });
if (request.method === "GET" && url.pathname === "/api/v1/provider-profiles") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_profiles", data: { items: [profile("deepseek"), profile("codex"), profile("minimax-m3"), profile("dsflash-go-cli-example")], count: 4, valuesPrinted: false } })}\n`);
return;
}
if (request.method === "PUT" && url.pathname === "/api/v1/provider-profiles/deepseek/credential") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_set_key", data: { action: "provider-profile-credential-updated", mutation: true, profile: "deepseek", configured: true, secretRef: { namespace: "agentrun-v01", name: "agentrun-v01-provider-deepseek", keys: ["auth.json", "config.toml"] }, credentialHashSuffix: "abc12345", configHashSuffix: "def67890", updatedAt: "2026-06-05T08:00:00.000Z", requiresExternalBridgeUpdate: true, valuesPrinted: false } })}\n`);
return;
}
if (request.method === "PUT" && url.pathname === "/api/v1/provider-profiles/hy/credential") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_set_auth_json", data: { action: "provider-profile-credential-updated", mutation: true, profile: "hy", configured: true, credentialSource: "auth-json", secretRef: { namespace: "agentrun-v01", name: "agentrun-v01-provider-hy", keys: ["auth.json", "config.toml"] }, credentialHashSuffix: "1234abcd", configHashSuffix: "def67890", updatedAt: "2026-06-05T08:00:00.000Z", valuesPrinted: false } })}\n`);
return;
}
if (request.method === "GET" && url.pathname === "/api/v1/provider-profiles/deepseek/config") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_config", data: { action: "provider-profile-config", profile: "deepseek", configured: true, secretRef: { namespace: "agentrun-v01", name: "agentrun-v01-provider-deepseek", keys: ["auth.json", "config.toml"] }, credentialHashSuffix: "abc12345", configHashSuffix: "def67890", updatedAt: "2026-06-05T08:00:00.000Z", configToml: 'model = "deepseek-chat"\nbase_url = "http://bridge/v1"\n', configTomlPrinted: true, credentialValuesPrinted: false, valuesPrinted: false } })}\n`);
return;
}
if (request.method === "PUT" && url.pathname === "/api/v1/provider-profiles/deepseek/config") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_set_config", data: { action: "provider-profile-config-updated", mutation: true, profile: "deepseek", configured: true, secretRef: { namespace: "agentrun-v01", name: "agentrun-v01-provider-deepseek", keys: ["auth.json", "config.toml"] }, credentialHashSuffix: "abc12345", configHashSuffix: "fedcba98", updatedAt: "2026-06-05T08:01:00.000Z", valuesPrinted: false } })}\n`);
return;
}
if (request.method === "DELETE" && url.pathname === "/api/v1/provider-profiles/deepseek") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_remove", data: { action: "provider-profile-removed", mutation: true, profile: "deepseek", configured: false, removed: true, builtinCapabilityRetained: true, secretRef: { namespace: "agentrun-v01", name: "agentrun-v01-provider-deepseek", keys: ["auth.json", "config.toml"] }, deletedResourceVersion: "rv-removed", credentialHashSuffix: "abc12345", configHashSuffix: "def67890", updatedAt: "2026-06-05T08:02:00.000Z", valuesPrinted: false } })}\n`);
return;
}
if (request.method === "POST" && url.pathname === "/api/v1/provider-profiles/gpt-pika/validate") {
response.end(`${JSON.stringify({ ok: true, traceId: "trc_test_submit", data: { action: "provider-profile-validation-started", validationId: "val_1234567890abcdef1234567890abcdef", profile: "gpt-pika", model: body?.model, runId: "run_profile_test", commandId: "cmd_profile_test", jobName: "agentrun-nc01-v02-runner-profile-test", status: "running", valuesPrinted: false } })}\n`);
return;
}
response.end(`${JSON.stringify({ ok: false, error: { code: "unexpected", message: `${request.method} ${url.pathname}` } })}\n`);
});
await listen(server);
return server;
}
function profile(name: string) {
return {
profile: name,
backendKind: name,
configured: true,
secretRef: { namespace: "agentrun-v01", name: `agentrun-v01-provider-${name}`, keys: ["auth.json", "config.toml"] },
credentialHashSuffix: "abc12345",
configHashSuffix: "def67890",
updatedAt: "2026-06-05T08:00:00.000Z",
valuesPrinted: false
};
}
function listen(server: any) {
return new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
}
function close(server: any) {
return new Promise<void>((resolve, reject) => server.close((error: Error | undefined) => (error ? reject(error) : resolve())));
}