mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-09-03 03:51:35 +00:00
* Add navi-admin service (extraction #7) Net-new fleet admin aggregator on :8427 — no port from recon (recon has no /api/admin route; Phase A §3). Three @require_auth routes: GET /api/admin/fleet fan-out to all 6 navi-* /api/admin/<svc>/info + recon /api/health, merged; never 5xx (failures land in errors[]) GET /api/admin/recon/info recon /api/health wrapped in the info shape GET /api/admin/navi-admin/info self-describe Fan-out forwards the caller's X-Authentik-Username so the @require_auth upstreams accept it; per-service admin endpoints stay localhost-only (this is the single edge-exposed admin surface). Service discovery: hardcoded list in fleet.py (Option B). No secrets, no DB. Deploy artifacts (NOT applied here): navi-admin.env.example, systemd unit, nginx ^~ /api/admin snippet, and deploy/caddy notes for the @authed_api edit (first Caddy change since #2). 12 hermetic tests (fleet happy-path, per-service timeout/500 → errors[], auth-header forwarding, recon-down degraded-not-5xx, self-info no-secrets, auth-required). Full monorepo suite green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * PR #7 review fixes 1. Symmetric degraded-entry handling in fleet.build_fleet — every probed service now appears in `services` with a uniform degraded dict on failure (matches recon's existing pattern), AND in errors[]. Operators see "everything I tried + which broke" consistently. 2. Catch ValueError specifically in _get_json — non-JSON 200 responses now surface as `error: 'invalid JSON'` instead of opaque 'ValueError'. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * PR #7 review fixes (round 2) 1. Unified degraded shape: wrap_recon_health calls _degraded_entry on failure — no more runtime.status vs runtime.recon_status asymmetry. Every probed service has the same shape on failure (runtime.status == 'unreachable'). recon-specific runtime fields (recon_status/recon_uptime/pipeline) remain only on the success path. 2. DRY'd git short-SHA helper into shared/git_sha.py — was duplicated in 7 service app.py files + fleet.recon_git_sha. One implementation, one place to fix when behavior changes. Adds shared/tests (testpaths now includes "shared"). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: zvx-echo6 <mj@k7zvx.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
54 lines
2.1 KiB
Markdown
54 lines
2.1 KiB
Markdown
# navi-admin — Caddy edit notes (deploy task, NOT done in the PR)
|
|
|
|
navi-admin's `/api/admin/*` is **auth-gated** (every admin-info is `@require_auth`).
|
|
Today the `navi.echo6.co` Caddy block on **CT 101** (`192.168.1.241 → pct 101`,
|
|
`/etc/caddy/Caddyfile`) routes `/api/admin/*` through `@public_api` (path `/api/*`)
|
|
with **no auth** → it would serve the fleet/admin endpoints unauthenticated.
|
|
|
|
So the deploy task must add `/api/admin/*` to the `@authed_api` matcher. **This is
|
|
the first Caddy edit since extraction #2** (Phase A §6/§8).
|
|
|
|
## The edit
|
|
|
|
Inside the `navi.echo6.co { ... }` block, the `@authed_api` matcher:
|
|
|
|
**Before**
|
|
```caddyfile
|
|
@authed_api {
|
|
path /api/contacts /api/contacts/* /api/auth/whoami /api/traffic /api/traffic/*
|
|
}
|
|
```
|
|
|
|
**After** (append `/api/admin/*`)
|
|
```caddyfile
|
|
@authed_api {
|
|
path /api/contacts /api/contacts/* /api/auth/whoami /api/traffic /api/traffic/* /api/admin/*
|
|
}
|
|
```
|
|
|
|
No other change. `@authed_api` already runs `forward_auth https://auth.echo6.co`
|
|
then `reverse_proxy 100.64.0.24:8440`; adding the path makes `/api/admin/*` take
|
|
that authed path instead of falling through to `@public_api`. Because Caddy
|
|
evaluates the `handle` blocks in source order and `@authed_api` is defined before
|
|
`@public_api`, the new path wins for `/api/admin/*` while `/api/*` still catches
|
|
everything else publicly.
|
|
|
|
## Apply (on CT 101)
|
|
|
|
```bash
|
|
ssh root@192.168.1.241 "pct exec 101 -- caddy validate --config /etc/caddy/Caddyfile"
|
|
ssh root@192.168.1.241 "pct exec 101 -- systemctl reload caddy" # acme/admin off → reload is fine here
|
|
```
|
|
|
|
## Why this is the only Caddy entry needed
|
|
|
|
The per-service `/api/admin/<svc>/info` endpoints stay **localhost-only** — they
|
|
are never edge-routed (nginx has no per-service admin block; navi-admin reaches
|
|
them over `127.0.0.1`). Only navi-admin's single `/api/admin` front door is
|
|
edge-exposed, so only this one path needs adding to `@authed_api`.
|
|
|
|
## nginx side (VM 1130)
|
|
|
|
Pair this with the `^~ /api/admin → 127.0.0.1:8427` block in
|
|
`deploy/nginx/navi-admin.conf.snippet`, added before the `location /api/`
|
|
catch-all in `/etc/nginx/sites-available/navi.echo6.co`.
|