Add admin firmware upload support

Implement authenticated HTTPS OTA uploads with bounded streaming, image
validation, reboot coordination, and lifecycle exclusion. Add the admin
UI,
regression tests, and Phase 10 acceptance documentation.
This commit is contained in:
2026-09-18 22:22:11 +02:00
parent 4f628a4098
commit 31a22eba06
31 changed files with 1442 additions and 88 deletions
+7 -1
View File
@@ -88,10 +88,16 @@ This is a semantic map, not a complete file inventory. Start here, then read the
### Browser admin backend
- Files: `src/web_admin_transport.{c,h}`, `src/web_admin_tickets.{c,h}`, protected registration/lifecycle in `web_server.c`, revocation through `web_serial_transport_revoke_*`, diagnostics in `web_console.c`.
- Routes: CSRF-protected admin-only `POST /api/admin/ws-ticket`; ordinary `GET /ws/admin` with cookie/Origin/ticket/shared-console admission before explicit 101. Admin UI entry is explicit; no admin broker client. One socket, two tickets, existing two shared console slots; six total HTTPD sockets, LRU disabled; current overall capacity is 39 URI handlers.
- Routes: CSRF-protected admin-only `POST /api/admin/ws-ticket`; ordinary `GET /ws/admin` with cookie/Origin/ticket/shared-console admission before explicit 101. Admin UI entry is explicit; no admin broker client. One socket, two tickets, existing two shared console slots; six total HTTPD sockets, LRU disabled; current overall capacity is 40 URI handlers.
- Currentness/policy: `admin_ssh_console_open_available()` shares two slots with runtime SSH; transport-qualified tokens and owner adapters revalidate outside console locks before commands/prompts. Parsed browser policy remains narrower than typed Settings; [shell contract](../web_administration.md#browser-shell-policy). Tests: `tests/admin_console_boundary/{run,accounts,lifecycle}.py`, `tests/admin_ssh_policy/run.py`, `tests/web_admin_transport/run.py --tickets`, `tests/web_cookie_auth/run.py --admin`.
- Ownership: 20 ms ESP timer queues at most one HTTPD poll, no new task; HTTPD owns 1,552 B PSRAM-only payload and IO. Closure uses HTTPD-owned `shutdown`, not IDF's reusable-pointer queued close. Detach fences submitters; only successful HTTPD stop retires queued state before restart. Session/principal currentness and generation checks protect all sensitive boundaries.
## Firmware upload
- `src/web_firmware_update.{c,h}`: admin raw `POST /api/firmware`, cookie/Origin/CSRF admission via `web_cookie_auth`, registration in `web_server`, UI in `web_ui`. Standard SDK OTA into inactive app only; bounded4KiB buffer, validated raw length/header/final image and principal before boot selection. No NVS/layout writes or vendor patches.
- HTTPD handles streaming synchronously; upload is deliberately disruptive to web traffic. Server/identity reservations fence lifecycle changes; atomic ordinary-reboot gate also covers console/SSH/browser/button reset paths. Success-response schedules delayed reset; response failure after selection latches uploads until deliberate manual reboot. No blind retries.
- Tests: `tests/web_firmware_update/run.py` (active-build SDK5.5.0 headers and actual begin/abort contract), `tests/web_ui_session/run.py`, existing auth/lifecycle tests. [Usage, acceptance limits and reusable regression checks](../roadmap.md#phase-10--simple-admin-web-firmware-upload). Phase 10 complete by explicit user acceptance on 2026-09-18: upload works and normal operation verified; no specific fault/NVS-comparison/power-loss/recovery pass implied. Initial install by wire; subsequent upload is application `firmware.bin`, not full-flash image.
## Typed settings source and regression map
HTTPD reads zero-wait projections and queues only IDs to the existing dispatcher. One original-login slot per domain; canonical owners compare/reserve at execution. [API/lifetime and failure contracts](../web_administration.md#typed-settings-api-and-operation-lifetime).