Explorar o código

Docs: mark R01-N12 fixed, refresh SPEC §9 / §13

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa hai 2 días
pai
achega
868fe6c2a6
Modificáronse 2 ficheiros con 47 adicións e 2 borrados
  1. 28 0
      SPEC.md
  2. 19 2
      doc/REVIEW_01.md

+ 28 - 0
SPEC.md

@@ -1322,6 +1322,32 @@ is gone — see `src/Auth/BootstrapAdmin.php`.
       tests (existing `tests/Cascade` + `tests/Controllers` already
       exercise these paths). Tenth fix from `doc/REVIEW_01.md`.
 
+- [x] **R01-N12 — Validate `/audit` date filters server-side**
+      (`1b28469`). The audit viewer concatenated `T00:00:00Z` /
+      `T23:59:59Z` onto the raw `from_date` / `to_date` query inputs
+      and bound the result against the ISO-8601 `occurred_at` column.
+      Garbage in (e.g. `2024/01/01` instead of `2024-01-01`) silently
+      produced empty result sets — a UX bug that hides events from a
+      casual auditor. `AuditController::index` now routes both inputs
+      through a pure static `validateDateFilters($from, $to)` that
+      strict-parses `Y-m-d` (`DateTimeImmutable::createFromFormat` +
+      round-trip equality, same pattern as `SprintController::
+      isIsoDate`) and returns the validated value (empty when parse
+      fails so the filter is dropped instead of poisoning the query)
+      plus an `errors` map keyed by field name. The view echoes the
+      user's raw input back into the date inputs so they can fix the
+      typo, tints the offending input amber, and renders an inline
+      "Use the format YYYY-MM-DD" notice + a banner. No session-flash
+      plumbing — the form is GET-driven and the response IS the form,
+      so errors travel with the rendered page. New
+      `tests/Controllers/AuditControllerTest.php` (16 cases) pins the
+      matrix: empty / valid / one-side-bad / both-bad, lenient
+      rollovers caught by the round-trip check (`2025-02-29`,
+      `2026-13-01`, `2026-02-30`, `2026-1-1`), whitespace rejected,
+      leap-year preserved verbatim, injection-shaped string rejected.
+      Tests: 227 / 590 (was 211 / 562). Eleventh fix from
+      `doc/REVIEW_01.md`.
+
 - [x] **New sprint form: drop weeks input + task list row hover**
       (`3728106`). The `/sprints/new` form no longer collects an
       `n_weeks` value — the week count is derived from `start_date` /
@@ -1438,6 +1464,8 @@ before acting — nothing here is load-bearing once it grows stale.
 ## 13. Git history (as of this writing)
 
 ```
+1b28469 Fix R01-N12: validate audit date filters server-side
+d6b163d Docs: mark R01-N10 fixed, refresh SPEC §9 / §13
 c1dbfc1 Fix R01-N10: bind sprint_id with placeholder in MAX(sort_order) lookups
 a8ed6af Docs: mark R01-N08 fixed, refresh SPEC §9 / §11 / §13
 bc745cd Fix R01-N08: idle session timeout + CSRF rotation on login

+ 19 - 2
doc/REVIEW_01.md

@@ -393,7 +393,24 @@ note. Do not delete entries — they're history.
 
 ### R01-N12 — Audit log `from_date`/`to_date` filters not validated
 - **Severity**: MEDIUM (UX bug, mild forensic impact).
-- **Status**: open.
+- **Status**: fixed-in-`1b28469` — `AuditController::index` now routes
+  both raw inputs through a pure static `validateDateFilters($from, $to)`
+  that strict-parses `Y-m-d` (`createFromFormat` + round-trip equality,
+  same pattern as `SprintController::isIsoDate`) and splits the output
+  into `from` / `to` (empty string when the input fails to parse so the
+  filter is dropped instead of poisoning the query) and an `errors` map
+  keyed by field name. The repo is fed the validated copy; the view
+  echoes the user's raw input back into the date fields so they can fix
+  the typo, tints the offending input amber, and shows an inline
+  "Use the format YYYY-MM-DD" notice plus a banner. No session-flash
+  plumbing — the form is GET-driven and the response is the form, so
+  errors travel with the rendered page. New
+  `tests/Controllers/AuditControllerTest.php` (16 cases) pins the
+  matrix: empty / valid / one-side-bad / both-bad, lenient rollovers
+  caught by the round-trip check (`2025-02-29`, `2026-13-01`,
+  `2026-02-30`, `2026-1-1`), whitespace rejected, leap-year preserved
+  verbatim, an injection-shaped string rejected. Suite: 227 / 590 (was
+  211 / 562).
 - **Where**:
   - `src/Repositories/AuditRepository.php` lines 149-156.
   - `src/Controllers/AuditController.php` lines 39-49.
@@ -788,7 +805,7 @@ A reasonable cadence (do not treat as binding):
 9. ~~**R01-N08** (idle session timeout + CSRF rotation)~~ — fixed in
    `bc745cd`.
 10. ~~**R01-N10** (bind-not-concat sweep)~~ — fixed in `c1dbfc1`.
-11. **R01-N12** (date filter validation) — UX bug.
+11. ~~**R01-N12** (date filter validation)~~ — fixed in `1b28469`.
 12. The rest as time permits.
 
 Each fix should ship as its own commit per SPEC.md §14, with a follow-up