admin / Synapse-Sonar
publicAttack Surface Simulation
Synapse-Sonar / synapse-sonar / lib / rbac.ts
1325 B · main
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 | import { Role } from "@prisma/client"; /** * Coarse-grained permission catalog for the MVP. A permission is granted to a * role if it appears in that role's set. TENANT_ADMIN is a superset. */ export type Permission = | "asset:read" | "asset:write" | "graph:simulate" // run blast-radius | "integration:read" | "integration:write" | "user:read" | "user:manage" // invite / change role / disable | "rule:write"; const MATRIX: Record<Role, Permission[]> = { READ_ONLY_VIEWER: ["asset:read", "integration:read", "user:read"], SECURITY_ANALYST: [ "asset:read", "asset:write", "graph:simulate", "integration:read", "user:read", "rule:write", ], TENANT_ADMIN: [ "asset:read", "asset:write", "graph:simulate", "integration:read", "integration:write", "user:read", "user:manage", "rule:write", ], }; export function can(role: Role, permission: Permission): boolean { return MATRIX[role]?.includes(permission) ?? false; } /** Throws a 403-shaped error when the role lacks the permission. */ export function assertCan(role: Role, permission: Permission): void { if (!can(role, permission)) { const err = new Error(`Forbidden: role ${role} lacks ${permission}`); (err as Error & { status?: number }).status = 403; throw err; } } |