---
title: "Test every role against every action · Agent Wranglers"
url: https://agentwranglers.se/playbook/accounts/roles-and-permissions/permission-matrix-test
updated: 2026-10-20
licence: "All rights reserved"
---

# Test every role against every action

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

- Level: Required
- Chapter: [Roles and permissions](https://agentwranglers.se/playbook/accounts/roles-and-permissions)
- Rule: 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: 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](https://agentwranglers.se/playbook/adversarial-testing/access-and-accounts/object-access) says.
- 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.

Example:

```python
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)]
```

```js
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}`));
    });
  }
}
```

**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`.

- Previous: [Start with roles and add record rules only when needed](https://agentwranglers.se/playbook/accounts/roles-and-permissions/rbac-then-abac)
- Next: [Give roles inside an organisation](https://agentwranglers.se/playbook/accounts/roles-and-permissions/org-scoped-roles)
- [Roles and permissions](https://agentwranglers.se/playbook/accounts/roles-and-permissions)
