From f165b786f7ef99e86c9b2169711802db57ebd2b2 Mon Sep 17 00:00:00 2001 From: demo-bot Date: Sun, 9 Aug 2026 16:01:16 +0000 Subject: [PATCH] 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. --- README.md | 90 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index f966cb2..330445a 100644 --- a/README.md +++ b/README.md @@ -1,71 +1,83 @@ -# Endpoint Monitor Service +# Endpoint Monitor -A typed FastAPI service for process-local monitor CRUD and secure, on-demand HTTP -checks. The full contract and status semantics are in -[`docs/service-contract.md`](docs/service-contract.md). +A typed FastAPI service that stores endpoint monitors in process-local memory and performs secure, on-demand HTTP checks. -## Run locally +## Quick start -```bash +Requires Python 3.12. + +```sh python -m venv .venv . .venv/bin/activate pip install -e '.[dev]' -uvicorn app.main:app --reload +make check +uvicorn app.main:app --reload --workers 1 ``` Create and check a monitor: -```bash -curl -sS -X POST http://localhost:8000/monitors \ +```sh +curl -sS -X POST http://localhost:8000/v1/monitors \ -H 'content-type: application/json' \ - -d '{"name":"example","url":"https://example.com/health?token=secret"}' -curl -sS -X POST http://localhost:8000/monitors/MONITOR_UUID/check -curl -sS http://localhost:8000/monitors/MONITOR_UUID/status -curl -sS http://localhost:8000/health/ready + -d '{"name":"example","url":"https://example.com/health?token=do-not-log"}' +curl -sS -X POST http://localhost:8000/v1/monitors/MONITOR_UUID/checks +curl -sS http://localhost:8000/v1/monitors/MONITOR_UUID/status ``` -OpenAPI is at `/docs`. There is intentionally no authentication. +Interactive OpenAPI documentation is at `/docs`. The full route/status/error contract and SSRF model are in [docs/service-design.md](docs/service-design.md). ## Configuration -All settings are validated at startup and use the `MONITOR_` prefix: +All values are startup-validated and use environment prefix `MONITOR_`: | Variable | Default | Constraint | |---|---:|---| | `MONITOR_APP_NAME` | endpoint-monitor | string | | `MONITOR_LOG_LEVEL` | INFO | logging level | -| `MONITOR_CONNECT_TIMEOUT_SECONDS` | 2 | >0, <=30 | -| `MONITOR_CHECK_TIMEOUT_SECONDS` | 5 | >0, <=60 | -| `MONITOR_MAX_REDIRECTS` | 3 | 0..10 | +| `MONITOR_CHECK_TIMEOUT_SECONDS` | 5 | >0, <=30 | +| `MONITOR_MAX_REDIRECTS` | 5 | 0–10 | +| `MONITOR_MAX_RESPONSE_BYTES` | 1000000 | 1–10000000 | -## Quality checks +Checks resolve every hop and block any hostname with a non-public answer. Redirects are manual and bounded; total elapsed timeout and response size are bounded. Query and fragment data and URL credentials are redacted from structured logs. URL credentials are rejected. Application checks cannot create a perfect DNS-rebinding boundary; use deny-by-default egress networking or a hardened outbound proxy in sensitive deployments. -```bash -ruff format --check . -ruff check . -mypy app -pytest +## Tests and quality + +```sh +make lint # Ruff formatting check and lint +make type # strict mypy +make test # pytest API/unit suite +make check # all three ``` -Outbound HTTP is mocked in tests. Security cases cover private DNS answers, redirects -to loopback, bounded errors, compare-and-set status publication, and query redaction. +Tests are directly inspectable under `tests/`: CRUD/operations and API mapping (`test_api.py`), lock concurrency and stale compare-and-set updates (`test_store.py`), timeouts/statuses/DNS and redirect SSRF/log redaction (`test_checker.py`), and environment validation (`test_config.py`). Outbound requests use `httpx.MockTransport`; tests do not access the network. ## Container -```bash -docker build -t endpoint-monitor . -docker run --rm -p 8000:8000 endpoint-monitor -# or: docker compose up --build +```sh +docker build -t endpoint-monitor:local . +docker run --rm -p 8000:8000 endpoint-monitor:local +# or +docker compose up --build ``` -The image runs as a non-root user and deliberately uses one worker. A restart loses -all monitors. Running multiple workers/replicas creates independent datasets and -inconsistent reads; use a shared durable store before scaling. DNS preflight is not a -replacement for network-level egress controls against rebinding. +The image runs as a non-root user, has a liveness healthcheck, and deliberately starts one Uvicorn worker. -## Project layout +## Layout -- `app/`: API, settings, locked store, checker, SSRF policy, JSON logging -- `tests/`: API, checker, store, configuration, and security tests -- `docs/service-contract.md`: routes, semantics, lifecycle, and threat boundaries -- `VERIFICATION.md`: exact validation commands and execution status +```text +app/ service implementation + checker.py bounded checks, DNS/redirect SSRF policy + config.py validated environment settings + logging.py structured JSON and URL redaction + main.py FastAPI routes and lifecycle + models.py API schemas and status semantics + store.py lock-protected in-memory state and CAS updates +tests/ mocked unit and API tests +docs/service-design.md contract and architecture +docs/verification.md execution record and reproducible commands +Dockerfile, compose.yaml, pyproject.toml, Makefile +``` + +## Important limitations + +All monitors disappear on restart. State is not shared between processes, hosts, or Uvicorn workers, so run exactly one worker. There is no authentication; place the service behind an authenticated gateway if exposed. For durable or horizontally scaled use, replace `MonitorStore` with a transactional shared datastore and coordinate check ownership.