From 3fc8f787f78439eeebd798827380b91070920246 Mon Sep 17 00:00:00 2001 From: Static Date: Mon, 3 Aug 2026 23:03:54 -0400 Subject: [PATCH] docs: remove generated internal task reports --- .../task-2-report.md | 130 ------------- .../task-2-report.md | 174 ------------------ 2 files changed, 304 deletions(-) delete mode 100644 .superpowers/sdd/2026-07-30-humwatch-api-auth-tls/task-2-report.md delete mode 100644 .superpowers/sdd/2026-07-30-humwatch-browser-hardening/task-2-report.md diff --git a/.superpowers/sdd/2026-07-30-humwatch-api-auth-tls/task-2-report.md b/.superpowers/sdd/2026-07-30-humwatch-api-auth-tls/task-2-report.md deleted file mode 100644 index c68c995..0000000 --- a/.superpowers/sdd/2026-07-30-humwatch-api-auth-tls/task-2-report.md +++ /dev/null @@ -1,130 +0,0 @@ -# Task 2 report - -## Changed files - -* `agent/security/auth.py` -* `agent/main.py` -* `agent/routes/health.py` -* `agent/routes/debug.py` -* `tests/conftest.py` -* `tests/test_api_auth.py` - -## Implementation choices - -* Added `require_bearer_token(request)` as a FastAPI dependency. It accepts only a two field, case insensitive Bearer authorization header and compares the credential with `secrets.compare_digest`. -* Missing, malformed, invalid, or unavailable credentials return HTTP 401 with `WWW-Authenticate: Bearer` and no credential detail. -* Registered health publicly under `/api/v1/health` and `/api/health`. -* Registered all telemetry, history, process, peer, SSE, and configuration routes under both prefixes with the bearer dependency. -* Kept static dashboard files public. -* Published stable health fields for service status, software version, API version, capabilities, authentication requirement, and TLS requirement. No token, credential source, process identifier, environment, or runtime path is returned. -* Gated debug registration behind `HUMWATCH_ENABLE_DEBUG`, disabled by default. Enabled debug remains authenticated and returns only LHM state and administrative state. -* Isolated API tests from the production lifespan. The test fixture now uses a no background task lifespan and resets the configuration singleton for each temporary test database. Production collector, retention, and discovery startup behavior was not changed. - -## Lifecycle diagnosis - -The original API fixture entered the real FastAPI lifespan for every test client. That lifespan starts the hardware collector, waits three seconds for sensor initialization, and launches retention and peer discovery tasks. Shutdown then has to cancel and await those tasks. A process inspection during the blocked run showed an old pytest process still alive for over six hours, alongside a newer bounded pytest process. The API tests do not need any of those background services, so the fixture was the wrong lifecycle boundary. - -## Test commands and outputs - -Initial focused run after writing the tests: - -```text -.venv/bin/python -m pytest tests/test_api_auth.py -q -30 errors during setup -ModuleNotFoundError: No module named 'fastapi' -``` - -The existing requirements were installed into the worktree environment with `uv` so the requested interpreter could run the suite. - -Before lifecycle isolation, the focused suite eventually completed but took 96.56 seconds: - -```text -30 passed, 1 warning in 96.56s (0:01:36) -``` - -After isolating the fixture lifecycle: - -```text -timeout 30 .venv/bin/python -m pytest tests/test_api_auth.py -q -.............................. [100%] -30 passed, 1 warning in 0.53s -``` - -Regression suite: - -```text -timeout 30 .venv/bin/python -m pytest -q -................................................. [100%] -49 passed, 1 warning in 0.54s -``` - -Syntax check: - -```text -.venv/bin/python -m compileall -q agent tests -``` - -Output: no output, exit status 0. - -Diff check: - -```text -git diff --check -``` - -Output: no output, exit status 0. - -## Concerns - -* The test suite emits one dependency warning from the installed FastAPI and Starlette TestClient integration about `httpx2`. It does not fail the suite. -* Debug output is intended only for controlled builds and is enabled through `HUMWATCH_ENABLE_DEBUG`. It remains bearer protected when enabled. - -## Round 1 review fixes - -* Wrapped `secrets.compare_digest` so non ASCII credential values that raise `TypeError` are treated as invalid credentials and return the existing generic 401 response. -* Added direct public coverage for `/api/health`. -* Added coverage for mixed case Bearer schemes and repeated or tab whitespace between the scheme and token. -* Kept browser authentication and EventSource work out of this API task. The route and token contract remains unchanged for the next plan. - -## Round 1 red evidence - -```text -timeout 30 .venv/bin/python -m pytest tests/test_api_auth.py::test_non_ascii_bearer_value_returns_unauthorized -q -F [100%] -E assert response.status_code == 401 -E assert 500 == 401 -1 failed, 1 warning -``` - -The failure reproduced the reviewer finding at the HTTP request boundary. The byte level non ASCII authorization value reached the application and caused the unhandled `compare_digest` type error to become HTTP 500. - -## Round 1 green evidence - -```text -timeout 30 .venv/bin/python -m pytest tests/test_api_auth.py -q -................................... [100%] -35 passed, 1 warning in 0.54s -``` - -```text -timeout 30 .venv/bin/python -m pytest -q -...................................................... [100%] -54 passed, 1 warning in 0.58s -``` - -```text -.venv/bin/python -m compileall -q agent tests -``` - -Output: no output, exit status 0. - -```text -git diff --check -``` - -Output: no output, exit status 0. - -## Round 1 concerns - -* The test suite still emits the existing non failing FastAPI and Starlette TestClient warning about `httpx2`. -* Browser bearer header and native EventSource support remain intentionally deferred to the sequenced browser hardening plan. diff --git a/.superpowers/sdd/2026-07-30-humwatch-browser-hardening/task-2-report.md b/.superpowers/sdd/2026-07-30-humwatch-browser-hardening/task-2-report.md deleted file mode 100644 index d784a16..0000000 --- a/.superpowers/sdd/2026-07-30-humwatch-browser-hardening/task-2-report.md +++ /dev/null @@ -1,174 +0,0 @@ -# Task 2 Report ... Authenticated browser SSE - -## Status - -Implemented and verified in `/projects/HumWatch/.worktrees/humwatch-security-hardening`. - -## Changed files - -- `static/js/api.js` ... added `_fetchStream`, which reuses the existing authenticated header builder without applying JSON response handling to a streaming response. -- `static/js/sse.js` ... replaced native EventSource with an AbortController backed `fetch` stream reader. It uses `/api/v1/sse`, sends the bearer token in an Authorization header, parses SSE event and data fields at blank line boundaries, dispatches the existing metrics and processes callbacks, preserves capped exponential reconnects and gap filling, handles 401 as reauthentication without reconnecting, and cancels the reader plus aborts the request on disconnect. -- `tests/test_frontend_sse.py` ... added the required source contract tests plus Node browser harness coverage for authenticated metrics dispatch, client abort cleanup, and 401 behavior. - -## Choices - -- Used `HumWatch.api._fetchStream` so SSE gets the same header composition as the rest of the API client while retaining access to the raw Response body. -- Kept the SSE token in the Authorization request header only. No token is placed in the endpoint URL. -- Reader cancellation and request abortion are both performed during disconnect. This closes the browser side stream so the server can detect the disconnect and remove its subscriber. -- A 401 calls the established `HumWatch.auth.handleUnauthorized()` flow. That flow clears the stored session and prompts for a replacement token. No reconnect timer is scheduled. -- Kept the existing 1 second to 30 second capped exponential reconnect behavior and current metric gap fill. - -## Verification - -### Red phase - -Command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q -``` - -Output: - -```text -FF -2 failed in 0.02s -``` - -The failures were the expected native EventSource use and missing `/api/v1/sse` endpoint. After adding the behavioral harness test, the focused suite remained red before implementation: - -```text -FFF -3 failed in 0.08s -``` - -### Green and regression checks - -Command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q && node --check static/js/api.js && node --check static/js/sse.js -``` - -Output: - -```text -... -3 passed in 0.07s -``` - -Command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q && node --check static/js/api.js && node --check static/js/sse.js && .venv/bin/python -m pytest tests/test_frontend_auth.py tests/test_frontend_sse.py tests/test_security_contract.py -q -``` - -Output: - -```text -.... -4 passed in 0.12s -................... -19 passed in 0.54s -``` - -Command: - -```bash -git diff --check -``` - -Output: - -```text -No output ... exit 0. -``` - -## Self review - -Checked that the endpoint is versioned, native EventSource is gone, the bearer token is header only, active stream resources are cleared on disconnect, and stale fetch completions cannot schedule a duplicate reconnect after a newer connection begins. - -## Concerns - -The stream reader depends on the standard browser Fetch, AbortController, TextDecoder, and ReadableStream APIs. Current supported desktop browsers provide these APIs. No browser integration test against a live FastAPI server was run in this bounded task. The Node harness verifies the browser side contract and the existing Python security contract tests remain green. - -## Round 1 ... Stream newline framing fix - -### Root cause - -The original stream parser normalized CRLF pairs only. A valid CR only stream left its record separators as `\r`, so the parser never saw the `\n\n` boundary that dispatches an SSE event. A trailing CR at a chunk boundary also cannot be normalized immediately because the next chunk may begin with LF, making the pair one CRLF newline rather than two newline characters. - -### Changes - -- `static/js/sse.js` ... added stateful newline normalization. A trailing CR is held until the next decoded chunk confirms whether it is a lone CR or the first half of CRLF. CR only, CRLF, and LF framing all reach the existing blank line parser as LF without introducing false blank records. -- `tests/test_frontend_sse.py` ... added a Node stream harness that covers CR only records, CRLF line ending and blank boundary splits across chunks, an empty decoded chunk between the two halves of CRLF, an event field split across chunks, and joined multiline data fields. - -### Verification - -Red phase command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q -``` - -Output: - -```text -..F.. -1 failed, 4 passed in 0.17s -``` - -The failing event showed the CR only metrics fields merged into the next event name instead of producing a metrics callback. - -Green and related checks command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q && node --check static/js/api.js && node --check static/js/sse.js && .venv/bin/python -m pytest tests/test_frontend_auth.py tests/test_frontend_sse.py tests/test_security_contract.py -q && git diff --check -``` - -Output: - -```text -..... -5 passed in 0.17s -.................... -20 passed in 0.56s -``` - -The two Node syntax checks and `git diff --check` produced no output and exited 0. - -### Empty chunk regression check - -After extending the fragmented CRLF test with an empty decoded chunk between `\r` and `\n`, the prior normalizer dispatched the processes event after its first data line. - -Command: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q -``` - -Output: - -```text -..F.. -1 failed, 4 passed in 0.18s -``` - -The guard now retains the pending CR through an empty chunk. Fresh verification after that change: - -```bash -.venv/bin/python -m pytest tests/test_frontend_sse.py -q && node --check static/js/api.js && node --check static/js/sse.js && .venv/bin/python -m pytest tests/test_frontend_auth.py tests/test_frontend_sse.py tests/test_security_contract.py -q && git diff --check -``` - -```text -..... -5 passed in 0.15s -.................... -20 passed in 0.55s -``` - -The syntax and diff checks again had no output and exited 0. - -### Round 1 concerns - -No live browser to FastAPI SSE integration run was performed in this bounded fix. The Node harness exercises the fetch stream parser with the relevant byte chunk boundaries and preserves the existing authenticated connection, abort cleanup, reconnect, and 401 coverage.