--- type: testing milestone: M3 date: "2026-05-11" project: Metamorph --- # Testing M3 — RBAC, groups, users, invitations ## 1. Lancement de la stack ```bash make clean # reset complet si une stack tournait déjà make up # build + start db/api/front make migrate # applique le schéma (head) ``` DoD réussie quand : - `http://localhost:8080` répond et la home indique « M3 milestone (RBAC) » - `make logs-api | grep INSTALL` montre le bandeau du token d'install (1ʳᵉ fois) - `make logs-api | grep metamorph.permissions.seeded` confirme `perms_total: 31` au boot ## 2. Tests automatisés ```bash make test-api # 39 tests pytest, dont 15 nouveaux sur RBAC make e2e # 28 tests Playwright, dont 8 M3 make e2e-report # ouvre le rapport HTML ``` Le rapport JUnit est dans `e2e/playwright-report/junit.xml`. ## 3. Procédure manuelle (smoke navigateur) ### Pré-requis 1. Stack up via `make up`. 2. `make print-install-token` → noter le token (ou `make logs-api` pour le bandeau). ### 3.1 Bootstrap admin 1. Visiter `http://localhost:8080/setup` → coller le token, créer `admin@metamorph.local` / `AdminPass1234!`. 2. Redirection auto vers `/login` après ~1.5 s. 3. Se connecter avec les mêmes identifiants. 4. La barre de nav fait apparaître les liens **Users / Groups / Invitations** (visibles uniquement quand `is_admin === true`). ### 3.2 Page Groups (`/admin/groups`) 1. Cliquer **+ New group** → modale `new group`. 2. Nom : `pentest-2026-Q2`, description libre. 3. Cocher uniquement `mission.read` et `mission.write_red_fields` dans la grille de permissions. 4. **Create group** → la carte apparaît dans la liste avec les badges `2 perms`. 5. Ouvrir le groupe `admin` (système) — le champ `Name` doit être désactivé et la mention « System groups cannot be renamed. » visible. 6. Tenter de supprimer le groupe `admin` → bouton **Delete** invisible (les groupes système sont protégés côté UI **et** serveur). ### 3.3 Page Invitations (`/admin/invitations`) 1. Cliquer **+ New invitation** → modale `new invitation`. 2. Email hint : `alice@metamorph.local`. Cocher `pentest-2026-Q2`. 3. **Generate link** → modale `invitation link` montrant l'URL one-shot ; bouton **Copy** disponible. 4. Coller l'URL dans un onglet privé → page `/register` pré-remplie avec l'email hint. Compléter le mot de passe, valider. ### 3.4 Page Users (`/admin/users`) 1. Liste les comptes existants. Chercher `alice` dans le champ **Search**. 2. Cliquer **Edit** sur Alice → modale `alice@metamorph.local`. Vérifier ses groupes (cochés : `pentest-2026-Q2`). 3. Décocher `pentest-2026-Q2`, cocher `redteam`. **Save changes**. 4. Recharger la page → Alice a maintenant le badge `redteam`. ### 3.5 Last-admin protection 1. Tenter de soft-delete l'admin courant via l'API : ```bash ACCESS=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \ -H 'Content-Type: application/json' \ -d '{"email":"admin@metamorph.local","password":"AdminPass1234!"}' | jq -r .access_token) MY_ID=$(curl -s http://localhost:8080/api/v1/auth/me -H "Authorization: Bearer $ACCESS" | jq -r .id) curl -i -X DELETE http://localhost:8080/api/v1/users/$MY_ID -H "Authorization: Bearer $ACCESS" ``` Réponse : **409** `{"error":"last_admin_protected"}`. ### 3.6 Vérification RBAC côté serveur (non-admin) 1. Se connecter en tant qu'Alice (membre uniquement de `redteam` après l'étape 3.4) : ```bash ACCESS=$(curl -s -X POST http://localhost:8080/api/v1/auth/login \ -H 'Content-Type: application/json' \ -d '{"email":"alice@metamorph.local","password":""}' | jq -r .access_token) ``` 2. `/users` → **403** : `redteam` n'a pas `user.read`. 3. `POST /groups` → **403** : `redteam` n'a pas `group.create`. 4. Naviguer dans le browser sur `/admin/users` → redirige vers `/` (RequireAdmin client-side). ### 3.7 Catalogue permissions ```bash curl -s http://localhost:8080/api/v1/permissions -H "Authorization: Bearer $ACCESS_ADMIN" | jq '.items | length' ``` Doit retourner `31` (cf. `app/services/permissions_seed.py:PERMISSION_CATALOGUE`). ## 4. Points de contrôle critiques - [x] Les 3 groupes système (`admin`, `redteam`, `blueteam`) existent avec `is_system=true` et leurs perms bind par défaut. - [x] Le seed est idempotent : booter, `make migrate`, rebooter → toujours `perms_total: 31`, `perms_created: 0`. - [x] Un non-admin reçoit 403 sur tout endpoint protégé par `@require_perm` qu'il ne couvre pas. - [x] L'admin bypass est effectif (`is_admin` → toujours OK même sans perm explicite). - [x] Les noms et perms des groupes système ne sont pas modifiables côté UI (champs disabled, bouton Delete masqué). - [x] Le dernier admin ne peut pas être désactivé / supprimé / retiré du groupe `admin`. - [x] `/admin/users`, `/admin/groups`, `/admin/invitations` masqués pour les non-admin (nav + RequireAdmin). - [x] `/diag/reset` réinitialise aussi les compteurs rate-limit (utile entre tests Playwright).