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:
90
README.md
90
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
|
A typed FastAPI service that stores endpoint monitors in process-local memory and performs secure, on-demand HTTP checks.
|
||||||
checks. The full contract and status semantics are in
|
|
||||||
[`docs/service-contract.md`](docs/service-contract.md).
|
|
||||||
|
|
||||||
## Run locally
|
## Quick start
|
||||||
|
|
||||||
```bash
|
Requires Python 3.12.
|
||||||
|
|
||||||
|
```sh
|
||||||
python -m venv .venv
|
python -m venv .venv
|
||||||
. .venv/bin/activate
|
. .venv/bin/activate
|
||||||
pip install -e '.[dev]'
|
pip install -e '.[dev]'
|
||||||
uvicorn app.main:app --reload
|
make check
|
||||||
|
uvicorn app.main:app --reload --workers 1
|
||||||
```
|
```
|
||||||
|
|
||||||
Create and check a monitor:
|
Create and check a monitor:
|
||||||
|
|
||||||
```bash
|
```sh
|
||||||
curl -sS -X POST http://localhost:8000/monitors \
|
curl -sS -X POST http://localhost:8000/v1/monitors \
|
||||||
-H 'content-type: application/json' \
|
-H 'content-type: application/json' \
|
||||||
-d '{"name":"example","url":"https://example.com/health?token=secret"}'
|
-d '{"name":"example","url":"https://example.com/health?token=do-not-log"}'
|
||||||
curl -sS -X POST http://localhost:8000/monitors/MONITOR_UUID/check
|
curl -sS -X POST http://localhost:8000/v1/monitors/MONITOR_UUID/checks
|
||||||
curl -sS http://localhost:8000/monitors/MONITOR_UUID/status
|
curl -sS http://localhost:8000/v1/monitors/MONITOR_UUID/status
|
||||||
curl -sS http://localhost:8000/health/ready
|
|
||||||
```
|
```
|
||||||
|
|
||||||
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
|
## 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 |
|
| Variable | Default | Constraint |
|
||||||
|---|---:|---|
|
|---|---:|---|
|
||||||
| `MONITOR_APP_NAME` | endpoint-monitor | string |
|
| `MONITOR_APP_NAME` | endpoint-monitor | string |
|
||||||
| `MONITOR_LOG_LEVEL` | INFO | logging level |
|
| `MONITOR_LOG_LEVEL` | INFO | logging level |
|
||||||
| `MONITOR_CONNECT_TIMEOUT_SECONDS` | 2 | >0, <=30 |
|
| `MONITOR_CHECK_TIMEOUT_SECONDS` | 5 | >0, <=30 |
|
||||||
| `MONITOR_CHECK_TIMEOUT_SECONDS` | 5 | >0, <=60 |
|
| `MONITOR_MAX_REDIRECTS` | 5 | 0–10 |
|
||||||
| `MONITOR_MAX_REDIRECTS` | 3 | 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
|
## Tests and quality
|
||||||
ruff format --check .
|
|
||||||
ruff check .
|
```sh
|
||||||
mypy app
|
make lint # Ruff formatting check and lint
|
||||||
pytest
|
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
|
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.
|
||||||
to loopback, bounded errors, compare-and-set status publication, and query redaction.
|
|
||||||
|
|
||||||
## Container
|
## Container
|
||||||
|
|
||||||
```bash
|
```sh
|
||||||
docker build -t endpoint-monitor .
|
docker build -t endpoint-monitor:local .
|
||||||
docker run --rm -p 8000:8000 endpoint-monitor
|
docker run --rm -p 8000:8000 endpoint-monitor:local
|
||||||
# or: docker compose up --build
|
# or
|
||||||
|
docker compose up --build
|
||||||
```
|
```
|
||||||
|
|
||||||
The image runs as a non-root user and deliberately uses one worker. A restart loses
|
The image runs as a non-root user, has a liveness healthcheck, and deliberately starts one Uvicorn worker.
|
||||||
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.
|
|
||||||
|
|
||||||
## Project layout
|
## Layout
|
||||||
|
|
||||||
- `app/`: API, settings, locked store, checker, SSRF policy, JSON logging
|
```text
|
||||||
- `tests/`: API, checker, store, configuration, and security tests
|
app/ service implementation
|
||||||
- `docs/service-contract.md`: routes, semantics, lifecycle, and threat boundaries
|
checker.py bounded checks, DNS/redirect SSRF policy
|
||||||
- `VERIFICATION.md`: exact validation commands and execution status
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user