feat(m7): blue review fields + spec amendment + reviewer follow-ups

User feedback after the M7 ship: blue team's Excel workflow had 5 extra
fields we didn't capture. Per-test page also doesn't match their
workflow — they need a tabular view, one table per scenario.

Spec
- tasks/spec.md amended (`revised: 2026-05-15`): §4 in-scope, §F6, §8
  model bullet. §F6 now pins the column matrix, single-row-edit
  semantics, Esc-cancel, blur-confirm, and reconciles detection_level
  as a pill inside the Commentaires cell (no 8th column).
- tasks/todo.md M7 section grew an "Amendement 2026-05-15" sub-block
  tracking backend ☑ and frontend ☐.

Backend
- Migration c2a8f4b1d6e9: 5 nullable columns on mission_tests
  (blue_log_source, blue_siem_logs, blue_incident_at,
  blue_incident_number, blue_incident_recipient_email).
- _BLUE_FIELDS extended; update_mission_test_fields propagates each
  field; MissionTestDetailView + MissionTestView (the nested view in
  GET /missions/{id}) surface every annotation field, plus
  last_actor_*, updated_at, detection_level_key — O(1) batch lookup
  for detection-level keys and last-actor users keeps it scalable.
- UpdateMissionTestPayload accepts each field with length caps
  (120/200_000/120/255).

Reviewer follow-ups applied
- blue_incident_at + executed_at now reject naïve datetimes
  (_ensure_aware_datetime) — Postgres would otherwise interpret
  them in the session TZ, defeating the M7 verbatim-time contract.
- blue_incident_recipient_email goes through a permissive RFC-shape
  regex (_validate_email_shape) so internal/lab TLDs like .local
  / .corp / .test pass — Pydantic EmailStr is too strict (lessons.md
  M2 trap).
- Project-wide: switched `e.errors()` to
  `e.errors(include_context=False, include_url=False)` because the
  AfterValidator-raised ValueError lands in ctx and Flask can't
  serialize it.

Tests
- 5 new pytest cases: blue user writes the 5 new fields, red user is
  individually 403'd on each, round-trip via GET, naïve datetime
  rejected, email shape validated (.local accepted, bad shape 400).
- 138 pytest green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Knacky
2026-05-15 14:45:18 +02:00
parent d679ff34d8
commit 447f15213a
16 changed files with 517 additions and 34 deletions

View File

@@ -149,7 +149,7 @@ spec: tasks/spec.md
---
## M7 — Saisie red & blue sur un test ☑
## M7 — Saisie red & blue sur un test ☑ (+ amendement 2026-05-15 ↻)
**But** : exécution de la mission, le cœur du produit.
@@ -164,6 +164,18 @@ spec: tasks/spec.md
**DoD** : red et blue saisissent en parallèle sans conflit ; un user sans `write_blue_fields` reçoit 403 sur les champs blue ; un fichier .evtx de 24 Mo est uploadé, un de 26 Mo est rejeté ; le hash SHA256 est correct.
### Amendement 2026-05-15 — fiche de review blue étendue + vue tabulaire
- ☑ Migration `c2a8f4b1d6e9` : 5 nouvelles colonnes sur `mission_tests``blue_log_source` (varchar 120), `blue_siem_logs` (text), `blue_incident_at` (timestamptz), `blue_incident_number` (varchar 120), `blue_incident_recipient_email` (varchar 255).
- ☑ Service `mission_tests` : `_BLUE_FIELDS` étendu aux 5 nouveaux champs, `update_mission_test_fields` accepte chaque kwarg, perm gating identique (red user → 403 sur chaque champ).
- ☑ Service `missions` : `MissionTestView` (vue nested dans `GET /missions/{id}`) inclut désormais toutes les annotations red/blue + `last_actor_*` + `updated_at` + `detection_level_key`, avec batch-lookup détection-level/users pour rester O(1) en nombre de tests.
- ☑ API : `UpdateMissionTestPayload` + serializer `_serialize_test` / `_serialize_test_detail` mis à jour, validation length-cap par champ.
- ☑ Tests pytest : 3 nouveaux (`test_blue_user_writes_new_blue_review_fields`, `test_red_user_cannot_write_new_blue_review_fields`, `test_blue_review_fields_survive_round_trip_via_get`) — 136 verts.
- ☐ Frontend : vue tabulaire pleine largeur dans l'onglet **tests** du detail page, un tableau par scénario, colonnes `Test | Procédure | Exécution | Source de log | Commentaires | Logs SIEM | Cyber Incident`, double-clic = mode édition inline gated par perms. La page `/missions/<id>/tests/<test_id>` reste pour l'upload de preuves.
- ☐ Docs : CHANGELOG section dédiée, testing-m7.md mise à jour pour la matrice de colonnes + le workflow d'édition inline.
**DoD amendement** : blue user double-clique sur une ligne, saisit `log_source` + `siem_logs` + le sous-record incident, sauve ; rafraîchir la mission → tout est persisté ; red user double-clique sur la même ligne → ne peut éditer que `Exécution` (`executed_at`, `red_command`).
---
## M8 — Niveaux de détection custom ☐