Quellcode durchsuchen

docs: mark SEC_REVIEW F18 as fixed in 33179d8

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
chiappa vor 5 Tagen
Ursprung
Commit
8fa6cdd902
1 geänderte Dateien mit 45 neuen und 1 gelöschten Zeilen
  1. 45 1
      doc/SEC_REVIEW.md

+ 45 - 1
doc/SEC_REVIEW.md

@@ -11,7 +11,7 @@
 >
 > Each finding is referenced as **F<N>** for later citation.
 >
-> **Findings rolled up:** 5 sev-3 (5 fixed, 0 open), 27 sev-2 (10 fixed, 17 open), 42 sev-1.
+> **Findings rolled up:** 5 sev-3 (5 fixed, 0 open), 27 sev-2 (11 fixed, 16 open), 42 sev-1.
 
 ---
 
@@ -587,6 +587,50 @@
   CVE gets root inside the container. No `--chown` on `COPY`. The
   `irdb-data:/data` volume is owned by root.
 - **Severity: 2**
+- **Status:** Fixed in `33179d8`. Both `api/Dockerfile` and
+  `ui/Dockerfile` now create an `app` system user (UID/GID 1000) and
+  switch to it via `USER app` after the last root-required step
+  (`apk`, `install-php-extensions`, `chmod +x`, `mkdir`/`chown`).
+  FrankenPHP/Caddy bind to unprivileged ports (8080/8081) — no
+  `setcap` is needed.
+
+  Layout choices:
+  - `/app` stays **root-owned and world-readable**. The runtime needs
+    only read access; leaving source root-owned is a partial mitigation
+    for F20 (an attacker landing RCE under `app` cannot overwrite
+    `/app/vendor/**` or `/app/public/index.php` to persist). Tightening
+    the read-only stance further (e.g. mounting `/app` read-only at
+    runtime) is tracked separately by F20.
+  - `/data` is **app-owned** so phinx migrations, the
+    `auth:bootstrap-service-token` console call, and runtime SQLite
+    writes succeed without root. Newly-created Docker named volumes
+    (`irdb-data`) inherit this ownership on first creation.
+  - `/home/app/.config` and `/home/app/.local/share` are pre-created
+    and app-owned; `XDG_CONFIG_HOME` / `XDG_DATA_HOME` point at them
+    so Caddy's autosaved-config and TLS-cache state has somewhere to
+    land without falling back to `/root`.
+  - PHP sessions in the UI continue to use the default `/tmp` save
+    path (world-writable), so no extra mount is required.
+
+  **Upgrade note for operators.** Existing volumes from pre-F18
+  deployments were created when `/data` was root-owned; after pulling
+  this image the new uid=1000 process cannot write to them and phinx
+  fails with `attempt to write a readonly database`. Recover with
+  either of:
+  ```
+  # one-shot chown (preserves data)
+  docker run --rm -u 0 -v irdb_irdb-data:/data alpine chown -R 1000:1000 /data
+  # or, if the SQLite data is disposable
+  docker compose down -v && docker compose up -d
+  ```
+  Documented in the upgrade section of the deployment notes.
+
+  Verification: rebuilt both images and confirmed
+  `docker compose exec api id` / `exec ui id` report `uid=1000(app)`,
+  the api healthz returns 200, all 429 integration tests still pass
+  under the new user, and the UI Caddy log shows
+  `serving initial configuration` with TLS storage at
+  `/home/app/.local/share/caddy`.
 
 ### F19 — No `.dockerignore` — host artifacts baked into images
 - **Files:** build context roots `api/`, `ui/`; `COPY . ./` lines