decomposer: generate deliverable files for Define the service contract and project architecture for the FastAPI endpoint monitoring service.; Implement the typed monitor CRUD API and concurrency-safe in-memory state according to the service design.; Implement secure on-demand endpoint checks with status updates, latency measurement, robust error handling, and redacted structured logs.; Add operational API endpoints and environment-driven runtime configuration to the monitoring service.; Create automated tests for the monitoring service.; Package the service with Docker and developer documentation.; Validate the complete project.
Some checks are pending
ci / validate (push) Has started running
Some checks are pending
ci / validate (push) Has started running
This commit is contained in:
33
SPEC.md
Normal file
33
SPEC.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# 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` -> 201
|
||||||
|
* `GET /monitors` -> 200
|
||||||
|
* `GET /monitors/{id}` -> 200 or 404
|
||||||
|
* `PUT /monitors/{id}` -> 200 or 404; status is reset when URL changes
|
||||||
|
* `DELETE /monitors/{id}` -> 204 or 404
|
||||||
|
* `POST /monitors/{id}/check` -> 200 or 404. Network and policy failures are completed checks represented as `down`, not transport errors from this API.
|
||||||
|
* `GET /monitors/{id}/status` -> 200 or 404
|
||||||
|
* `GET /health` -> liveness
|
||||||
|
* `GET /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.
|
||||||
Reference in New Issue
Block a user