From 2962d33a3bab0787c5e42eb3ebdf2b5338a88c1a Mon Sep 17 00:00:00 2001 From: Apple Date: Tue, 3 Mar 2026 06:55:49 -0800 Subject: [PATCH] feat(sofiia-console): add artifacts list endpoint + team onboarding doc - runbook_artifacts.py: adds list_run_artifacts() returning files with names, paths, sizes, mtime_utc from release_artifacts// - runbook_runs_router.py: adds GET /api/runbooks/runs/{run_id}/artifacts - docs/runbook/team-onboarding-console.md: one-page team onboarding doc covering access, rehearsal run steps, audit auth model (strict, no localhost bypass), artifacts location, abort procedure Made-with: Cursor --- docs/runbook/team-onboarding-console.md | 187 ++++++++++++++++++ .../sofiia-console/app/runbook_artifacts.py | 25 +++ .../sofiia-console/app/runbook_runs_router.py | 9 + 3 files changed, 221 insertions(+) create mode 100644 docs/runbook/team-onboarding-console.md diff --git a/docs/runbook/team-onboarding-console.md b/docs/runbook/team-onboarding-console.md new file mode 100644 index 00000000..708fea1f --- /dev/null +++ b/docs/runbook/team-onboarding-console.md @@ -0,0 +1,187 @@ +# Team Onboarding: Sofiia Console + Runbook Runner (v1) + +Документ для нових членів команди. Один раз прочитати, далі — практика. + +--- + +## 1. Доступ до Console + +**URL:** https://console.daarion.space + +### Отримання ключа + +1. Запитати у адміністратора персональний ключ. +2. Адміністратор генерує: `python3 -c "import secrets; print(secrets.token_urlsafe(32))"` +3. Ключ додається до `SOFIIA_CONSOLE_TEAM_KEYS` на NODA1 (`name:key` формат). +4. Перезапуск контейнера не потрібен при зміні env — тільки `docker compose up -d`. + +### Логін + +1. Відкрити https://console.daarion.space +2. Ввести свій ключ у форму Login +3. Cookie встановлюється автоматично на 7 днів +4. Перевірити: `GET /api/auth/check` → `{"ok": true, "identity": "user:"}` + +### Revocation + +Якщо ключ скомпрометований — повідомити адміністратора. Він видаляє `name:key` з env та перезапускає контейнер. + +--- + +## 2. Запуск Rehearsal / Release Run + +### Крок 1 — Створити run + +```bash +POST /api/runbooks/runs +{ + "runbook_path": "runbook/rehearsal-v1-30min-checklist.md", + "operator_id": "your_name", + "node_id": "NODA1", + "sofiia_url": "http://localhost:8002" +} +``` + +Отримаєш `run_id`. Зберегти його. + +### Крок 2 — Auto steps (натискати `Next`) + +```bash +POST /api/runbooks/runs/{run_id}/next +``` + +Автоматично виконуються: + +| # | Крок | Тип | +|---|------|-----| +| 0 | Health check `/api/health` → 200 | http_check | +| 1 | Metrics `/metrics` → 200 | http_check | +| 2 | Audit auth `/api/audit` → 401 | http_check | +| 3 | Preflight script (STRICT=1) | script | +| 4 | Redis idempotency smoke | script | +| 5 | Generate evidence script | script | + +### Крок 3 — Manual steps + +Runner зупиниться і поверне `{"type": "manual", "instructions_md": "..."}`. + +Виконати дію (наприклад, restart), потім: + +```bash +POST /api/runbooks/runs/{run_id}/steps/{step_index}/complete +{ + "status": "ok", + "notes": "restart completed", + "operator_id": "your_name" +} +``` + +**Observation Window step** — внести метрики в `data`: + +```json +{ + "status": "ok", + "notes": "observation 15 min", + "data": { + "5xx_total": 0, + "replays_delta": 0, + "rate_limited_chat_delta": 0, + "send_latency_p95_ms": null + } +} +``` + +### Крок 4 — Артефакти + +```bash +POST /api/runbooks/runs/{run_id}/evidence +POST /api/runbooks/runs/{run_id}/post_review +``` + +Де знаходяться файли: + +```bash +GET /api/runbooks/runs/{run_id}/artifacts +# → {"files": [{"name": "release_evidence.md", "path": "...", "bytes": 2048}, ...]} +``` + +Або напряму на NODA1: `${SOFIIA_DATA_DIR}/release_artifacts//` + +--- + +## 3. Audit trail + +**Хто може читати audit:** + +| Роль | `/api/audit` | +|------|-------------| +| `operator` (головний ключ) | ✅ | +| `user:` (team key) | ✅ | +| localhost без ключа | ❌ (strict auth) | +| без ключа взагалі | ❌ | + +> Audit endpoint **не має** localhost bypass. Потрібен ключ завжди. + +**Читання audit trail:** + +```bash +curl -H "X-API-Key: $YOUR_KEY" \ + "https://console.daarion.space/api/audit?limit=20" +``` + +--- + +## 4. Якщо щось ламається + +**Перевірити стан run:** +```bash +GET /api/runbooks/runs/{run_id} +# → status, current_step, кожен крок зі статусом +``` + +**Подивитись деталі кроку** — у полі `result`: +- `exit_code` — для script кроків +- `stderr_tail` — лог помилки +- `timeout: true` — якщо перевищено timeout +- `ok: false` — крок не пройшов + +**Abort run:** +```bash +POST /api/runbooks/runs/{run_id}/abort +{"operator_id": "your_name"} +``` + +--- + +## 5. Коли запускати Rehearsal + +Обов'язково перед: +- релізом sofiia-console +- підключенням нової ноди +- значними змінами в конфігурації агентів +- масштабуванням (нові ноди в кластері) + +--- + +## 6. Корисні команди (quick ref) + +```bash +# Список останніх runs (через API) +GET /api/runbooks/runs # якщо є list endpoint + +# Health console +GET /api/health + +# Метрики +GET /metrics + +# Версія +GET /api/meta/version + +# Auth check +GET /api/auth/check +``` + +--- + +_Версія документа: v1 · console.daarion.space · Sofiia Console `e0bea910`_ diff --git a/services/sofiia-console/app/runbook_artifacts.py b/services/sofiia-console/app/runbook_artifacts.py index ba31c7f6..1c463732 100644 --- a/services/sofiia-console/app/runbook_artifacts.py +++ b/services/sofiia-console/app/runbook_artifacts.py @@ -361,6 +361,31 @@ async def render_release_evidence(run_id: str) -> Dict[str, Any]: } +async def list_run_artifacts(run_id: str) -> Dict[str, Any]: + """ + List files in release_artifacts// with sizes and mtimes. + Returns {run_id, dir, files: [{name, path, bytes, mtime_utc}]}. + """ + out_dir = _artifacts_dir(run_id) + files = [] + if out_dir.exists(): + for f in sorted(out_dir.iterdir()): + if f.is_file(): + stat = f.stat() + files.append({ + "name": f.name, + "path": str(f), + "bytes": stat.st_size, + "mtime_utc": _iso_utc(stat.st_mtime), + }) + return { + "run_id": run_id, + "dir": str(out_dir), + "exists": out_dir.exists(), + "files": files, + } + + async def render_post_review(run_id: str) -> Dict[str, Any]: """ Generate post-release review markdown from run DB data. diff --git a/services/sofiia-console/app/runbook_runs_router.py b/services/sofiia-console/app/runbook_runs_router.py index fca19554..cf111521 100644 --- a/services/sofiia-console/app/runbook_runs_router.py +++ b/services/sofiia-console/app/runbook_runs_router.py @@ -82,6 +82,15 @@ async def complete_step( return {"ok": True, "run_id": run_id, "step_index": step_index, "next_step": step_index + 1} +@runbook_runs_router.get("/{run_id}/artifacts") +async def list_artifacts( + run_id: str, + _auth: str = Depends(require_auth), +): + """List generated artifacts for a run (paths, sizes, mtimes).""" + return await artifacts.list_run_artifacts(run_id) + + @runbook_runs_router.post("/{run_id}/evidence") async def generate_evidence( run_id: str,