238c270ac4
Co-authored-by: Codex <codex@noreply.local>
165 lines
6.3 KiB
TypeScript
165 lines
6.3 KiB
TypeScript
import { readFileSync, rmSync } from "node:fs";
|
|
import { describe, expect, test } from "bun:test";
|
|
import { parseAgentRunClientConfigYaml, resolveAgentRunAuth, runAgentRunCommand, stripAgentRunResourceWrapperArgs } from "./agentrun";
|
|
|
|
const agentRunClientYaml = [
|
|
"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",
|
|
].join("\n");
|
|
|
|
const agentRunMinimalClientYaml = [
|
|
"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",
|
|
].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",
|
|
"--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.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 });
|
|
}
|
|
});
|
|
});
|