Roles and permissions Required
Test every role against every action
Keep a table of every role and every action with the expected answer, and run it as a test against the server on every change.
How to do it
Build the list of actions from the route table or the permission list, so a new route without an entry fails the test. For each role, sign in as a test user with that role and call each action. Expect 2xx where allowed and 403 or 404 where refused. Add a signed-out visitor and a user from another organisation, as check ownership on every record says.
Example
import itertools
import pytest
ROLES = ["owner", "admin", "member", "viewer", "signed_out", "other_org"]
EXPECTED = load_table("access-matrix.csv") # (role, "POST /invoices/{id}/refund") -> 200 or 403
@pytest.mark.parametrize("role,action", itertools.product(ROLES, all_routes()))
def test_access(client_for, role, action):
method, path = action.split(" ", 1)
assert client_for(role).open(path, method=method).status_code == EXPECTED[(role, action)]
import { test } from 'node:test';
import assert from 'node:assert/strict';
for (const role of ROLES) {
for (const action of allRoutes()) {
test(`${role} ${action}`, async () => {
const [method, path] = action.split(' ');
const response = await clientFor(role).fetch(path, { method });
assert.equal(response.status, EXPECTED.get(`${role} ${action}`));
});
}
}
How to check
Add a route without adding it to the table, and the test fails. Change a role's permissions without changing the table, and the test fails too.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers accounts playbook: https://agentwranglers.se/playbook/accounts/roles-and-permissions/permission-matrix-test.