Add terminal API tests and fix silent CSRF reload - #6
Conversation
Tests (35 new): - test_ttyd_manager.py: TTYDManager create/delete/list/get, port allocation, limits, dead process cleanup - test_csrf.py: CSRF token round-trip, expiry, tampering, edge cases - test_terminals_api.py: TTYD route pattern matching Fixes: - Show "Session expired, reloading..." on CSRF 419 instead of silently reloading the page (caused "nothing happens" on button) - Reset button text in .finally() if stuck on "Creating..." Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production. |
|
Claude finished @axisrow's task in 2m 22s —— View job PR Review: Add terminal API tests and fix silent CSRF reload
SummaryThe production fix in Issues Found1. Tests copy production code instead of importing — silent divergence risk (medium)
The comment 2.
|
Triage of review commentsComment 1 — Test copy diverges from production (missing tmux cleanup, _cleanup_dead)Verdict: FIX. Confirmed — test copy was simplified. Fixed: added tmux cleanup in delete_terminal, added _cleanup_dead method, moved cleanup outside lock in list_terminals/get_terminal. Added test_delete_terminal_kills_tmux_session. Comment 2 — test_delete_terminal_kill_on_timeout tests wrong pathVerdict: FIX. Confirmed — side_effect hit both wait() calls. Fixed with list side_effect: Comment 3 — Button re-enabled during 419 reload windowVerdict: SKIP. Cosmetic — double-click during 500ms window produces another 419 which also reloads. No data loss or security impact. |
- Add tmux kill-session cleanup to delete_terminal test copy - Add _cleanup_dead method matching production implementation - Move cleanup outside lock in list_terminals/get_terminal - Fix test_delete_terminal_kill_on_timeout: use list side_effect so only first wait() raises TimeoutExpired - Add test_delete_terminal_kills_tmux_session - Add subprocess.run mocks where tmux cleanup runs Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@claude review. Focus on critical issues: bugs, security vulnerabilities, logical errors, data loss risks, performance problems. Do NOT nitpick style, naming conventions, minor formatting, or subjective preferences — only flag issues that could break functionality or cause real harm in production. |
|
Claude finished @axisrow's task in 2m 53s —— View job PR Review: Add terminal API tests and fix silent CSRF reload
SummaryThe two issues flagged in the previous review have been properly fixed. The production fix is correct. No new critical issues found — this PR looks ready to merge. Previous Issues — Verified FixedIssue 1 — Test copy diverged from production ( Fixed. The test copy now includes:
Issue 2 — Fixed. Production Fix Correctness Verified
The One Observation (not blocking)
What Looks Good
|
) Six P1 correctness/reliability fixes from the #101 code review. #3 (proxy.py): enable SO_KEEPALIVE on both tunnel sockets so a client that vanishes without a FIN (laptop sleep, NAT timeout) is detected by the OS and the idle tunnel thread + sockets are freed instead of leaking forever. #4 (ratelimit.py): use time.monotonic() instead of wall-clock time.time(), so a backward clock jump (NTP correction, suspend/resume, VM migration) cannot freeze the window and lock out legitimate users past 60s/300s. #5 (app.py): _check_auth now honours redirect=True in the removed-user branch — a browser navigation with a valid cookie whose account was deleted/renamed lands on /login (302) instead of a raw 403 JSON blob. #6 (proxy.py): add "cookie" to HOP_BY_HOP_HEADERS so the client's signed ttyd_session + csrf_token is not forwarded to the internal ttyd (defense depth). #10 (bin/clihost-sync.sh): the remote symlink guards were byte-identical triplicates (local pair + one copy in each of two `bash -s` heredocs), so hardening one silently bypassed the others — the class of bug caught 3× before (#88/#90/#95). Define them once in a shared emit_remote_prelude injected into both remote payloads. #11 (.env.example): document SESSION_TIMEOUT, CLEANUP_ROOT, ROOT_PASSWORD, HAPI_USER, HERMES_AUTO_UPDATE (read by code + CLAUDE.md but missing from the example), plus the REQUEST_TIMEOUT slowloris knob for completeness. New/changed env vars documented in .env.example: SESSION_TIMEOUT, CLEANUP_ROOT, ROOT_PASSWORD, HAPI_USER, HERMES_AUTO_UPDATE, REQUEST_TIMEOUT. No port or volume changes. Closes #101 findings #3, #4, #5, #6, #10, #11. Claude-Session: https://claude.ai/code/session_01KgvJhzd8gEhXVE4MVu18nn Co-authored-by: axisrow <axisrow@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Test plan
python -m pytest tests/— 128 tests pass (93 existing + 35 new)🤖 Generated with Claude Code