mirror of
https://github.com/zvx-echo6/navi.git
synced 2026-08-26 17:31:37 +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>
This commit is contained in:
parent
15cad0abf4
commit
d644741c75
21 changed files with 716 additions and 87 deletions
29
backend/shared/git_sha.py
Normal file
29
backend/shared/git_sha.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"""Shared git short-SHA helper.
|
||||
|
||||
Used by every navi-* service's create_app() for the `version` field in
|
||||
admin-info, and by navi-admin's fleet.recon_git_sha to read recon's deployed
|
||||
SHA from its clone path. One implementation, one place to fix when behavior
|
||||
needs changing.
|
||||
"""
|
||||
import subprocess
|
||||
|
||||
|
||||
def git_short_sha(repo_path: str | None = None) -> str:
|
||||
"""Return ``git rev-parse --short HEAD`` for the given repo path, or for the
|
||||
current working directory if path is None. Returns 'unknown' on any failure
|
||||
(no git, no repo, permission denied, detached HEAD, etc.) — never raises.
|
||||
|
||||
repo_path: explicit repo to query (uses ``git -C <path>``); None = current
|
||||
cwd (the systemd unit's WorkingDirectory in prod).
|
||||
"""
|
||||
cmd = ['git']
|
||||
if repo_path is not None:
|
||||
cmd.extend(['-C', repo_path])
|
||||
cmd.extend(['rev-parse', '--short', 'HEAD'])
|
||||
try:
|
||||
sha = subprocess.check_output(
|
||||
cmd, stderr=subprocess.DEVNULL, text=True, timeout=3,
|
||||
).strip()
|
||||
return sha or 'unknown'
|
||||
except Exception:
|
||||
return 'unknown'
|
||||
0
backend/shared/tests/__init__.py
Normal file
0
backend/shared/tests/__init__.py
Normal file
14
backend/shared/tests/test_git_sha.py
Normal file
14
backend/shared/tests/test_git_sha.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
"""Hermetic tests for shared.git_sha.git_short_sha."""
|
||||
from shared.git_sha import git_short_sha
|
||||
|
||||
|
||||
def test_git_short_sha_returns_unknown_on_bad_path(tmp_path):
|
||||
# tmp_path is an empty dir, not a git repo → graceful 'unknown', no raise.
|
||||
assert git_short_sha(str(tmp_path)) == 'unknown'
|
||||
|
||||
|
||||
def test_git_short_sha_in_real_repo():
|
||||
# The suite runs from inside the navi-backend repo, so the cwd lookup works.
|
||||
sha = git_short_sha()
|
||||
assert sha != 'unknown'
|
||||
assert len(sha) >= 7 # short SHA, sanity bound
|
||||
Loading…
Add table
Add a link
Reference in a new issue