|
|
@@ -1048,6 +1048,28 @@ with a `BOOTSTRAP_ADMIN` audit row.
|
|
|
unchanged. *New sprint* stays in the header as the one
|
|
|
quick-action admins reach for from any page.
|
|
|
|
|
|
+- [x] **R01-N01 — Local-admin password is hash-only (no plaintext fallback)**
|
|
|
+ (`857df15`). `src/Auth/LocalAdmin.php` previously read the password
|
|
|
+ verbatim from `LOCAL_ADMIN_PASSWORD` and compared it with
|
|
|
+ `hash_equals()`; anyone with read access to `.env` had immediate
|
|
|
+ admin. Now the env var is `LOCAL_ADMIN_PASSWORD_HASH` (a
|
|
|
+ `password_hash()` output, typically `$2y$...` bcrypt) and
|
|
|
+ verification is `password_verify()`. Operator's explicit choice
|
|
|
+ was the clean break — there is *no* plaintext fallback. Existing
|
|
|
+ deployments must regenerate the hash before the next sign-in;
|
|
|
+ until they do, `LocalAdmin::isEnabled()` returns false and
|
|
|
+ `/auth/local` 404s rather than silently re-using stale config.
|
|
|
+ Email comparison stays `hash_equals()` (timing-safe) on the
|
|
|
+ trimmed input. Hash recipe lives in README §Quick setup step 3
|
|
|
+ and admin-manual §3.5 — both ship the host-PHP one-liner *and*
|
|
|
+ the `docker run --rm php:8.3-cli php -r '...'` form for
|
|
|
+ hash-without-host-PHP, with the single-quotes-in-`.env` warning
|
|
|
+ so the `$` segments aren't eaten by the shell that runs
|
|
|
+ `docker compose up`. New `tests/Auth/LocalAdminTest.php` (9
|
|
|
+ cases) locks the contract in, including a regression guard
|
|
|
+ asserting that `LOCAL_ADMIN_PASSWORD` alone does *not* enable
|
|
|
+ the fallback. Tests: 159 / 443 (was 150 / 430).
|
|
|
+
|
|
|
- [x] **R01-N04 — `SESSION_SECRET` removed from env template + docs**
|
|
|
(`296883c`). The env var was documented as the salt for the
|
|
|
session cookie name / CSRF tokens but nothing in the code reads
|
|
|
@@ -1148,7 +1170,7 @@ for f in $(git ls-files '*.php'); do php -l "$f" | tail -1 | sed "s|^|$f: |"; do
|
|
|
Run the test suite:
|
|
|
```bash
|
|
|
vendor/bin/phpunit
|
|
|
-# → OK (150 tests, 430 assertions)
|
|
|
+# → OK (159 tests, 443 assertions)
|
|
|
```
|
|
|
|
|
|
The Phase 20 parser tests need `ext-dom`, `ext-zip`, `ext-xmlreader`,
|
|
|
@@ -1195,6 +1217,8 @@ before acting — nothing here is load-bearing once it grows stale.
|
|
|
## 13. Git history (as of this writing)
|
|
|
|
|
|
```
|
|
|
+857df15 Fix R01-N01: hash-only LOCAL_ADMIN_PASSWORD_HASH (no plaintext fallback)
|
|
|
+f075e12 Docs: mark R01-N04 fixed, refresh SPEC §9 / §13
|
|
|
296883c Fix R01-N04: drop unused SESSION_SECRET from env template + docs
|
|
|
18389bb Docs: mark R01-N02 / R01-N31 fixed, refresh SPEC §9 / §11 / §13
|
|
|
7fd849b Fix R01-N02 / R01-N31: gate runtime panel on home page to admins
|