2.8 KiB
Endpoint Monitor Service Contract
Architecture
A single FastAPI process exposes typed REST routes, delegates process-local state to an asyncio.Lock protected store, and delegates outbound checks to a checker that validates and pins DNS results independently on every redirect hop. The production fetcher uses aiohttp with a per-hop pinned resolver, normal TLS hostname verification, proxy/environment settings disabled, manual redirects, and a total bounded timeout.
This service intentionally has no authentication. It must therefore only be exposed where that is acceptable. State is volatile, is not shared between workers, and disappears on restart; run exactly one worker.
Resource and routes
A monitor has UUID id, name, HTTP(S) url, creation/update timestamps, integer revision, and nullable current_status. Status is unknown, up, or down; a check records HTTP status (if any), elapsed milliseconds, check time, and a stable error category/message (if any).
POST /monitors-> 201GET /monitors-> 200GET /monitors/{id}-> 200 or 404PUT /monitors/{id}-> 200 or 404; status is reset when URL changesDELETE /monitors/{id}-> 204 or 404POST /monitors/{id}/check-> 200 or 404. Network and policy failures are completed checks represented asdown, not transport errors from this API.GET /monitors/{id}/status-> 200 or 404GET /health-> livenessGET /ready-> readiness and explicit process-local storage mode
Validation errors use FastAPI's 422 response. Application errors have {"detail":{"code":...,"message":...}}. A check updates status atomically only if the monitor still exists at the same revision; its response says whether it was applied, preventing stale in-flight checks from overwriting an edit.
Security and logging
Only HTTP and HTTPS are accepted. Userinfo is forbidden. Before each request and redirect, every DNS answer is classified with ipaddress; any non-global, private, loopback, link-local, multicast, reserved, or unspecified answer rejects the hop. Literal IPs follow the same rule. The validated addresses are pinned into that hop's connector, preventing a second resolver lookup/DNS rebinding. Redirects are manual and bounded. Total, connect, and read timeouts are bounded. Environment proxies are disabled.
Logs are one-line JSON. URLs are sanitized to scheme/host/port/path; query, fragment, and userinfo never enter structured fields. Error strings are normalized and never include exception text that could echo a secret-bearing URL.
Project layout
app/ contains configuration, models, locked storage, SSRF policy, outbound checker, logging, and API assembly. tests/ exercises API/store/checker policy with fake outbound I/O. pyproject.toml, Docker assets, and README provide developer and runtime workflows.