diff --git a/ROADMAP.md b/ROADMAP.md index a60d57a..1902794 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -7,9 +7,9 @@ > Update the **Current step** line and the item status every time something moves. > Add new findings at the bottom of the relevant block rather than rewriting history. -**Current step:** Block 0 closed on 2026-09-18 (0.1–0.6 done and verified against a -live stack). Next: Block 1 needs client inputs for 1.1/1.2, so Block 2 (2.1, 2.2, -2.3) and 5.1 are the ones that can start immediately. +**Current step:** Block 0 closed, plus 2.1, 2.2 and 5.1 (2026-09-18). Next: 2.3 +(Docker secret `*_FILE` loading), then 2.4/2.5 (the release gate and its decayed +preflight). Block 1 still waits on client inputs for 1.1/1.2. **Last audit:** 2026-09-18, full read of `local/`, `dtf-site.html`, `deploy/`, `.gitea/`, docs and legacy prototypes. Findings below carry their audit IDs. @@ -171,7 +171,7 @@ and ships only fake adapters, so the deployed system cannot take an order at all ## Block 2 · Security — before any public exposure -### `[ ]` 2.1 — Rate limiting and audit logs are blind to the client `(F5)` +### `[x]` 2.1 — Rate limiting and audit logs are blind to the client `(F5)` uvicorn runs without trusted proxy headers (`forwarded_allow_ips` defaults to `127.0.0.1`; nginx is a different container IP), so `request.client.host` is nginx @@ -184,7 +184,7 @@ record has no attacker IP. - **Accept:** two clients on different IPs have independent buckets; audit rows carry the real IP. -### `[ ]` 2.2 — The public site throttles itself `(F6)` +### `[x]` 2.2 — The public site throttles itself `(F6)` `local/app.py:115` — `rate_limit('guest-sessions', ENVIRONMENT, 120, 900)` is keyed on the environment name: 120 new visitors per 15 minutes **site-wide** (~8/min). @@ -332,9 +332,13 @@ charges. Fix as part of 1.1. ## Block 5 · Hygiene and maintenance -- `[ ]` 5.1 — CI coverage `(F33)`. The smoke, workflow, security, retention and - browser suites exist under `local/` and would have caught 0.1 — none run in CI. - Add a compose-backed job. **Highest leverage item in this block.** +- `[x]` 5.1 — CI coverage `(F33)`. An `integration` job now builds the localhost + stack and runs smoke, workflow, security, scanning, retention, runtime security + and both browser suites; `publish-and-deploy` depends on it. Verified by + reintroducing the 0.1 defect: `py_compile` and the unit tests still passed while + `smoke_test` failed on `/session`, blocking the release. Browser tests skip with + a warning when the runner has no Chrome — **install `google-chrome-stable` on the + runner (or set `CHROME_BIN`) to make them gate as well.** - `[ ]` 5.2 — Remove or archive the dead prototypes `(F30)`: `portal/`, `kanban/`, `agente/`, root `schema.sql` (~1,500 lines describing an abandoned model). Several expose unauthenticated endpoints taking the acting user from the request body @@ -395,6 +399,20 @@ charges. Fix as part of 1.1. guard that refuses identical credentials in both configuration forms. - `[x]` Checkout confirmation moved out of the panel the success path hides. +### Block 2 and CI — 2026-09-18 + +- `[x]` The web gateway overwrites `X-Forwarded-For` with the peer address instead + of appending to it, and `client_ip()` resolves the requester for rate-limit + buckets and security events. Verified: a forged `203.0.113.99` never reaches the + audit trail. +- `[x]` Guest sessions are limited per source. The first attempt used 30/IP, which + the new regression caught as too tight for shared NAT — recreating the original + fault in a narrower form — so the ceiling is 240 per 15 minutes, overridable with + `GUEST_SESSION_LIMIT`. +- `[x]` Security events now carry the source address (`operator_login_failed`, + `customer_login_failed`, `cross_origin_rejected`, `http_security_event`). +- `[x]` CI runs the integration suites against a real stack before publishing. + ### Reporting - `[x]` Week-1 client report (`Relatorio-Semana-1-DTF.docx`), corrected 2026-09-18 to