auth-yes/server/tests/scopes.test.ts
google-labs-jules[bot] 0d59c2ac75 refactor(test): decompose main.test.ts into domain specific test files
Extracted the 1,577-line monolithic `server/main.test.ts` into five isolated, domain-specific files under `server/tests/`:
- `forward_auth.test.ts`: ForwardAuth bypass, cookie scoping, and sandbox.
- `rpc.test.ts`: ConnectRPC SPIFFE and RBAC tests.
- `auth.test.ts`: Audit ledger, WebAuthn PRF, passkey magic links.
- `events.test.ts`: Multi-claim join endpoints and killswitch.
- `scopes.test.ts`: Zero-trust guards and self-revocations.

Successfully maintained all tests cleanly isolated via standard mocking and deleted `main.test.ts` after migrating and executing `deno test --allow-all` with zero failures.

Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
2026-08-26 05:12:08 +00:00

396 lines
11 KiB
TypeScript

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";
const originalSql = sqlWrapper.sql;
function setMockSql(mockImpl: () => Promise<any>) {
sqlWrapper.sql = mockImpl as any;
}
function restoreMockSql() {
sqlWrapper.sql = originalSql;
}
rateLimitWrapper.checkRateLimit = () => Promise.resolve(true);
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);
} finally {
sqlWrapper.sql = originalSql;
valkeyStub.restore();
valkeyExpireStub.restore();
}
},
);
});