import test from "node:test"; import assert from "node:assert/strict"; import os from "node:os"; import path from "node:path"; import { mkdtemp, rm } from "node:fs/promises"; import { NextRequest } from "next/server"; let runtimeRoot = ""; let data: typeof import("../src/lib/boss-data"); let authCookie = ""; let getAdminAccess: (typeof import("../src/app/api/v1/admin/access/route"))["GET"]; let postAdminAccess: (typeof import("../src/app/api/v1/admin/access/route"))["POST"]; let baseState: Awaited>; async function setup() { if (runtimeRoot) return; runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-rbac-admin-access-")); process.env.BOSS_RUNTIME_ROOT = runtimeRoot; process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json"); const [dataModule, authModule, routeModule] = await Promise.all([ import("../src/lib/boss-data.ts"), import("../src/lib/boss-auth.ts"), import("../src/app/api/v1/admin/access/route.ts"), ]); data = dataModule; authCookie = authModule.AUTH_SESSION_COOKIE; getAdminAccess = routeModule.GET; postAdminAccess = routeModule.POST; baseState = structuredClone(await data.readState()); } test.after(async () => { if (runtimeRoot) await rm(runtimeRoot, { recursive: true, force: true }); }); test.beforeEach(async () => { await setup(); const state = structuredClone(baseState); state.accountDeviceGrants = []; state.accountProjectGrants = []; state.accountSkillGrants = []; state.permissionAuditLogs = []; if (!state.devices.some((device) => device.id === "win-gpu-01")) { state.devices.push({ id: "win-gpu-01", name: "Windows GPU", avatar: "W", account: "gpu@example.com", source: "production", status: "online", projects: [], quota5h: 0, quota7d: 0, lastSeenAt: "2026-04-26T12:00:00+08:00", preferredExecutionMode: "cli", }); } state.deviceSkills = [ { skillId: "mac-studio:boss-server-debug", deviceId: "mac-studio", name: "boss-server-debug", description: "服务器调试", path: "/Users/kris/.codex/skills/boss-server-debug/SKILL.md", invocation: "$boss-server-debug", category: "Mac Studio", updatedAt: "2026-04-26T12:00:00+08:00", }, { skillId: "win-gpu-01:boss-server-debug", deviceId: "win-gpu-01", name: "boss-server-debug", description: "Windows 服务器调试", path: "C:/Users/kris/.codex/skills/boss-server-debug/SKILL.md", invocation: "$boss-server-debug", category: "Windows GPU", updatedAt: "2026-04-26T12:01:00+08:00", }, ]; await data.writeState(state); }); async function authedRequest( account: string, role: "member" | "admin" | "highest_admin", url: string, init: RequestInit = {}, ) { const session = await data.createAuthSession({ account, role, displayName: account, loginMethod: "password", }); return new NextRequest(url, { ...init, headers: { ...(init.headers ?? {}), cookie: `${authCookie}=${session.sessionToken}`, }, }); } async function adminPost(body: Record) { return postAdminAccess( await authedRequest("krisolo", "highest_admin", "http://127.0.0.1:3000/api/v1/admin/access", { method: "POST", body: JSON.stringify(body), }), ); } test("member cannot read or mutate access management", async () => { const getResponse = await getAdminAccess( await authedRequest("worker@example.com", "member", "http://127.0.0.1:3000/api/v1/admin/access"), ); assert.equal(getResponse.status, 403); const postResponse = await postAdminAccess( await authedRequest("worker@example.com", "member", "http://127.0.0.1:3000/api/v1/admin/access", { method: "POST", body: JSON.stringify({ action: "grant_device" }), }), ); assert.equal(postResponse.status, 403); }); test("highest admin can create a member and grant scoped device project and skill access", async () => { const accountResponse = await adminPost({ action: "upsert_account", account: "worker@example.com", displayName: "Worker", role: "member", password: "worker-pass", }); assert.equal(accountResponse.status, 200); const accountPayload = await accountResponse.json(); assert.equal(accountPayload.account.account, "worker@example.com"); assert.equal(accountPayload.account.passwordHash, undefined); const deviceResponse = await adminPost({ action: "grant_device", account: "worker@example.com", deviceId: "mac-studio", permissions: ["device.view"], note: "Mac 只读", }); assert.equal(deviceResponse.status, 200); const devicePayload = await deviceResponse.json(); assert.equal(devicePayload.grant.deviceId, "mac-studio"); const projectResponse = await adminPost({ action: "grant_project", account: "worker@example.com", projectId: "master-agent", permissions: ["project.view", "master_agent.ask"], }); assert.equal(projectResponse.status, 200); const skillResponse = await adminPost({ action: "grant_skill", account: "worker@example.com", skillId: "mac-studio:boss-server-debug", deviceId: "mac-studio", permissions: ["skill.view", "skill.use"], }); assert.equal(skillResponse.status, 200); const state = await data.readState(); assert.equal(state.accountDeviceGrants.length, 1); assert.equal(state.accountProjectGrants.length, 1); assert.equal(state.accountSkillGrants.length, 1); assert.equal(state.permissionAuditLogs.length, 4); const getResponse = await getAdminAccess( await authedRequest("krisolo", "highest_admin", "http://127.0.0.1:3000/api/v1/admin/access"), ); assert.equal(getResponse.status, 200); const getPayload = await getResponse.json(); assert.equal( getPayload.accounts.some((account: { passwordHash?: string }) => Boolean(account.passwordHash)), false, ); assert.equal(getPayload.grants.devices.length, 1); assert.equal(getPayload.grants.projects.length, 1); assert.equal(getPayload.grants.skills.length, 1); const bossServerDebugCatalog = getPayload.skillCatalog.find( (item: { name: string }) => item.name === "boss-server-debug", ); assert.equal(bossServerDebugCatalog.deviceCount, 2); assert.deepEqual( bossServerDebugCatalog.devices.map((device: { deviceId: string }) => device.deviceId).sort(), ["mac-studio", "win-gpu-01"], ); }); test("highest admin can revoke a grant", async () => { const grantResponse = await adminPost({ action: "grant_device", account: "worker@example.com", deviceId: "mac-studio", permissions: ["device.view"], }); const grantPayload = await grantResponse.json(); const revokeResponse = await adminPost({ action: "revoke_grant", grantId: grantPayload.grant.grantId, }); assert.equal(revokeResponse.status, 200); const state = await data.readState(); assert.equal(state.accountDeviceGrants.length, 0); assert.equal(state.permissionAuditLogs.at(0)?.action, "grant.revoked"); }); test("highest admin can apply a permission template across device project and skill scopes", async () => { await adminPost({ action: "upsert_account", account: "developer@example.com", displayName: "Developer", role: "member", password: "developer-pass", }); const getResponse = await getAdminAccess( await authedRequest("krisolo", "highest_admin", "http://127.0.0.1:3000/api/v1/admin/access"), ); assert.equal(getResponse.status, 200); const getPayload = await getResponse.json(); assert.deepEqual( getPayload.permissionTemplates.map((template: { templateId: string }) => template.templateId), ["viewer", "developer", "operator"], ); const applyResponse = await adminPost({ action: "apply_template", account: "developer@example.com", templateId: "developer", deviceIds: ["mac-studio"], projectIds: ["master-agent"], skillIds: ["mac-studio:boss-server-debug"], }); assert.equal(applyResponse.status, 200); const applyPayload = await applyResponse.json(); assert.equal(applyPayload.grants.devices.length, 1); assert.equal(applyPayload.grants.projects.length, 1); assert.equal(applyPayload.grants.skills.length, 1); const state = await data.readState(); assert.deepEqual(state.accountDeviceGrants.at(0)?.permissions, ["device.view"]); assert.deepEqual(state.accountProjectGrants.at(0)?.permissions, [ "project.view", "thread.chat", "master_agent.ask", ]); assert.deepEqual(state.accountSkillGrants.at(0)?.permissions, ["skill.view", "skill.use"]); assert.equal( state.permissionAuditLogs.some((log) => log.action === "grant.updated" && log.detail === "template:developer"), true, ); });