78 lines
2.5 KiB
Markdown
78 lines
2.5 KiB
Markdown
# Endpoint Monitor API
|
||
|
||
A typed FastAPI service for process-local endpoint monitors and secure, on-demand HTTP checks.
|
||
|
||
## Features
|
||
|
||
- CRUD monitor resources and current-status retrieval
|
||
- bounded HTTP/HTTPS checks with latency measurement
|
||
- SSRF protection on every DNS lookup and redirect hop
|
||
- JSON logs with URL credentials, query strings, and fragments redacted
|
||
- health/readiness endpoints and validated `MONITOR_` environment settings
|
||
- concurrency-safe in-memory state
|
||
|
||
## Layout
|
||
|
||
- `docs/service-contract.md` — API and architecture contract
|
||
- `app/` — settings, models, store, checker, logging, and FastAPI routes
|
||
- `tests/` — API and checker/security tests using mocked outbound HTTP
|
||
- `docs/verification.md` — validation commands and expected evidence
|
||
|
||
## Run locally
|
||
|
||
```bash
|
||
python -m venv .venv && . .venv/bin/activate
|
||
pip install -e '.[dev]'
|
||
uvicorn app.main:app --reload
|
||
```
|
||
|
||
Open `http://127.0.0.1:8000/docs`.
|
||
|
||
## Examples
|
||
|
||
```bash
|
||
curl -sS -X POST http://127.0.0.1:8000/monitors \
|
||
-H 'content-type: application/json' \
|
||
-d '{"name":"example","url":"https://example.com/"}'
|
||
curl -sS http://127.0.0.1:8000/monitors
|
||
curl -sS -X POST http://127.0.0.1:8000/monitors/MONITOR_ID/check
|
||
curl -sS http://127.0.0.1:8000/monitors/MONITOR_ID/status
|
||
curl -sS http://127.0.0.1:8000/healthz
|
||
curl -sS http://127.0.0.1:8000/readyz
|
||
```
|
||
|
||
PUT accepts the same body as POST and replaces the mutable fields. DELETE returns 204. Unknown IDs return the JSON error envelope documented in the service contract.
|
||
|
||
## Configuration
|
||
|
||
All settings are validated at startup.
|
||
|
||
| Variable | Default | Meaning |
|
||
|---|---:|---|
|
||
| `MONITOR_REQUEST_TIMEOUT_SECONDS` | `5.0` | Total check timeout, range 0.1–30 |
|
||
| `MONITOR_MAX_REDIRECTS` | `5` | Manual redirect limit, range 0–10 |
|
||
| `MONITOR_MAX_MONITORS` | `1000` | Process-local monitor capacity |
|
||
| `MONITOR_LOG_LEVEL` | `INFO` | Python log level |
|
||
|
||
Private, loopback, link-local, multicast, reserved, and otherwise non-global resolved addresses are rejected. URL userinfo is rejected. Only HTTP and HTTPS are accepted.
|
||
|
||
## Quality checks
|
||
|
||
```bash
|
||
ruff format --check .
|
||
ruff check .
|
||
mypy app
|
||
pytest -q
|
||
```
|
||
|
||
## Container
|
||
|
||
```bash
|
||
docker build -t endpoint-monitor .
|
||
docker run --rm -p 8000:8000 endpoint-monitor
|
||
# or
|
||
docker compose up --build
|
||
```
|
||
|
||
The container has a non-root user and one worker intentionally. State is process-local and is lost on restart; multiple workers/replicas do not share monitors. Use a durable shared database before horizontal scaling or production persistence is required.
|