Repository navigation
fix(tools): the bench web client logs back in on the 401 a dropped session gets - #291
Merged
Merged
Conversation
…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
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
tools/air_test_suite.py'sWeblogs 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:
/api/ls,WebManager_Files.cpp)requirePerm( )(/api/status,/api/users;WebManager_Auth.cpp:99-103,WebManager_Api.cpp:31){"error":"Unauthorized"}/api/loginor a password change:{"ok":false,"err":1})Found on 2026-10-24 on the S10c bench. A tool built on this client read
POST /api/users HTTP 401from a healthy device after its walks logged in, and its restore step could not log in either.Proof
tools/test_air_web_session.pyruns 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.The test joins the
gatesjob. 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