---
name: step-03-perm-audit
description: Cross-reference permissions between controllers, Permissions.cs, seed data, and roles
next_step: steps/step-04-route-audit.md
---

# Step 3: Permission Audit

## YOUR TASK:
Cross-reference permissions across 4 sources to ensure complete coverage:
1. Controller `[RequirePermission]` attributes → what the API enforces
2. `Permissions.cs` static constants → what the code defines
3. `PermissionsSeedData` → what gets seeded to the database
4. `RolesSeedData` → what roles have which permissions

---

## EXECUTION SEQUENCE:

### 1. Extract Controller Permissions

For each file in {controller_files}:

Grep for `[RequirePermission(` and extract the permission string:
```csharp
[RequirePermission(Permissions.Employees.Read)]
[RequirePermission(Permissions.AbsenceManagement.Create)]
```

Build a set: `{controller_permissions}` = all unique permission references.

Also note which controller and HTTP method uses each permission (for context in findings).

### 2. Extract Permissions.cs Constants

Read {permissions_file} and extract all `public const string` values:
```csharp
public const string Read = "human-resources.employees.read";
public const string Wildcard = "human-resources.employees.*";
```

Build a set: `{defined_permissions}` = all permission path strings.
Also track the constant name → path mapping.

### 3. Extract Seed Data Permissions

For each file in {perm_seed_files}:

Grep for permission path patterns:
```csharp
Path = "human-resources.employees.read"
new PermissionSeedEntry { ... Path = "..." }
"human-resources.employees.read"  // in HasData() or SeedPermissionsAsync
```

Build a set: `{seeded_permissions}` = all permission paths in seed data.

### 4. Extract Role Mappings

For each file in {role_seed_files}:

Grep for role-permission associations. Look for patterns:
```csharp
// Role assignment patterns
new { RoleId = ..., PermissionId = ... }
SeedRolePermissionsAsync
rolePermissions.Add(...)
```

Build a map: `{role_mappings}` = { permission_path: [role_names] }

### 5. Cross-Reference Matrix

**Check A: Controllers → Permissions.cs**
For each permission in {controller_permissions}:
- Verify it resolves to a constant in {defined_permissions}
- If missing → BLOCKING (controller references undefined permission)

**Check B: Permissions.cs → Seed Data**
For each permission in {defined_permissions} (excluding wildcards):
- Verify it exists in {seeded_permissions}
- If missing → BLOCKING (permission defined but never seeded = always 403)

**Check C: Seed Data → Roles**
For each permission in {seeded_permissions}:
- Verify it has at least one role mapping in {role_mappings}
- If missing → CRITICAL (permission seeded but no role has it = always 403)

**Check D: Admin Role Wildcard**
- Verify admin role has wildcard (`*`) permissions for each module
- If missing → CRITICAL (admin cannot access module)

**Check E: Role Matrix Sanity**
- Viewer role must NOT have write permissions (create, update, delete)
- Admin must have wildcard or all individual permissions

### 6. Record Findings

| ID | Severity | Rule |
|----|----------|------|
| PERM-001 | BLOCKING | Controller uses permission not defined in Permissions.cs |
| PERM-002 | BLOCKING | Permissions.cs constant not seeded in PermissionsSeedData |
| PERM-003 | CRITICAL | Seeded permission has no role mapping (always 403 for all users) |
| PERM-004 | CRITICAL | Admin role missing wildcard for module |
| PERM-005 | WARNING | Permission path segments not in kebab-case |
| PERM-006 | WARNING | Viewer role has write permission (create/update/delete) |
| PERM-007 | WARNING | Permission defined in Permissions.cs but unused by any controller (dead code) |

---

## SUCCESS METRICS:
- All 4 sources extracted completely
- Cross-reference matrix fully evaluated
- Role matrix sanity checked
- Findings recorded with file:line evidence

## NEXT STEP:
If {scope} is `all` or `route` → proceed to `./step-04-route-audit.md`
If {scope} is `perm` → skip to `./step-05-report.md`
