{ "schema": "jarca-ledger.review-evidence/v1", "issue": 6, "pull_request": 7, "source_review": 51, "finding": "D6-23", "contract_sha256": "4f734169ec896747fe39fd7f3ab75d1fc0d8cdd4903045e665beba40d80eb1fe", "verified_at_utc": "2026-10-03T00:10:43Z", "source_revision": "e7242a89f7f1faacbe984713a5ad211bd7bcac2b", "source_tree_clean_before_evidence_write": true, "environment": { "os": "Linux 6.18.34+rpt-rpi-v8", "architecture": "aarch64", "python": "3.13.5", "starlette": "1.3.1", "httpx": "0.28.1", "streamlit": "1.58.0", "uvicorn": "0.49.0", "itsdangerous": "2.2.0", "credentials": "synthetic test-only values; not recorded", "signing_secret": "synthetic test-only value; not recorded" }, "commands": [ { "purpose": "Focused route, hardened cookie, event-loop offload, and failed-delay helper verification", "command": "uv run --extra dashboard --extra dev pytest -q tests/test_dashboard_auth_server.py tests/test_dashboard_authentication.py", "exit_code": 0, "result": "29 passed; one Starlette/httpx deprecation warning", "relevant_output": "............................. [100%]\n=============================== warnings summary ===============================\ntests/test_dashboard_auth_server.py:11\n /opt/data/gitea-agent/repositories/jsfamily/jarca-ledger-mcp/worktrees/issue-6/checkout/tests/test_dashboard_auth_server.py:11: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.\n from starlette.testclient import TestClient\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html" }, { "purpose": "Real-delay concurrent failed login plus successful login and hardened cookie runtime probe", "command": "uv run --extra dashboard python - <<'PY'\nimport asyncio\nimport json\nimport os\nimport secrets\nimport time\n\nfrom starlette.requests import Request\n\nfrom dashboard import authentication\nfrom dashboard.auth_server import login\n\nadmin_id = \"synthetic-\" + secrets.token_hex(8)\nadmin_password = secrets.token_hex(16)\nos.environ[authentication.ADMIN_ID_ENV] = admin_id\nos.environ[authentication.ADMIN_PASSWORD_ENV] = admin_password\nos.environ[authentication.SIGNING_SECRET_ENV] = secrets.token_hex(32)\n\n\ndef request(password: str) -> Request:\n body = f\"admin_id={admin_id}&admin_password={password}\".encode()\n sent = False\n\n async def receive():\n nonlocal sent\n if sent:\n return {\"type\": \"http.disconnect\"}\n sent = True\n return {\"type\": \"http.request\", \"body\": body, \"more_body\": False}\n\n scope = {\n \"type\": \"http\",\n \"method\": \"POST\",\n \"scheme\": \"https\",\n \"path\": \"/api/auth/login\",\n \"raw_path\": b\"/api/auth/login\",\n \"query_string\": b\"\",\n \"headers\": [\n (b\"host\", b\"testserver\"),\n (b\"origin\", b\"https://testserver\"),\n (b\"content-type\", b\"application/x-www-form-urlencoded\"),\n ],\n \"client\": (\"testclient\", 50000),\n \"server\": (\"testserver\", 443),\n }\n return Request(scope, receive)\n\n\nasync def main() -> None:\n wrong_password = secrets.token_hex(16)\n started = time.monotonic()\n failures = [asyncio.create_task(login(request(wrong_password))) for _ in range(2)]\n await asyncio.sleep(0.1)\n probe_elapsed = time.monotonic() - started\n success_started = time.monotonic()\n success = await login(request(admin_password))\n success_elapsed = time.monotonic() - success_started\n failed = await asyncio.gather(*failures)\n total_elapsed = time.monotonic() - started\n cookie = success.headers.get(\"set-cookie\", \"\")\n assert success.status_code == 303\n assert success.headers[\"location\"] == \"/\"\n assert all(marker in cookie for marker in [\"HttpOnly\", \"Secure\", \"SameSite=lax\", \"Path=/\", \"Max-Age=86400\"])\n assert all(response.status_code == 303 for response in failed)\n assert all(\"set-cookie\" not in response.headers for response in failed)\n assert probe_elapsed < 0.5\n assert success_elapsed < 0.5\n assert 0.95 <= total_elapsed < 1.75\n print(json.dumps({\n \"success\": True,\n \"source_revision\": \"e7242a89f7f1faacbe984713a5ad211bd7bcac2b\",\n \"successful_login_status\": success.status_code,\n \"successful_login_cookie_hardened\": True,\n \"failed_login_statuses\": [response.status_code for response in failed],\n \"failed_login_cookie_absent\": True,\n \"event_loop_probe_elapsed_seconds\": round(probe_elapsed, 6),\n \"successful_login_elapsed_seconds\": round(success_elapsed, 6),\n \"concurrent_failed_logins_total_elapsed_seconds\": round(total_elapsed, 6),\n \"minimum_failed_login_delay_seconds\": 1.0,\n \"credentials_and_cookie_values_recorded\": False,\n }, indent=2))\n\n\nasyncio.run(main())\nPY", "exit_code": 0, "result": { "success": true, "source_revision": "e7242a89f7f1faacbe984713a5ad211bd7bcac2b", "successful_login_status": 303, "successful_login_cookie_hardened": true, "failed_login_statuses": [ 303, 303 ], "failed_login_cookie_absent": true, "event_loop_probe_elapsed_seconds": 0.10056, "successful_login_elapsed_seconds": 0.001267, "concurrent_failed_logins_total_elapsed_seconds": 1.00614, "minimum_failed_login_delay_seconds": 1.0, "credentials_and_cookie_values_recorded": false }, "relevant_output": "{\n \"success\": true,\n \"source_revision\": \"e7242a89f7f1faacbe984713a5ad211bd7bcac2b\",\n \"successful_login_status\": 303,\n \"successful_login_cookie_hardened\": true,\n \"failed_login_statuses\": [\n 303,\n 303\n ],\n \"failed_login_cookie_absent\": true,\n \"event_loop_probe_elapsed_seconds\": 0.10056,\n \"successful_login_elapsed_seconds\": 0.001267,\n \"concurrent_failed_logins_total_elapsed_seconds\": 1.00614,\n \"minimum_failed_login_delay_seconds\": 1.0,\n \"credentials_and_cookie_values_recorded\": false\n}" } ], "hashes_sha256": { "dashboard/auth_server.py": "4b991fbe942b573f8be270538b7e9df81bca9ffed3a8982f09db0d95d26e66d1", "dashboard/authentication.py": "63df2e33ef10859039c9b8140e92cbf0c7c8c9fe2d19cfcedbf16637c8cc2596", "tests/test_dashboard_auth_server.py": "8b96421af776b613867a8a5ab5dd962033b39d1cc616ba4e91cf3c4de63a1f0d", "tests/test_dashboard_authentication.py": "1ca7ecc4d4db55c674aa2934d665b121476ff5fa2e1f74071090a67e815af676", "pyproject.toml": "64100d3aa1c2272df2e2139ed435724901f7215ea72e48bee9d73f95e7e53a8d" }, "redaction": { "credentials_recorded": false, "signing_secret_recorded": false, "token_or_cookie_value_recorded": false, "request_body_recorded": false, "raw_set_cookie_recorded": false }, "notes": [ "This artifact is an evidence-only descendant of source_revision; the application and test paths hashed above were not modified before these commands ran.", "The runtime probe exercised the changed streaming login path with synthetic credentials, confirmed hardened 24-hour cookie issuance, retained the real one-second failed-login delay, and showed the event loop and a successful login remained responsive while two failed requests waited.", "This D6-23 evidence does not replace or claim a fresh browser run; D6-22 remains supported by docs/evidence/issue-6-persistent-auth-https.json and the Review #51 change-impact analysis." ] }