Skip to content

Server HTTP tests; fix two things they found (1.4.1) - #4

Merged
usermaneGermane merged 2 commits into
mainfrom
server-http-tests
Oct 11, 2026
Merged

usermaneGermane merged 2 commits into
mainfrom
server-http-tests

Conversation

@usermaneGermane

Copy link
Copy Markdown
Owner

Adds tests/test_server_http.py — 79 tests, ~4 s, standard library only, the same file in both server repos — and fixes the two server bugs it found. Bumps the version to 1.4.1 (patch).

Why

The server repos' tests covered setup, listen settings, logging and bind, but never sent the server a request. Request handling was only tested from the clients, through client code, so the refusals meant for a broken, outdated or hostile client were never run.

What the tests cover

  • Token: /health is open; everything else is 401 without Bearer <token> (missing, wrong, Basic, no scheme, lowercase bearer); checked before routing.
  • Paths: only /vault/<user> and /vault/<user>/meta; dangerous usernames (.., .hidden, con, NUL, 64 chars, …) refused and nothing created; 63 chars accepted; POST/DELETE/PATCH → 501.
  • If-Match: first push without it OK; later push without it → 428; stale → 409 with the store unchanged; quoted revision accepted; * overwrites; two pushes racing for one revision → exactly one 200 and one 409.
  • Bodies: not JSON / no blob / not a string / not ASCII / not base64 / too short → 400; empty or nonsense Content-Length → 400; over 8 MB → 413 without reading it.
  • History: each push keeps the revision it replaces; trimmed to HISTORY_LIMIT (20); X-PassMan-Drop-History: 1 clears it.
  • Key generation: stored, kept when the header is left out, nonsense → 400.
  • Responses: Cache-Control: no-store and JSON on successes and errors.
  • Access log: names the request, never the body, the token or the query string; garbled request lines are refused and the server carries on.

Mutation-checked: removing the lock, the revision check or the If-Match requirement each makes its test fail.

Fixed in server/passman_server.py

  1. GET /vault/<user>/meta/<anything> returned the user's meta: _user_from_path ignored parts after the third. Now 404, as its docstring says.
  2. The access log kept the query string, which log_message's docstring says it leaves out. A log_request override now cuts it from the logged request line.

Neither had a practical effect (both need the token; the clients send no query strings), but the file now does what it says.

The same server file goes to both clients' test copies in separate PRs (Client-Windows, Client-Linux); all four copies stay byte-identical.

Also

  • Test fixture polls for shutdown every 10 ms instead of 0.5 s (otherwise the file took 40 s).
  • README Development section: describes the new tests; both clients (not only Windows) keep a copy of passman_server.py.

Tested

Full suite locally on Python 3.13 (Windows): 171 passed.

🤖 Generated with Claude Code

https://claude.ai/code/session_011jnuqjxmKqjXT4CuBRJMzr

usermaneGermane and others added 2 commits October 11, 2026 18:38
tests/test_server_http.py (79 tests, ~4 s, identical in both server repos)
talks to a real server on 127.0.0.1 with no client: the token, routing and
usernames, If-Match (428 / 409 / "*" / two pushes racing for one revision),
malformed and oversized bodies, history trimming and drop-history, the key
generation header, Cache-Control, the access log, garbled request lines.
Until now the request handling was only exercised from the clients, which
never send what a broken or hostile client would.

Fixed in passman_server.py (the same file in all four repos):
- GET /vault/<user>/meta/<anything> answered with the meta; the path
  parser ignored parts after the third. Now 404, as its docstring says.
- The access log kept the query string, which log_message's docstring
  says it leaves out. log_request now cuts it from the request line.
Neither had a practical effect: both need the token, and the clients send
no query strings.

READMEs: describe the new tests; both clients (not just Windows) keep a
copy of passman_server.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jnuqjxmKqjXT4CuBRJMzr
CI on Python 3.13 failed the garbled-request test: the error page came
after the headers and one recv() only had the headers. Read until the
server closes instead.

Also stop sending what the server refuses before reading -- a body on a
PUT that fails the token or path check, the extra blank line after a
garbled request line. Closing a socket with unread bytes can send a reset
instead of a normal close, which can lose the answer: one local run
failed that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011jnuqjxmKqjXT4CuBRJMzr
@usermaneGermane
usermaneGermane merged commit a5df2fc into main Oct 11, 2026
3 checks passed
@usermaneGermane
usermaneGermane deleted the server-http-tests branch November 8, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant