169 lines
5.8 KiB
TypeScript
169 lines
5.8 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import { PermissionQuery, buildQuery } from "./queries";
|
|
import { RBAC } from "./rbac";
|
|
|
|
describe("evaluating a query", () => {
|
|
const testCases: {
|
|
name: string;
|
|
query: PermissionQuery;
|
|
permissions: string[];
|
|
valid: boolean;
|
|
}[] = [
|
|
{
|
|
name: "Simple role check (Pass)",
|
|
query: buildQuery(() => "admin"),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Simple role check (Fail)",
|
|
query: buildQuery(() => "developer"),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "'and' of two permissions (Pass)",
|
|
query: buildQuery(({ and }) => and("admin", "user")),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "'and' of two permissions (Fail)",
|
|
query: buildQuery(({ and }) => and("admin", "developer")),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "'or' of two permissions (Pass)",
|
|
query: buildQuery(({ or }) => or("admin", "developer")),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "or' of two permissions (Fail)",
|
|
query: buildQuery(({ or }) => or("developer", "guest")),
|
|
permissions: ["admin", "user", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "and' and 'or' combination (Pass)",
|
|
query: buildQuery(({ and, or }) => and("admin", or("user", "guest"))),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "'and' and 'or' combination (Fail)",
|
|
query: buildQuery(({ and, or }) => and("admin", or("developer", "editor"))),
|
|
permissions: ["user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'and'(Pass)",
|
|
query: buildQuery(({ and }) => and("admin", and("user", and("guest", "moderator")))),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'and' (Fail)",
|
|
query: buildQuery(({ and }) => and("admin", and("developer", "guest"))),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'or'(Pass)",
|
|
query: buildQuery(({ or }) => or("admin", or("user", or("guest", "moderator")))),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'or' (Fail)",
|
|
query: buildQuery(({ or }) => or("developer", or("editor", "viewer"))),
|
|
permissions: ["admin", "user", "guest", "moderator"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Complex combination of 'and' and 'or'(Pass)",
|
|
query: buildQuery(({ and, or }) => or(and("admin", "user"), and("guest", "moderator"))),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Complex combination of 'and' and 'or' (Fail)",
|
|
query: buildQuery(({ and, or }) => or(and("admin", "developer"), and("editor", "viewer"))),
|
|
permissions: ["admin", "user", "guest", "moderator", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Multiple levels of nesting(Pass)",
|
|
query: buildQuery(({ and, or }) =>
|
|
or(and("admin", or("user", and("guest", "moderator"))), "editor"),
|
|
),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Multiple levels of nesting (Fail)",
|
|
query: buildQuery(({ and, or }) =>
|
|
or(and("admin", or("developer", and("guest", "moderator"))), "viewer"),
|
|
),
|
|
permissions: ["user", "guest", "moderator", "editor"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Complex combination of 'and' and 'or' at different levels (Pass)",
|
|
query: buildQuery(({ and, or }) =>
|
|
or(and("admin", or("user", and("guest", "moderator"))), and("editor", "viewer")),
|
|
),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Complex combination of 'and' and 'or' at different levels (Fail)",
|
|
query: buildQuery(({ and, or }) =>
|
|
or(and("admin", or("developer", and("guest", "moderator"))), and("editor", "developer")),
|
|
),
|
|
permissions: ["user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'and' and 'or'(Pass)",
|
|
query: buildQuery(({ and, or }) =>
|
|
and("admin", or("user", and("guest", or("moderator", "editor")))),
|
|
),
|
|
permissions: ["admin", "user", "guest", "moderator", "editor", "viewer"],
|
|
valid: true,
|
|
},
|
|
{
|
|
name: "Deep nesting of 'and' and 'or' (Fail)",
|
|
query: buildQuery(({ and, or }) =>
|
|
and("admin", or("developer", and("guest", or("moderator", "editor")))),
|
|
),
|
|
permissions: ["user", "guest", "moderator", "editor", "viewer"],
|
|
valid: false,
|
|
},
|
|
];
|
|
|
|
for (const tc of testCases) {
|
|
test(tc.name, () => {
|
|
const res = new RBAC().evaluatePermissions(tc.query, tc.permissions);
|
|
expect(res.err).toBeUndefined();
|
|
expect(res.val!.valid).toBe(tc.valid);
|
|
});
|
|
}
|
|
});
|
|
|
|
describe("bad queries", () => {
|
|
test("catch empty {}", () => {
|
|
const res = new RBAC().validateQuery({
|
|
or: [
|
|
"*",
|
|
"api.*.read_key",
|
|
// @ts-expect-error
|
|
{},
|
|
],
|
|
});
|
|
expect(res.err).toBeDefined();
|
|
expect(res.err!.message).toMatchInlineSnapshot(`"invalid_union: : Invalid input"`);
|
|
});
|
|
});
|