mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 16:53:17 +00:00
- Add IAM v2 auth with role_id, is_owner, status checks, and API key without tenant_admin bypass - Enforce CRUD permissions and project/warehouse scope across API routes - Rewrite usuarios.vue with ribbon, tree, user/role management, and permission matrix - Add dynamic menu, route guards, usePermissions/useScope composables - Apply role templates on create; filter project docs by category; hide cost tab without permission - Add iam_test unit tests; update bootstrap and SaaS tenant admin to use role_id Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
72 lines
2.7 KiB
TypeScript
72 lines
2.7 KiB
TypeScript
import { assert, assertEquals } from "jsr:@std/assert@1";
|
|
import {
|
|
ALL_PERMISSION_CODES,
|
|
LEGACY_TO_V2,
|
|
PROJECT_DOC_CATEGORIES,
|
|
projectDocPerm,
|
|
RESERVED_ROLE_CODES,
|
|
ROLE_TEMPLATES,
|
|
} from "./iam_catalog.ts";
|
|
import { filterSensitivePermissions } from "./permissions.ts";
|
|
import { assertProjectAccess, isOwnerAccountRow } from "./user_scope.ts";
|
|
|
|
Deno.test("IAM catálogo: permisos CRUD únicos", () => {
|
|
const codes = new Set(ALL_PERMISSION_CODES);
|
|
assertEquals(codes.size, ALL_PERMISSION_CODES.length);
|
|
assert(codes.has("workers.view"));
|
|
assert(codes.has("project_docs.tecnico.view"));
|
|
assert(codes.has("users.view"));
|
|
});
|
|
|
|
Deno.test("IAM: códigos de rol reservados", () => {
|
|
assert(RESERVED_ROLE_CODES.has("tenant_admin"));
|
|
assert(RESERVED_ROLE_CODES.has("user"));
|
|
assert(!RESERVED_ROLE_CODES.has("supervisor_obra"));
|
|
});
|
|
|
|
Deno.test("IAM: plantilla supervisor sin gastos ni IAM", () => {
|
|
const sup = ROLE_TEMPLATES.supervisor_obra.permissions;
|
|
assert(sup.includes("projects.view"));
|
|
assert(sup.includes("project_docs.tecnico.view"));
|
|
assert(!sup.some((p) => p.startsWith("expenses.")));
|
|
assert(!sup.some((p) => p.startsWith("users.")));
|
|
assert(!sup.some((p) => p.startsWith("settings.")));
|
|
});
|
|
|
|
Deno.test("IAM: plantilla contador con gastos y costos", () => {
|
|
const cont = ROLE_TEMPLATES.contador.permissions;
|
|
assert(cont.includes("expenses.view"));
|
|
assert(cont.includes("cost_control.view"));
|
|
assert(!cont.some((p) => p.startsWith("project_docs.")));
|
|
});
|
|
|
|
Deno.test("IAM: permisos sensibles filtrados para no propietario", () => {
|
|
const input = ["workers.view", "users.create", "settings.update", "reports.view"];
|
|
const filtered = filterSensitivePermissions(input, false);
|
|
assertEquals(filtered, ["workers.view", "reports.view"]);
|
|
assertEquals(filterSensitivePermissions(input, true), input);
|
|
});
|
|
|
|
Deno.test("IAM: alcance por obra", () => {
|
|
const scope = { allProjects: false, projectIds: [10, 20], warehouseCentral: false, warehouseProjects: true };
|
|
assert(assertProjectAccess(scope, 10));
|
|
assert(!assertProjectAccess(scope, 99));
|
|
assert(assertProjectAccess({ ...scope, allProjects: true }, 99));
|
|
});
|
|
|
|
Deno.test("IAM: cuenta propietaria", () => {
|
|
assert(isOwnerAccountRow({ is_owner: true }));
|
|
assert(isOwnerAccountRow({ role_code: "tenant_admin" }));
|
|
assert(!isOwnerAccountRow({ role_code: "supervisor" }));
|
|
});
|
|
|
|
Deno.test("IAM: categorías documento obra", () => {
|
|
for (const cat of PROJECT_DOC_CATEGORIES) {
|
|
assertEquals(projectDocPerm(cat, "view"), `project_docs.${cat}.view`);
|
|
}
|
|
});
|
|
|
|
Deno.test("IAM: mapeo legacy a v2", () => {
|
|
assert(LEGACY_TO_V2.manage_workers.includes("workers.view"));
|
|
assert(LEGACY_TO_V2.manage_expenses.includes("cost_control.view"));
|
|
});
|