diff --git a/.agents/phases/todo/82_security_headers/00_phase.md b/.agents/phases/complete/82_security_headers/00_phase.md similarity index 100% rename from .agents/phases/todo/82_security_headers/00_phase.md rename to .agents/phases/complete/82_security_headers/00_phase.md diff --git a/.agents/phases/todo/82_security_headers/01_headers_middleware.md b/.agents/phases/complete/82_security_headers/01_headers_middleware.md similarity index 100% rename from .agents/phases/todo/82_security_headers/01_headers_middleware.md rename to .agents/phases/complete/82_security_headers/01_headers_middleware.md diff --git a/.agents/phases/todo/82_security_headers/02_registration_and_integration.md b/.agents/phases/complete/82_security_headers/02_registration_and_integration.md similarity index 100% rename from .agents/phases/todo/82_security_headers/02_registration_and_integration.md rename to .agents/phases/complete/82_security_headers/02_registration_and_integration.md diff --git a/.agents/phases/todo/82_security_headers/03_e2e_and_commit.md b/.agents/phases/complete/82_security_headers/03_e2e_and_commit.md similarity index 100% rename from .agents/phases/todo/82_security_headers/03_e2e_and_commit.md rename to .agents/phases/complete/82_security_headers/03_e2e_and_commit.md diff --git a/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.err b/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.md b/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.md new file mode 100644 index 0000000..bfe16a5 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.md @@ -0,0 +1,15 @@ +All completion criteria verified green — no defects found, nothing to fix. Final report: + +**Phase 82 (security headers) — final verification pass: all green** + +- Verified prior-run implementation: `app/core/security_headers.py` (pure-ASGI, header-only, exact A1 CSP), registration in `app/main.py` after `configure_caching` (outermost), unit/integration/E2E suites. +- Deviation confirmed sound: `data:`-URI favicon (blocked by locked CSP) → static `frontend/assets/favicon.svg` in 5 templates + Containerfile `cp`; SVG element byte-identical to the old data-URI (verified programmatically); serves 200 with all three headers. +- Curl check (server booted like e2e conftest, log: `/tmp/curl_security_headers_final.log`): `/`, `/api/health`, `/assets/styles.css`, `/nope` (404) → all three headers, CSP exactly `default-src 'self'; base-uri 'none'; frame-ancestors 'none'`. +- `uv run pytest tests/unit/test_security_headers.py tests/integration/test_security_headers.py -v --no-cov` → 13 passed (incl. SSE byte-identity pin). +- `uv run pytest tests/e2e/test_security_headers.py -v --no-cov` (isolated) → 2 passed (headers + zero CSP violations + painted page). +- SSE tripwire `uv run pytest tests/e2e/test_chat_rag.py -v --no-cov` → 3 passed. +- `uv run pytest --cov=app --cov-report=term-missing` → 1665 passed, app/ 99% (>90%); `uv run ruff check . && uv run pyright` → clean (0 errors). +- `git diff --stat` limited to phase-82 files + the two documented deviations (favicon set, `tests/unit/__init__.py`); no `pyproject.toml`/`uv.lock`/JS diffs. +- Commit + phase-dir move left to the harness per pipeline rules (not executed by me). + +Next pending phase: `83_chat_save_payload_limits`. diff --git a/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.validate b/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.validate new file mode 100644 index 0000000..8c8b417 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__00_phase.a1.validate @@ -0,0 +1,84 @@ +........................................................................ [ 4%] +........................................................................ [ 8%] +........................................................................ [ 12%] +........................................................................ [ 17%] +........................................................................ [ 21%] +........................................................................ [ 25%] +........................................................................ [ 30%] +........................................................................ [ 34%] +........................................................................ [ 38%] +........................................................................ [ 43%] +........................................................................ [ 47%] +........................................................................ [ 51%] +........................................................................ [ 56%] +........................................................................ [ 60%] +........................................................................ [ 64%] +........................................................................ [ 69%] +........................................................................ [ 73%] +........................................................................ [ 77%] +........................................................................ [ 82%] +........................................................................ [ 86%] +........................................................................ [ 90%] +........................................................................ [ 95%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 178 0 100% +app/api/chats.py 110 0 100% +app/api/config.py 7 0 100% +app/api/doc_drafts.py 93 0 100% +app/api/docs.py 50 0 100% +app/api/git_sources.py 212 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 29 0 100% +app/api/sync.py 101 0 100% +app/api/tokens.py 28 0 100% +app/config.py 141 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 108 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 19 0 100% +app/core/tokens.py 33 0 100% +app/db.py 21 0 100% +app/main.py 64 0 100% +app/models.py 94 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 222 0 100% +app/rag/archive_upload.py 128 0 100% +app/rag/chunker.py 206 4 98% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 180 3 98% +app/rag/llm.py 216 0 100% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 150 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 231 0 100% +-------------------------------------------------- +TOTAL 3232 12 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +validation OK diff --git a/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.err b/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.md b/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.md new file mode 100644 index 0000000..81a9f57 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.md @@ -0,0 +1,18 @@ +Task 01 complete — all gates green. + +**Implemented** +- `app/core/security_headers.py` (new): `CSP` constant (exact A1 string `default-src 'self'; base-uri 'none'; frame-ancestors 'none'`) + `SecurityHeadersMiddleware` — pure-ASGI, wraps `send`, writes CSP / `X-Frame-Options: DENY` / `X-Content-Type-Options: nosniff` on `http.response.start` only, non-http fast path, never touches a body (SSE-safe); module docstring carries the SEC-04 audit basis, No-CDN verification, and pure-ASGI/SSE rationale. +- `tests/unit/test_security_headers.py` (new, 8 tests): A1-string pin; plain 200 with exact header values; 404-shaped (empty header list); SSE `StreamingResponse` byte-identity pin (two frames in order, boundaries intact, headers present); message-level "only start is mutated" pin; http send-wrapped/receive-untouched identity; websocket + lifespan passthrough (original send/receive identity, zero injection). + +**Test / lint / coverage** +- `uv run pytest tests/unit/test_security_headers.py -v --no-cov` → 8 passed +- `uv run pytest --cov=app --cov-report=term-missing` → 1660 passed, TOTAL 99% (>90%); `app/core/security_headers.py` 100% +- `uv run ruff check .` → All checks passed +- `uv run pyright` → 0 errors +- `git status` → only the two new files added (plus pre-existing harness artifacts under `.agents/`, untouched) + +**Notable decisions** +- SSE pin accounts for starlette's own empty trailer frame + `; charset=utf-8` suffix (framework behavior, not the middleware). +- Tests drive raw ASGI via a small `asyncio.run` helper (no pytest-asyncio in the repo; matches `test_caching.py` style) and also use a real `StreamingResponse` for the SSE test. + +**Next pending task:** `02_registration_and_integration.md` (`app/main.py` registration + integration tests on real app responses). diff --git a/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.validate b/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.validate new file mode 100644 index 0000000..3dfba88 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__01_headers_middleware.a1.validate @@ -0,0 +1,84 @@ +........................................................................ [ 4%] +........................................................................ [ 8%] +........................................................................ [ 13%] +........................................................................ [ 17%] +........................................................................ [ 21%] +........................................................................ [ 26%] +........................................................................ [ 30%] +........................................................................ [ 34%] +........................................................................ [ 39%] +........................................................................ [ 43%] +........................................................................ [ 47%] +........................................................................ [ 52%] +........................................................................ [ 56%] +........................................................................ [ 60%] +........................................................................ [ 65%] +........................................................................ [ 69%] +........................................................................ [ 73%] +........................................................................ [ 78%] +........................................................................ [ 82%] +........................................................................ [ 86%] +........................................................................ [ 91%] +........................................................................ [ 95%] +........................................................................ [ 99%] +.... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 178 0 100% +app/api/chats.py 110 0 100% +app/api/config.py 7 0 100% +app/api/doc_drafts.py 93 0 100% +app/api/docs.py 50 0 100% +app/api/git_sources.py 212 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 29 0 100% +app/api/sync.py 101 0 100% +app/api/tokens.py 28 0 100% +app/config.py 141 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 108 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 19 0 100% +app/core/tokens.py 33 0 100% +app/db.py 21 0 100% +app/main.py 62 0 100% +app/models.py 94 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 222 0 100% +app/rag/archive_upload.py 128 0 100% +app/rag/chunker.py 206 4 98% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 180 3 98% +app/rag/llm.py 216 0 100% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 150 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 231 0 100% +-------------------------------------------------- +TOTAL 3230 12 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +validation OK diff --git a/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.err b/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.md b/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.md new file mode 100644 index 0000000..0ed6983 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.md @@ -0,0 +1,19 @@ +All gates green. Final report: + +**Phase 82 · Task 02 — Registration + integration tests (complete)** + +Implemented: +- `app/main.py`: `SecurityHeadersMiddleware` registered immediately after `configure_caching(app)` — outermost on purpose (headers on every response incl. static-catch-all 404s); nothing else reordered. +- `tests/integration/test_security_headers.py` (new, 5 tests, shared `client` fixture — no new fixtures): `GET /`, `/api/health`, `/assets/styles.css`, `/definitely-not-a-page` (404) all carry the three headers with the exact A1 CSP; `?v=` rewrite coexistence pin (caching middleware intact under the header-only middleware). + +Results: +- `uv run pytest tests/integration/test_security_headers.py tests/integration/test_caching_revalidation.py -v` → 10 passed (caching suite green untouched). +- `uv run pytest --cov=app --cov-report=term-missing` → 1665 passed, **99%** coverage (`security_headers.py` 100%). +- `uv run ruff check . && uv run pyright` → clean. +- SSE tripwire: `uv run pytest tests/e2e/test_chat_rag.py -v --no-cov` → 3 passed (stream byte-identical through the new middleware). + +Notable decisions: +- **Defect fixed:** full-suite collection crashed with pytest "import file mismatch" — `test_security_headers.py` now exists in both `tests/unit/` and `tests/integration/` (both paths mandated by the phase). Fix: added `tests/unit/__init__.py` (unit modules import as `unit.*`), mirroring the existing `tests/e2e/__init__.py` precedent; `tests/integration/` deliberately stays a plain dir because 3 files there use sibling imports (`from test_chat_api import …`). One extra new file beyond the task's list — unavoidable given the phase's own "full `uv run pytest` green" gate. +- No `pyproject.toml`/template/JS diffs; no git add/commit (left in working tree for the harness). + +Next pending task: `.agents/phases/todo/82_security_headers/03_e2e_and_commit.md` (dedicated Playwright suite + full gate + atomic commit). diff --git a/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.validate b/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.validate new file mode 100644 index 0000000..8c8b417 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__02_registration_and_integration.a1.validate @@ -0,0 +1,84 @@ +........................................................................ [ 4%] +........................................................................ [ 8%] +........................................................................ [ 12%] +........................................................................ [ 17%] +........................................................................ [ 21%] +........................................................................ [ 25%] +........................................................................ [ 30%] +........................................................................ [ 34%] +........................................................................ [ 38%] +........................................................................ [ 43%] +........................................................................ [ 47%] +........................................................................ [ 51%] +........................................................................ [ 56%] +........................................................................ [ 60%] +........................................................................ [ 64%] +........................................................................ [ 69%] +........................................................................ [ 73%] +........................................................................ [ 77%] +........................................................................ [ 82%] +........................................................................ [ 86%] +........................................................................ [ 90%] +........................................................................ [ 95%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 178 0 100% +app/api/chats.py 110 0 100% +app/api/config.py 7 0 100% +app/api/doc_drafts.py 93 0 100% +app/api/docs.py 50 0 100% +app/api/git_sources.py 212 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 29 0 100% +app/api/sync.py 101 0 100% +app/api/tokens.py 28 0 100% +app/config.py 141 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 108 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 19 0 100% +app/core/tokens.py 33 0 100% +app/db.py 21 0 100% +app/main.py 64 0 100% +app/models.py 94 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 222 0 100% +app/rag/archive_upload.py 128 0 100% +app/rag/chunker.py 206 4 98% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 180 3 98% +app/rag/llm.py 216 0 100% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 150 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 231 0 100% +-------------------------------------------------- +TOTAL 3232 12 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +validation OK diff --git a/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.err b/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.err new file mode 100644 index 0000000..e69de29 diff --git a/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.md b/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.md new file mode 100644 index 0000000..8f8c2cf --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.md @@ -0,0 +1,7 @@ +**Phase 82 · Task 03 — E2E suite + full gate (complete; commit/move left to harness per pipeline rules)** + +- New `tests/e2e/test_security_headers.py` (2 tests, house conftest, no LLM interaction): real `page.goto` of `/` and `/sources.html` → all three headers, CSP exactly the A1 string; console listener (attached pre-nav) asserts zero `/Content Security Policy/i` messages; chat page painted (canvas bg `rgb(15,10,10)` + `#main` booted). +- **Deviations (flagged):** (1) paint check pinned on the `` canvas, not `body` — the phase-08 contract keeps `body` transparent by design, so the task's literal body check could never pass; (2) **audit miss fixed:** all 5 templates' `data:`-URI favicon is blocked by the locked `default-src 'self'` CSP (the mandated zero-violation gate was unmeetable). Fixed by serving `frontend/assets/favicon.svg` (byte-identical artwork) + `href="/assets/favicon.svg"` in the 5 templates + a Containerfile stage-1 `cp` (its asset-coverage pin required). The **locked A1 CSP string stays untouched** — no `img-src data:` weakening. +- Curl check (server on final tree; full output in `/tmp/curl_security_headers.log`): `/`, `/api/health`, `/assets/styles.css`, `/nope` all carry the exact A1 CSP + `DENY` + `nosniff` (incl. 404s); note `HEAD /api/health` → 404 is pre-existing (FastAPI 0.141 doesn't auto-register HEAD; the static catch-all answers it — middleware-proven status-neutral); `GET /api/health` → 200 with all three. +- Results: `uv run pytest tests/e2e/test_security_headers.py -v --no-cov` → 2 passed (isolated); `uv run pytest tests/e2e/test_chat_rag.py -v --no-cov` → 3 passed (SSE byte-identical); `uv run pytest --cov=app` → 1665 passed, **99%** (>90%); `uv run ruff check . && uv run pyright` → clean; template-touching E2E (`test_cache_busting`, `test_asset_cache_revalidation`, `test_dark_tech_theme`) → 15 passed. +- Next pending task: `.agents/phases/todo/83_chat_save_payload_limits` (after the harness commits + moves phase 82). diff --git a/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.validate b/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.validate new file mode 100644 index 0000000..8c8b417 --- /dev/null +++ b/.agents/reports/82_security_headers/82_security_headers__03_e2e_and_commit.a1.validate @@ -0,0 +1,84 @@ +........................................................................ [ 4%] +........................................................................ [ 8%] +........................................................................ [ 12%] +........................................................................ [ 17%] +........................................................................ [ 21%] +........................................................................ [ 25%] +........................................................................ [ 30%] +........................................................................ [ 34%] +........................................................................ [ 38%] +........................................................................ [ 43%] +........................................................................ [ 47%] +........................................................................ [ 51%] +........................................................................ [ 56%] +........................................................................ [ 60%] +........................................................................ [ 64%] +........................................................................ [ 69%] +........................................................................ [ 73%] +........................................................................ [ 77%] +........................................................................ [ 82%] +........................................................................ [ 86%] +........................................................................ [ 90%] +........................................................................ [ 95%] +........................................................................ [ 99%] +......... [100%] +=============================== warnings summary =============================== +.venv/lib/python3.13/site-packages/fastapi/testclient.py:1 + /var/home/ducoterra/Projects/Personal/brain_of_reese/.venv/lib/python3.13/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead. + from starlette.testclient import TestClient as TestClient # noqa + +-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html +================================ tests coverage ================================ +_______________ coverage: platform linux, python 3.13.13-final-0 _______________ + +Name Stmts Miss Cover +-------------------------------------------------- +app/__init__.py 1 0 100% +app/api/__init__.py 0 0 100% +app/api/auth.py 52 0 100% +app/api/chat.py 178 0 100% +app/api/chats.py 110 0 100% +app/api/config.py 7 0 100% +app/api/doc_drafts.py 93 0 100% +app/api/docs.py 50 0 100% +app/api/git_sources.py 212 0 100% +app/api/health.py 10 0 100% +app/api/steering.py 42 0 100% +app/api/suggestions.py 29 0 100% +app/api/sync.py 101 0 100% +app/api/tokens.py 28 0 100% +app/config.py 141 0 100% +app/core/__init__.py 0 0 100% +app/core/auth.py 45 0 100% +app/core/caching.py 108 0 100% +app/core/debugging.py 29 2 93% +app/core/docs_push.py 39 0 100% +app/core/logging.py 13 0 100% +app/core/rate_limit.py 44 0 100% +app/core/security_headers.py 19 0 100% +app/core/tokens.py 33 0 100% +app/db.py 21 0 100% +app/main.py 64 0 100% +app/models.py 94 0 100% +app/rag/__init__.py 0 0 100% +app/rag/agent.py 222 0 100% +app/rag/archive_upload.py 128 0 100% +app/rag/chunker.py 206 4 98% +app/rag/git_sources.py 14 0 100% +app/rag/importer.py 180 3 98% +app/rag/llm.py 216 0 100% +app/rag/overview.py 71 0 100% +app/rag/prompts.py 88 0 100% +app/rag/retriever.py 150 3 98% +app/rag/scaffolding.py 55 0 100% +app/rag/source_removal.py 41 0 100% +app/rag/sources_meta.py 16 0 100% +app/rag/suggestions.py 27 0 100% +app/rag/summarizer.py 24 0 100% +app/schemas.py 231 0 100% +-------------------------------------------------- +TOTAL 3232 12 99% +coverage gate: app/ 99% (>90%) OK +All checks passed! +0 errors, 0 warnings, 0 informations +validation OK diff --git a/Containerfile b/Containerfile index 3754840..337d223 100644 --- a/Containerfile +++ b/Containerfile @@ -25,6 +25,7 @@ RUN mkdir -p /out/assets \ && esbuild ./assets/markdown.js --minify --outfile=/out/assets/markdown.js \ && esbuild ./assets/styles.css --minify --outfile=/out/assets/styles.css \ && cp -r ./assets/themes /out/assets/themes \ + && cp ./assets/favicon.svg /out/assets/favicon.svg \ && cp ./index.html ./document.html ./login.html ./shared.html ./doc-edit.html /out/ # ---------- Stage 2: python dependencies ---------- diff --git a/app/core/security_headers.py b/app/core/security_headers.py new file mode 100644 index 0000000..142f3c5 --- /dev/null +++ b/app/core/security_headers.py @@ -0,0 +1,81 @@ +"""Security headers on every response (phase 82 — security audit SEC-04). + +Audit basis (SEC-04, severity Medium): no response in the app carried +``Content-Security-Policy``, ``X-Frame-Options``, or +``X-Content-Type-Options``. Every page — including the admin sign-in and +the admin-only views — could be embedded in a third-party page's +iframe: a malicious LAN page could overlay the admin UI and trick the +signed-in owner into clicking Sync / Revoke / Delete-source actions +(audit PoC: ``