Skip to content

fix(tools): the bench web client logs back in on the 401 a dropped session gets - #291

Merged
angeloINTJ merged 1 commit into
mainfrom
fix/bench-web-relogin-401
Oct 25, 2026
Merged

angeloINTJ merged 1 commit into
mainfrom
fix/bench-web-relogin-401

Conversation

@angeloINTJ

Copy link
Copy Markdown
Owner

What

tools/air_test_suite.py's Web logs back in when a request comes back 403, which is what a stale cookie got after a reboot (measured 2026-09-07). But the device keeps one web session per user: a login reuses the user's slot with a new token (WebManager::allocSessionSlot, src/WebManager_Auth.cpp). So a second client logging in as the same user kills the first one's cookie while the device stays up, for example a walk run as a subprocess or the maintainer's browser.

The device answers that dead cookie in two ways:

Routes Answer The client before The client now
file routes (/api/ls, WebManager_Files.cpp) 403 logs in again, retries the same
behind requirePerm( ) (/api/status, /api/users; WebManager_Auth.cpp:99-103, WebManager_Api.cpp:31) 401 {"error":"Unauthorized"} returned it untouched logs in again, retries
a handler's own 401 (a wrong password at /api/login or a password change: {"ok":false,"err":1}) 401 untouched untouched: a retry would count a second failure toward the lockout

Found on 2026-10-24 on the S10c bench. A tool built on this client read POST /api/users HTTP 401 from a healthy device after its walks logged in, and its restore step could not log in either.

Proof

tools/test_air_web_session.py runs the client against a local stand-in for the device's rule: one session per user, the two answers above, and a password handler that counts its calls.

401 after another login 403 after another login wrong password never logged in
main's client FAIL (401, no new login) ok ok ok
this client ok ok ok (sent once) ok
mutant: retry on any 401 ok ok FAIL (the handler ran twice) ok

The test joins the gates job. The CI gates, run locally in a depth-1 clone: 37 of 37 steps pass (quick mode: native suites, sanitizers and fuzz skipped). Host only: no image changes, nothing ran on a board.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LyLm7Q1o7kCHngE63BnoTx

…ssion gets

tools/air_test_suite.py's Web logs back in when a request comes back 403,
which is what a stale cookie got after a reboot on 2026-09-07. The device
keeps one web session per user, though: a login reuses the user's slot with
a new token (WebManager::allocSessionSlot, src/WebManager_Auth.cpp), so a
second client logging in as the same user (a walk run as a subprocess, a
browser) kills the first one's cookie while the device stays up. The file
routes answer that cookie with 403. The routes behind requirePerm( ) answer
it with 401 {"error":"Unauthorized"} (WebManager_Auth.cpp:99-103,
WebManager_Api.cpp:31), and the client returned that untouched. On
2026-10-24, on the S10c bench, a tool built on this client read
"POST /api/users HTTP 401" from a healthy device after its walks had logged
in, and the run's restore step could not log in either.

The client now treats that 401, matched by its exact body, like the 403: it
logs in again and sends the request once more. Both are refused before the
handler runs. A 401 with any other body is a handler's own answer: a wrong
password at /api/login or at a password change answers {"ok":false,"err":1}.
That one stays untouched, since a retry would count a second failure toward
the lockout.

tools/test_air_web_session.py runs the client against a local stand-in for
the device's rule: one session per user, those two answers, and a password
handler that counts its calls.
- Before the fix: 3 ok, 1 failed (after another login, the 401 came back
  401 with no new login).
- After: 4 ok.
- A mutant that retries on any 401 fails exactly the wrong-password case
  (the handler ran twice).
The test joins the gates job in .github/workflows/build.yml. The CI gates,
run locally in a depth-1 clone: 37 of 37 steps pass (quick mode: native
suites, sanitizers and fuzz skipped). Host only: nothing here ran on a board.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LyLm7Q1o7kCHngE63BnoTx
@github-actions github-actions Bot added documentation Improvements or additions to documentation ci Continuous integration and automation tools Build tools, scripts, and developer tooling labels Oct 25, 2026
@angeloINTJ
angeloINTJ merged commit 12a6060 into main Oct 25, 2026
13 checks passed
@angeloINTJ angeloINTJ mentioned this pull request Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Continuous integration and automation documentation Improvements or additions to documentation tools Build tools, scripts, and developer tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant