Skip to content

Test coverage: from module directories to one RBAC route matrix

“49 module test directories” only speaks to breadth; quality depends on how cases pin boundaries. Below, one real RBAC route matrix shows what behavior is under test.

Directory names under test/ map to modules (for example rbac/, audit/, trigger/, team/). Change a module, run that directory first — the regression net stays clear. Each governance capability has its own directory, which reduces blind spots where a feature has no tests. Cross-cutting unit/ / integration/ trees often force searching across folders after a module change and make missed regressions more likely.

Those directories cover kernel behavior (sessions, tools, providers) and governance behavior (RBAC, identity, org, team, triggers, retention, observability).

Route-permission cases enumerate role × method × path in a table:

const cases: Case[] = [
["operator", "GET", "/global/config", true],
["operator", "PATCH", "/global/config", false],
["approver", "PATCH", "/global/config", false],
["operator", "POST", "/global/dispose", false],
["operator", "GET", "/global/dispose", true],
["admin", "POST", "/global/dispose", true],
["operator", "POST", "/global/retention/run", false],
["admin", "POST", "/global/retention/run", true],
["readonly", "GET", "/global/health", true],
["operator", "POST", "/session/abc/init", true],
["operator", "PATCH", "/prefs", true],
]
for (const [role, method, path, want] of cases) {
test(`${role} ${method} ${path} → ${want}`, () => {
expect(allowed(role as never, method, path)).toBe(want)
})
}

Three boundaries (where over-privilege bugs often hide):

Same path, different read vs write. GET /global/dispose is open to operator; POST is admin-only. Auth is path × method, not path alone.

Exceptions are in the cases. GET /global/health is true for readonly as well. Health probes must not be broken by a tight permission default; the exception is pinned by tests, not by convention.

Regression guards. Operator can still init a session and change prefs — tightening global write must not lock normal execution paths.

Permission defects look like “this role is allowed or blocked wrongly for this method+path.” The matrix pins combinations; adding a route means adding a row.

Temp-directory fixtures give each case its own directory, optionally init git / write config, clean up at the end, and scrub null bytes from paths (CI defense). Multi-tenant and multi-instance isolation only stays stable when cases do not contaminate each other.


Related: