Drill-down endpoint exposing detailed findings per project. Resolves the
HTTP gap for the Vercel admin dashboard, which cannot SSH/Tailscale to
the VPS, plus a future portable /analyse-vulnerabilite skill.
- Project -> agent lookup via /data/defenseurs/agents-map.json (Sergent snapshot)
- findLatestReportForAgent scans REPORTS_DIR + REPORTS_DIR/archive (post-07:30 UTC rotation)
- Filters: category exact match, severity threshold inclusive upward
- Asymmetric severity rule: default hides LOW+INFO; ?severity=LOW returns
LOW+MEDIUM+HIGH+CRITICAL but still hides INFO; INFO opt-in via explicit param
- Distinguishes "report present + scan clean" (no status field) from
"no report at all" ({findings:[], status:"no_data"})
- Bootstraps vitest (devDep; runtime stays 0-dep), 14 tests covering auth,
validation, filters, asymmetry, mtime selection, error paths
- Refactor: export handler so tests can spin up ephemeral servers; server.listen
guarded by require.main === module
Closes #3
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
64 lines
2.3 KiB
Markdown
64 lines
2.3 KiB
Markdown
# vps-health-api
|
|
|
|
Lightweight health monitoring API for the VPS. Node 22, HTTP-native, zero runtime deps.
|
|
|
|
## Endpoints
|
|
|
|
All endpoints require `Authorization: Bearer $HEALTH_TOKEN`.
|
|
|
|
| Method | Path | Description |
|
|
|--------|------|-------------|
|
|
| GET | `/health` | CPU, memory, disk, uptime, Logto reachability |
|
|
| GET | `/defenseurs` | Defenseurs executive status (status.json) |
|
|
| GET | `/defenseurs/findings?project=X` | Detailed findings for a project's Defenseur |
|
|
| GET | `/reports/scans?date=YYYY-MM-DD` | Aggregated scan reports for a UTC date |
|
|
|
|
### `GET /defenseurs/findings`
|
|
|
|
Query params:
|
|
|
|
- `project` (required) — project name, looked up in `agents-map.json` (e.g. `la-suite-booking`)
|
|
- `category` (optional) — exact match, one of `deps|secrets|code|acces|infra`
|
|
- `severity` (optional) — threshold, one of `CRITICAL|HIGH|MEDIUM|LOW|INFO`
|
|
- default (no param): `MEDIUM`, `HIGH`, `CRITICAL`
|
|
- `LOW` returns `LOW`+`MEDIUM`+`HIGH`+`CRITICAL` but still hides `INFO`
|
|
- `INFO` returns `INFO` only (explicit opt-in)
|
|
|
|
Responses:
|
|
|
|
- `200 { agent, project, timestamp, findings: Finding[] }` — report present (empty `findings` if clean scan; no `status` field)
|
|
- `200 { findings: [], status: "no_data" }` — no report on file for the agent
|
|
- `400` — missing `project` or invalid `category` / `severity`
|
|
- `401` — missing or invalid token
|
|
- `404` — unknown project
|
|
- `500` — `agents-map.json` unreadable or corrupted
|
|
|
|
Example:
|
|
|
|
```
|
|
curl -H "Authorization: Bearer $HEALTH_TOKEN" \
|
|
"https://health.lacompagniemaximus.com/defenseurs/findings?project=la-suite-booking&severity=HIGH"
|
|
```
|
|
|
|
## Config
|
|
|
|
| Env var | Default | Purpose |
|
|
|---------|---------|---------|
|
|
| `PORT` | `3001` | HTTP port |
|
|
| `HEALTH_TOKEN` | — | Bearer token (fail-closed if missing) |
|
|
| `REPORTS_DIR` | `/data/defenseurs/reports` | Scan reports dir |
|
|
| `DEFENSEURS_AGENTS_MAP_PATH` | `/data/defenseurs/agents-map.json` | Project -> agent snapshot |
|
|
| `LOGTO_HEALTH_URL` | auth.lacompagniemaximus.com | Logto OIDC discovery URL |
|
|
|
|
## Bind-mounts (Coolify, read-only)
|
|
|
|
- `/home/defenseur/defenseurs/status.json` -> `/data/defenseurs/status.json`
|
|
- `/home/defenseur/defenseurs/reports/` -> `/data/defenseurs/reports/`
|
|
- `/home/defenseur/defenseurs/agents-map.json` -> `/data/defenseurs/agents-map.json`
|
|
|
|
## Tests
|
|
|
|
```
|
|
npm install
|
|
npm test
|
|
```
|