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 failed
ci / test (push) Has been cancelled
Some checks failed
ci / test (push) Has been cancelled
This commit is contained in:
@@ -1,52 +1,56 @@
|
||||
# Service contract and architecture
|
||||
# Endpoint Monitor service contract
|
||||
|
||||
## Resource and lifecycle
|
||||
## Resources and lifecycle
|
||||
|
||||
A monitor has a server-generated UUID, name, absolute HTTP(S) URL, expected HTTP status,
|
||||
timestamps, and a current status. State is process-local memory guarded by one `asyncio.Lock`;
|
||||
it starts empty on every process start, is not shared across workers, and is lost on restart.
|
||||
Run exactly one worker unless an external store is added. Returned models are frozen so state
|
||||
cannot be mutated outside the store lock.
|
||||
A monitor has an immutable UUID, `name`, HTTP(S) `url`, timestamps, and a current
|
||||
check snapshot. New and URL-updated monitors are `unknown`. State is process-local
|
||||
memory, protected by one async lock, and is lost on restart. Multiple workers do not
|
||||
share state. No authentication is provided; deploy behind an authenticated gateway.
|
||||
|
||||
## HTTP contract
|
||||
## HTTP API
|
||||
|
||||
| Method | Path | Success | Purpose |
|
||||
|---|---|---:|---|
|
||||
| POST | `/monitors` | 201 | Create |
|
||||
| GET | `/monitors` | 200 | List |
|
||||
| GET | `/monitors/{uuid}` | 200 | Retrieve |
|
||||
| PATCH | `/monitors/{uuid}` | 200 | Partial update |
|
||||
| DELETE | `/monitors/{uuid}` | 204 | Delete |
|
||||
| POST | `/monitors/{uuid}/check` | 200 | Run and atomically persist a check |
|
||||
| GET | `/monitors/{uuid}/status` | 200 | Retrieve current status |
|
||||
| GET | `/health/live` | 200 | Process liveness |
|
||||
| GET | `/health/ready` | 200 | In-memory service readiness |
|
||||
| Method and path | Success | Notes |
|
||||
|---|---:|---|
|
||||
| `POST /monitors` | 201 | Create; duplicate names are allowed |
|
||||
| `GET /monitors` | 200 | Stable creation-order list |
|
||||
| `GET /monitors/{id}` | 200 | Retrieve |
|
||||
| `PUT /monitors/{id}` | 200 | Full update |
|
||||
| `DELETE /monitors/{id}` | 204 | Delete |
|
||||
| `POST /monitors/{id}/check` | 200 | Run one bounded check and atomically publish it |
|
||||
| `GET /monitors/{id}/status` | 200 | Current snapshot; no network call |
|
||||
| `GET /health/live` | 200 | Process is serving HTTP |
|
||||
| `GET /health/ready` | 200 | Configuration and in-memory store are available |
|
||||
|
||||
Missing resources return `{"error":{"code":"not_found","message":"monitor not found"}}`
|
||||
with 404. Invalid UUIDs or bodies return a generic, input-redacting `invalid_request` with 422.
|
||||
There is intentionally no authentication.
|
||||
Missing monitor IDs return `404 {"detail":"monitor not found"}`. Validation failures
|
||||
use FastAPI's 422 response. A check transport failure is a successful invocation and
|
||||
returns a snapshot with `error`; an unsafe target returns `blocked`. These are not API
|
||||
5xx responses because the service completed the requested check.
|
||||
|
||||
Status meanings: `never_checked` has no observation; `up` exactly matches `expected_status`;
|
||||
`down` is a completed nonmatching HTTP response; `error` is timeout/protocol/network failure;
|
||||
`blocked` means outbound policy rejected the destination. Check failures are check results (200),
|
||||
not API transport failures. A monitor deleted while its check runs yields 404 rather than being
|
||||
recreated.
|
||||
## Status semantics
|
||||
|
||||
## Outbound security and logging
|
||||
`unknown` means never checked or URL changed. `up` means final status 200-399 after
|
||||
safe redirects. `down` means final status 400-599. `error` means timeout, DNS failure,
|
||||
or HTTP transport failure. `blocked` means SSRF policy rejected a host/address or
|
||||
redirect. Snapshots contain completion time, latency in milliseconds, optional HTTP
|
||||
status, and a bounded non-sensitive error code.
|
||||
|
||||
Only HTTP(S), credential-free URLs are accepted by the checker. Every initial and redirected
|
||||
hop is resolved immediately before request; all returned addresses must be globally routable.
|
||||
Redirects are handled manually and bounded, requests have bounded timeouts, bodies are streamed,
|
||||
and exceptions map to stable non-sensitive messages. This blocks direct, DNS, and redirect
|
||||
attempts to loopback/private/link-local/reserved addresses. Like most application-level DNS
|
||||
checks, there remains a small resolver-to-connect rebinding race; production high-assurance
|
||||
deployments should additionally enforce an egress proxy/firewall.
|
||||
## Check security and consistency
|
||||
|
||||
Structured JSON check logs include IDs, status, latency, and scheme/host/port/path only. Query,
|
||||
fragment, credentials, response bodies, and raw exception text are excluded.
|
||||
Only HTTP(S), no URL credentials, and a non-empty hostname are accepted. Every hop is
|
||||
resolved before I/O; every resolved address must be globally routable. Redirects are
|
||||
followed manually and revalidated, with a configured maximum. Timeouts and redirect
|
||||
counts are bounded. The store uses a revision compare-and-set so a result from an old
|
||||
URL cannot overwrite a concurrent update. This DNS preflight mitigates ordinary SSRF;
|
||||
deployments requiring protection from DNS rebinding should also enforce egress policy
|
||||
at the network layer.
|
||||
|
||||
Logs are JSON and include monitor ID, outcome, latency, and a URL with credentials,
|
||||
query, and fragment removed. Raw exception text and redirect locations are never
|
||||
logged.
|
||||
|
||||
## Layout
|
||||
|
||||
`app/api.py` owns HTTP semantics, `models.py` schemas, `store.py` locked state, `checker.py` check
|
||||
orchestration, `security.py` outbound policy, and `config.py` environment settings. Tests isolate
|
||||
outbound traffic with `httpx.MockTransport`.
|
||||
`app/` contains settings, models, locked store, SSRF validation, checker, logging, and
|
||||
FastAPI composition. `tests/` contains API/unit security tests. Packaging is in
|
||||
`pyproject.toml`, `Dockerfile`, and `compose.yaml`; operational evidence is in
|
||||
`VERIFICATION.md`.
|
||||
|
||||
Reference in New Issue
Block a user