import assert from "node:assert/strict"; import { test } from "bun:test"; import { createCloudApiServer } from "./server.ts"; test("cloud api access control grants visible device pods and blocks unavailable gateway jobs", async () => { const server = createCloudApiServer({ env: { HWLAB_ACCESS_CONTROL_REQUIRED: "1", HWLAB_BOOTSTRAP_ADMIN_USERNAME: "admin", HWLAB_BOOTSTRAP_ADMIN_PASSWORD: "admin-pass" }, now: () => "2026-05-28T00:00:00.000Z" }); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); try { const { port } = server.address(); const adminLogin = await postJson(port, "/auth/login", { username: "admin", password: "admin-pass" }); assert.equal(adminLogin.status, 200); assert.equal(adminLogin.body.actor.role, "admin"); const adminCookie = adminLogin.cookie; const userCreate = await postJson(port, "/v1/admin/users", { username: "alice", password: "alice-pass", displayName: "Alice" }, adminCookie); assert.equal(userCreate.status, 201); assert.equal(userCreate.body.user.username, "alice"); assert.equal(JSON.stringify(userCreate.body).includes("alice-pass"), false); const podCreate = await postJson(port, "/v1/admin/device-pods", { devicePodId: "device-pod-71-freq", name: "71-FREQ", profile: { schemaVersion: 1, target: { id: "target-71-freq" }, projectWorkspace: { projectPath: "FirmWare/MDK-ARM/app.uvprojx", targetName: "app" }, route: { gatewaySessionId: "gws_missing", resourceId: "res_windows_host", capabilityId: "cap_device_host_cli", hostCli: "node tools/device-host-cli.mjs" } } }, adminCookie); assert.equal(podCreate.status, 201); assert.equal(podCreate.body.devicePod.profile.route.gatewaySessionId, "redacted"); assert.equal(JSON.stringify(podCreate.body).includes("gws_missing"), false); const emptyLogin = await postJson(port, "/auth/login", { username: "alice", password: "alice-pass" }); assert.equal(emptyLogin.status, 200); const aliceCookie = emptyLogin.cookie; const emptyList = await getJson(port, "/v1/device-pods", aliceCookie); assert.equal(emptyList.status, 200); assert.deepEqual(emptyList.body.devicePods, []); const grant = await postJson(port, "/v1/admin/device-pod-grants", { devicePodId: "device-pod-71-freq", userId: userCreate.body.user.id }, adminCookie); assert.equal(grant.status, 201); const visible = await getJson(port, "/v1/device-pods", aliceCookie); assert.equal(visible.status, 200); assert.equal(visible.body.contractVersion, "device-pod-authority-v1"); assert.equal(visible.body.source.kind, "CLOUD_API_PROFILE_AUTHORITY"); assert.equal(visible.body.source.fake, false); assert.equal(visible.body.devicePods.length, 1); assert.equal(visible.body.devicePods[0].devicePodId, "device-pod-71-freq"); assert.match(visible.body.devicePods[0].profileHash, /^sha256:/u); const job = await postJson(port, "/v1/device-pods/device-pod-71-freq/jobs", { intent: "workspace.ls", args: { path: "." } }, aliceCookie); assert.equal(job.status, 409); assert.equal(job.body.status, "blocked"); assert.equal(job.body.blocker.code, "gateway_dispatch_unavailable"); assert.equal(job.body.devicePodId, "device-pod-71-freq"); assert.equal(job.body.profileHash, visible.body.devicePods[0].profileHash); const events = await getJson(port, "/v1/device-pods/device-pod-71-freq/events", aliceCookie); assert.equal(events.status, 200); assert.equal(events.body.events[0].blocker.code, "gateway_dispatch_unavailable"); const unsupported = await postJson(port, "/v1/device-pods/device-pod-71-freq/jobs", { intent: "debug.erase-all", args: {} }, aliceCookie); assert.equal(unsupported.status, 400); assert.equal(unsupported.body.error.code, "unsupported_device_job_intent"); const revoke = await fetch(`http://127.0.0.1:${port}/v1/admin/device-pod-grants/device-pod-71-freq/${userCreate.body.user.id}`, { method: "DELETE", headers: { cookie: adminCookie } }); assert.equal(revoke.status, 200); const revoked = await revoke.json(); assert.equal(revoked.devicePodId, "device-pod-71-freq"); assert.equal(revoked.userId, userCreate.body.user.id); const afterRevoke = await getJson(port, "/v1/device-pods", aliceCookie); assert.equal(afterRevoke.status, 200); assert.deepEqual(afterRevoke.body.devicePods, []); } finally { await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))); } }); test("cloud api protects device-pod routes when access control is required", async () => { const server = createCloudApiServer({ env: { HWLAB_ACCESS_CONTROL_REQUIRED: "1" }, now: () => "2026-05-28T00:00:00.000Z" }); await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); try { const { port } = server.address(); const response = await fetch(`http://127.0.0.1:${port}/v1/device-pods`); assert.equal(response.status, 401); const payload = await response.json(); assert.equal(payload.error.code, "auth_required"); } finally { await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve()))); } }); async function postJson(port, path, body, cookie = null) { const response = await fetch(`http://127.0.0.1:${port}${path}`, { method: "POST", headers: { "content-type": "application/json", ...(cookie ? { cookie } : {}) }, body: JSON.stringify(body) }); return { status: response.status, cookie: response.headers.get("set-cookie"), body: await response.json() }; } async function getJson(port, path, cookie = null) { const response = await fetch(`http://127.0.0.1:${port}${path}`, { headers: cookie ? { cookie } : {} }); return { status: response.status, body: await response.json() }; }