# Read-only sensitive HTTP/API pattern audit

Use for source-only audits that identify safe reuse points before adding read-only APIs to a local or sensitive dashboard. The goal is an evidence-backed integration boundary, not implementation.

## Scope discipline

1. Capture initial Git status/HEAD and classify source, tests, deployment metadata, and suspicious data/credential filenames before opening files.
2. Do not open production databases, reports, exports, logs, environment files, documents, or secrets. Read only source, tests, docs, schemas, and deployment templates that cannot contain live values.
3. Prefer existing synthetic fixtures and temporary port-0 servers for verification. Disable bytecode/test caches and compare final status, HEAD, index/worktree shape, and changed-file content against the initial capture. If concurrent work only re-stages identical content, report the index transition rather than falsely claiming byte-identical Git status; if file content changed during review, re-read/retest the final tree or withhold approval.
4. Report exact `file:line` anchors, distinguish implemented controls from planned documentation, and do not infer authentication from loopback binding, Host validation, CSRF, or `SameSite` cookies.

## Mechanical trace order

Trace each concern from server primitive → route dispatch → provider/contract → tests → deployment:

1. **Authentication:** locate the actual identity gate. CSRF is request-integrity protection, not authentication. If absent, mark it as a blocking gap before any sensitive GET API is exposed. Secrets must come from runtime configuration, never query strings, bundles, fixtures, or committed files.
2. **Host and same-origin:** require Host validation before routing/authentication. For browser requests, reject a supplied mismatching Origin and cross-site Fetch Metadata; do not require Origin unconditionally for GET because direct navigation/clients may omit it. Keep CORS closed unless explicitly required. Treat hard-coded `http` origin comparison as valid only for a direct HTTP-loopback deployment; proxies/HTTPS need an explicit trusted external-origin model.
3. **CSP:** inspect the page that will call the API. `connect-src 'none'` blocks same-origin fetch; use a route/profile-specific `connect-src 'self'` only for API-enabled HTML and retain the stricter policy elsewhere. Preserve local-only assets and test for zero external requests.
4. **Cache/privacy headers and total error boundary:** confirm `Cache-Control: no-store` on success, redirects, authentication failures, validation errors, and server errors. Framework/default `send_error` paths often bypass the normal secure response helper. Keep response serialization and byte-budget enforcement inside the controlled exception boundary too: a provider can return a non-JSON-serializable object even when dispatch itself did not raise, and the server must still return a generic no-store JSON 500 rather than disconnecting with a traceback.
5. **Query parsing:** do not copy a permissive convenience query parser. Use strict parsing with a field-count cap, exact allowed key sets, exactly one value per scalar, bounded text, ISO dates, enum/identifier allowlists, maximum range, and rejection of unknown/duplicate/blank values.
6. **Response limits:** identify existing contract ceilings, then enforce endpoint-specific row/time/byte limits. Apply bounds in SQL/cursor iteration, not after loading an entire table. Validate serialized bytes before sending.
7. **Route/path/identity allowlists:** prefer exact route tables; permit dynamic segments only through a full regex plus semantic validation. Never map client-controlled table, column, filename, or filesystem paths. Reuse proven `resolve()`/containment/symlink checks only for explicitly approved file routes. Treat IDs and drill-down targets as part of the trust boundary: an ID emitted from an explicit API DB must never be resolved by a legacy document route against another DB. Remove the cross-route identifier, namespace it, or bind the authenticated route to the same explicit provider.
8. **Provider safety:** verify SQLite is opened with an explicit required DB target and `mode=ro`; avoid production-path fallbacks. Trace missingness, future-date exclusion, deterministic ordering/aggregation, provenance, canonical identifiers, and arbitrary free-text handling at the response boundary.
9. **Search and redaction:** use registry-driven result adapters and fixed result types. Return stable IDs, canonical labels, dates, and safe navigation targets. Generic bounded-text/path regexes are insufficient for arbitrary database snippets; exclude raw document text, filenames, local paths, URLs, source labels, and unrestricted notes unless a separate redaction/allowlist contract proves them safe. Test embedded absolute paths outside the developer's usual roots (`/var/...`, `/mnt/...`), traversal-like relative paths (`../../...`), Windows drive/UNC paths, and URL forms. Prefer allowlisted metadata grammars over an ever-growing denylist when practical.
10. **Synthetic tests:** set environment before importing modules with import-time configuration; build a caller-provided fail-no-replace temporary DB with a synthetic marker; start the real handler on port 0; assert an explicit synthetic response sentinel before browser/API probes. Use two distinct synthetic DBs plus colliding IDs to prove API identifiers cannot cross into legacy document routes.
11. **Unknown HTTP methods:** test arbitrary method tokens through the real parser, not only methods with explicit `do_*` handlers. Host validation must still run first. Exercise both origin-form (`/api/v1/...`) and absolute-form (`http://host/api/v1/...`) request targets over a raw socket; normalize the parsed path before API classification so both receive controlled no-store JSON rather than framework HTML errors.

## Minimal integration architecture

Keep the change split into four narrow layers:

- `request_gate`: Host → method → authentication → supplied Origin/Fetch Metadata → route.
- `parse_api_query`: endpoint schema, exact keys/single values, range and count limits.
- endpoint adapters: registry/allowlist-driven bounded read-only SQL, no whole-bundle fallback for targeted queries.
- `send_json`: deterministic JSON plus `no-store`, `nosniff`, fixed content type, HEAD semantics, byte budget, and generic safe errors for every status.

For an API-enabled HTML route, make CSP selection explicit rather than weakening one global policy. Require an explicit read-only database configuration in deployment metadata. Keep write actions on the existing separately validated queue/worker boundary.

## Endpoint reuse checklist

- **Catalog:** canonical metric registry/public metadata only; optional search filters this registry, not DB columns.
- **Series:** metric ID from registry, bounded `from/to`, allowed resolution, SQL-level date predicate/limit, validated point contract.
- **Day:** exact ISO path segment and targeted one-day queries; do not build/filter the complete historical bundle.
- **Events:** fixed event-type enum, bounded interval, deterministic order, planned/administered/cancelled semantics kept distinct.
- **Labs:** canonical parameter/unit pairs, exact numeric grammar, original-verification/provenance gates, date bound and early limit.
- **Search:** grouped adapters over approved domains with a small total/per-group cap and no unrestricted snippets.

## High-value negative tests

- missing/wrong credentials; valid credentials; hostile Host rejected before auth;
- mismatching scheme/host/port Origin and cross-site Fetch Metadata;
- unsupported methods and non-allowlisted/dynamic routes;
- unknown, duplicate, blank, malformed, overlong, or excessive query fields;
- non-allowlisted IDs/types/resolutions, reversed/oversized ranges, future dates;
- row and serialized-byte overflow;
- `no-store` and security headers on every 2xx/3xx/4xx/5xx API path;
- HEAD returns matching status/headers and no body;
- missing stays missing, explicit numeric zero stays observed;
- responses contain no filesystem paths, filenames, URLs, raw document text, or unrestricted source labels;
- synthetic sentinel, temporary DB, read-only connection, and unchanged Git status before/after.

## Reporting shape

Lead with blocking findings by severity, then provide a reuse matrix (`concern → file:line → reusable as-is/adapt/do-not-reuse`), endpoint mapping, minimal architecture, missing tests, executed synthetic evidence, and final unchanged-tree confirmation. Separate observed facts from recommendations.