import { assert, assertEquals } from "jsr:@std/assert"; import { stub } from "jsr:@std/testing/mock"; import { app } from "../main.ts"; import { sqlWrapper } from "../db.ts"; import { valkey } from "../valkey.ts"; import { rateLimitWrapper } from "../ratelimit.ts"; import { auditWrapper } from "../audit.ts"; const originalSql = sqlWrapper.sql; const originalAudit = auditWrapper.auditLog; const auditEvents: Array< { action: string; resource?: string | null; details?: any } > = []; function setMockSql(mockImpl: () => Promise) { sqlWrapper.sql = mockImpl as any; } function restoreMockSql() { sqlWrapper.sql = originalSql; } rateLimitWrapper.checkRateLimit = () => Promise.resolve(true); auditWrapper.auditLog = ( _userId: string | null, action: string, resource: string | null, details: Record | null, ) => { auditEvents.push({ action, resource, details }); }; Deno.test("Zero-Trust Scope Guards", async (t) => { const mockUserId = "user-id-guards"; await t.step( "Delegated session is blocked from mutating sessions without scope", async () => { const mockSessionId = "ay_sess_delegated_123"; setMockSql( (async (strings: any, ..._values: any[]) => { const q = Array.isArray(strings) ? strings.join("?") : String(strings); if (q.includes("SELECT id, is_agent FROM sessions")) { return [{ id: "other_session", is_agent: false }]; } return []; }) as any, ); if ((valkey as any).get.restore) { (valkey as any).get.restore(); } const valkeyStub = stub( valkey, "get", () => Promise.resolve( JSON.stringify({ uuid: mockUserId, username: "agent-user", isAgent: true, customScopes: ["read:data"], }), ), ); try { const req = new Request( "http://localhost/api/sessions/other_session/extend", { method: "POST", headers: { "Authorization": `Bearer ${mockSessionId}`, "Content-Type": "application/json", }, body: JSON.stringify({ extendHours: 2 }), }, ); const res = await app.fetch(req); assertEquals(res.status, 403); const body = await res.json(); assertEquals(body.error, "Forbidden: Insufficient scopes"); } finally { valkeyStub.restore(); } }, ); await t.step("Delegated session can self-revoke", async () => { const mockSessionId = "ay_sess_delegated_123"; setMockSql( (async (strings: any, ..._values: any[]) => { const q = Array.isArray(strings) ? strings.join("?") : String(strings); if (q.includes("SELECT id FROM sessions WHERE id =")) { return [{ id: mockSessionId }]; } if (q.includes("DELETE FROM sessions")) { return [{ id: mockSessionId }]; } return []; }) as any, ); if ((valkey as any).get.restore) { (valkey as any).get.restore(); } const valkeyStub = stub( valkey, "get", () => Promise.resolve( JSON.stringify({ uuid: mockUserId, username: "agent-user", isAgent: true, customScopes: ["read:data"], }), ), ); const delStub = stub(valkey, "del", () => Promise.resolve(1 as any)); try { const req = new Request( `http://localhost/api/sessions/${mockSessionId}`, { method: "DELETE", headers: { "Authorization": `Bearer ${mockSessionId}` }, }, ); const res = await app.fetch(req); assertEquals(res.status, 200); const body = await res.json(); assertEquals(body.success, true); } finally { valkeyStub.restore(); delStub.restore(); } }); await t.step( "Delegated session blocked from UI /admin redirect", async () => { const mockSessionId = "ay_sess_delegated_123"; setMockSql( (async (strings: any, ..._values: any[]) => { const q = Array.isArray(strings) ? strings.join("?") : String(strings); if (q.includes("SELECT g.id")) { return [{ id: "admin-grant-id" }]; } return []; }) as any, ); if ((valkey as any).get.restore) { (valkey as any).get.restore(); } const valkeyStub = stub( valkey, "get", () => Promise.resolve( JSON.stringify({ uuid: mockUserId, username: "agent-user", isAgent: true, customScopes: ["read:data"], }), ), ); try { const req = new Request("http://localhost/admin/users", { headers: { "Cookie": `session_id=${mockSessionId}` }, }); const res = await app.fetch(req); assertEquals(res.status, 302); assertEquals(res.headers.get("location"), "/dashboard"); } finally { valkeyStub.restore(); } }, ); await t.step( "Delegated session without admin scope blocked from POST /api/sessions/delegate", async () => { const mockSessionId = "ay_sess_delegated_123"; if ((valkey as any).get.restore) { (valkey as any).get.restore(); } const valkeyStub = stub( valkey, "get", () => Promise.resolve( JSON.stringify({ uuid: mockUserId, username: "agent-user", isAgent: true, customScopes: ["write:sessions"], }), ), ); try { const req = new Request("http://localhost/api/sessions/delegate", { method: "POST", headers: { "Authorization": `Bearer ${mockSessionId}`, "Content-Type": "application/json", }, body: JSON.stringify({ label: "Sub Agent" }), }); const res = await app.fetch(req); assertEquals(res.status, 403); const body = await res.json(); assertEquals(body.error, "Forbidden: Insufficient scopes"); } finally { valkeyStub.restore(); } }, ); await t.step( "Delegated session without write:events blocked from POST /api/events", async () => { const mockSessionId = "ay_sess_delegated_123"; if ((valkey as any).get.restore) { (valkey as any).get.restore(); } const valkeyStub = stub( valkey, "get", () => Promise.resolve( JSON.stringify({ uuid: mockUserId, username: "agent-user", isAgent: true, customScopes: ["read:data"], }), ), ); try { const req = new Request("http://localhost/api/events", { method: "POST", headers: { "Authorization": `Bearer ${mockSessionId}`, "Content-Type": "application/json", }, body: JSON.stringify({ name: "Hacking Workshop" }), }); const res = await app.fetch(req); assertEquals(res.status, 403); const body = await res.json(); assertEquals(body.error, "Forbidden: Insufficient scopes"); } finally { valkeyStub.restore(); } }, ); restoreMockSql(); }); Deno.test("Agent Session Delegation & Scoped Permissions", async (t) => { await t.step( "POST /api/sessions/delegate - Mints child session with scopes", async () => { const valkeyStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const valkeySetStub = stub(valkey, "set", () => Promise.resolve("OK")); const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((_query: any, ..._args: any[]) => { return Promise.resolve([{ id: "mock-id" }]); }) as any; try { const res = await app.request("/api/sessions/delegate", { method: "POST", headers: { Authorization: "Bearer admin-session", "Content-Type": "application/json", }, body: JSON.stringify({ label: "Antigravity Assistant", lifespanHours: 12, mode: "read_only", }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assert(json.sessionId.startsWith("ay_sess_")); assertEquals(json.label, "Antigravity Assistant"); assert(json.scopes.includes("read:audit")); } finally { sqlWrapper.sql = originalSql; valkeyStub.restore(); valkeySetStub.restore(); } }, ); await t.step( "PUT /api/sessions/:id/scopes - Updates custom scopes", async () => { const valkeyStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((_query: any, ..._args: any[]) => { return Promise.resolve([{ id: "ay_sess_123", is_agent: true }]); }) as any; try { const res = await app.request("/api/sessions/ay_sess_123/scopes", { method: "PUT", headers: { Authorization: "Bearer admin-session", "Content-Type": "application/json", }, body: JSON.stringify({ customScopes: ["read:audit", "app:ed-droid"], }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assertEquals(json.scopes, ["read:audit", "app:ed-droid"]); } finally { sqlWrapper.sql = originalSql; valkeyStub.restore(); } }, ); await t.step( "POST /api/sessions/:id/extend - Extends session TTL", async () => { const valkeyStub = stub(valkey, "get", (key: any) => { if (String(key) === "admin-session") { return Promise.resolve( JSON.stringify({ uuid: "admin-uuid", username: "tylerg" }), ); } return Promise.resolve(null); }); const valkeyExpireStub = stub(valkey, "expire", () => Promise.resolve(1)); const originalSql = sqlWrapper.sql; sqlWrapper.sql = ((_query: any, ..._args: any[]) => { return Promise.resolve([{ id: "ay_sess_123", expires_at: new Date().toISOString(), }]); }) as any; try { const res = await app.request("/api/sessions/ay_sess_123/extend", { method: "POST", headers: { Authorization: "Bearer admin-session", "Content-Type": "application/json", }, body: JSON.stringify({ extendHours: 2, }), }); assertEquals(res.status, 200); const json = await res.json(); assert(json.success === true); assert(json.newExpiresAt); assert(auditEvents.some((e) => e.action === "session_extended")); } finally { sqlWrapper.sql = originalSql; valkeyStub.restore(); valkeyExpireStub.restore(); } }, ); // Verify full audit coverage across delegation endpoints assert(auditEvents.some((e) => e.action === "session_delegated")); assert(auditEvents.some((e) => e.action === "session_scopes_updated")); auditWrapper.auditLog = originalAudit; });