Swadhin Biswas Feature/ai code reviewer (#79) · 8/16/2026
cfd400d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { describe, expect, it } from "vitest";
import {
hasPatScope,
hasRepoWriteScope,
PAT_SCOPES,
} from "@/lib/permissions";
describe("fine-grained PAT scope enforcement", () => {
it("legacy tokens (no scopes) keep full access", () => {
expect(hasPatScope(undefined, "repo:write")).toBe(true);
expect(hasPatScope([], "admin")).toBe(true);
});
it("allows when the required scope is present", () => {
expect(hasPatScope(["repo:write"], "repo:write")).toBe(true);
expect(hasPatScope(["repo:read", "notifications"], "notifications")).toBe(
true,
);
});
it("blocks when the required scope is absent", () => {
expect(hasPatScope(["repo:read"], "repo:write")).toBe(false);
expect(hasPatScope(["repo:read"], "admin")).toBe(false);
expect(hasPatScope(["notifications"], "repo:read")).toBe(false);
});
it("admin scope implies all other scopes", () => {
expect(hasPatScope(["admin"], "repo:write")).toBe(true);
expect(hasPatScope(["admin"], "notifications")).toBe(true);
expect(hasPatScope(["admin"], ["repo:read", "repo:write"])).toBe(true);
});
it("requires ALL scopes when an array is given", () => {
expect(
hasPatScope(["repo:read", "repo:write"], ["repo:read", "repo:write"]),
).toBe(true);
expect(hasPatScope(["repo:read"], ["repo:read", "repo:write"])).toBe(false);
});
it("hasRepoWriteScope blocks read-only tokens from writes", () => {
expect(hasRepoWriteScope(undefined)).toBe(true);
expect(hasRepoWriteScope(["repo:write"])).toBe(true);
expect(hasRepoWriteScope(["repo:read"])).toBe(false);
expect(hasRepoWriteScope(["notifications"])).toBe(false);
});
it("exposes a stable scope vocabulary", () => {
expect(PAT_SCOPES).toContain("repo:read");
expect(PAT_SCOPES).toContain("repo:write");
expect(PAT_SCOPES).toContain("admin");
expect(PAT_SCOPES).toContain("notifications");
});
});