remove docs/CHANGES-2026-09.md: one-off audit-batch record, every fix already in the git log with explanatory commits; drop its mention from SPEC milestones
This commit is contained in:
1 parent
de0bf8b156
commit
63a677f028
2 files changed
+2
-55
No files matched your search
@@ -184,6 +184,5 @@ shipped since this list was written.) Add when someone asks.
|
||||
states, autoplay default, `run.sh`.
|
||||
7. Auth — login screen, then multi-user CLI-created accounts with
|
||||
per-user history + test suite.
|
||||
8. Later (see git log, `docs/CHANGES-2026-09.md`): provider layer with
|
||||
hianime primary, SQLite storage, stats/events, 2026-09 security
|
||||
audit batch.
|
||||
8. Later (see git log): provider layer with hianime primary, SQLite
|
||||
storage, stats/events, 2026-09 security audit batch.
|
||||
@@ -1,52 +0,0 @@
|
||||
# Code-audit fix batch (2026-09)
|
||||
|
||||
Findings from the 2026-09-15 code audit, in shipping order. The systemd
|
||||
cutover was explicitly deferred — the process stays on run.sh's nohup
|
||||
model; only the restart mechanism's blast radius is fixed here.
|
||||
|
||||
## 1. login handler blocks the event loop (HIGH)
|
||||
|
||||
`login` is `async def`, so the anti-brute-force `time.sleep(0.5)` inside
|
||||
the lockout check runs ON the event loop: every wrong password stalls
|
||||
every in-flight request (all streams included) on the single worker.
|
||||
Fix: make the handler a plain `def` (uvicorn runs it on the threadpool);
|
||||
move the lockout logic into a side-effect-free `server/auth.py` so it is
|
||||
unit-testable without booting the app. Regression test measures
|
||||
`/api/cdn` latency while a wrong-password login is mid-sleep.
|
||||
|
||||
## 2. run.sh global pkill (HIGH)
|
||||
|
||||
`pkill -f "uvicorn .*app:app"` also matches the test server
|
||||
(`uvicorn server.app:app --host 127.0.0.1 --port 8399`): an ani-web
|
||||
restart kills running test sessions (and vice versa). Fix: PID file
|
||||
(`server.pid`) becomes the primary kill path; any pattern fallback is
|
||||
port-scoped to the real instance.
|
||||
|
||||
## 3. lockout is per-username only (MEDIUM)
|
||||
|
||||
Spreading failures across usernames bypasses the per-username lockout
|
||||
entirely (and anyone can lock a known account for 15 min). Add a
|
||||
per-IP failure budget (`ANIWEB_IP_FAILS` / window) on top of the
|
||||
per-username lockout. Client IP = `request.client.host`; the reverse
|
||||
proxy's `X-Forwarded-For` is consulted only when `ANIWEB_TRUST_XFF=1`
|
||||
(set by run.sh), so a spoofed header can't widen or narrow the gate.
|
||||
|
||||
## 4. login is exempt from the CSRF header check (MEDIUM)
|
||||
|
||||
The custom-header check that makes cross-site form POSTs fail excludes
|
||||
`/login`. The exemption is load-bearing only by accident (JSON body
|
||||
content-type); login becomes covered by the same check as every other
|
||||
mutation, and login.html sends the header.
|
||||
|
||||
## 5. dependencies unpinned (MEDIUM)
|
||||
|
||||
`curl_cffi` version churn = impersonation churn = silent upstream 403
|
||||
waves. requirements.txt becomes a full freeze; bump deliberately.
|
||||
|
||||
## 6. live-upstream e2e gated off by default
|
||||
|
||||
The Playwright tests scrape and play real provider content — they go red
|
||||
whenever a provider rotates or a title is taken down (observed repeatedly).
|
||||
A suite that fails for non-regressions can't gate anything, so the default
|
||||
run is now hermetic only; run the live e2e deliberately with
|
||||
`ANIWEB_LIVE_TESTS=1`.
|
||||
Reference in new issue
Block a user