# release_check — Release Gate **Єдиний оркестрований job для перевірки готовності до релізу** Нода: NODE2 (dev) + NODA1 (production) --- ## Що це? `release_check` — internal task у Job Orchestrator, який послідовно запускає всі release gates і повертає єдиний структурований verdict `pass/fail`. Замінює ручне запускання кожного gate окремо. --- ## Gates (послідовно) | # | Gate | Tool | Умова блокування | |---|------|------|-----------------| | 1 | **PR Review** | `pr_reviewer_tool` (mode=`blocking_only`) | blocking_count > 0 | | 2 | **Config Lint** | `config_linter_tool` (strict=true) | blocking_count > 0 | | 3 | **Contract Diff** | `contract_tool` (fail_on_breaking=true) | breaking_count > 0 | | 4 | **Threat Model** | `threatmodel_tool` (risk_profile) | unmitigated_high > 0 | | 5 | **Smoke** *(optional)* | `job_orchestrator_tool` → `smoke_gateway` | job fail | | 6 | **Drift** *(optional)* | `job_orchestrator_tool` → `drift_check_node1` | job fail | Gates 1–4 завжди виконуються (якщо є вхідні дані). Gates 5–6 виконуються тільки при `run_smoke=true` / `run_drift=true`. --- ## Як запустити ### Через job_orchestrator_tool (рекомендовано) ```json { "action": "start_task", "agent_id": "sofiia", "params": { "task_id": "release_check", "inputs": { "service_name": "router", "diff_text": "", "openapi_base": "", "openapi_head": "", "risk_profile": "agentic_tools", "fail_fast": false, "run_smoke": true, "run_drift": false } } } ``` ### Через Sofiia (OpenCode/Telegram) ``` "Запусти release_check для сервісу router з цим diff: ..." "Зроби release gate перевірку" ``` ### Dry run (тільки валідація) ```json { "action": "start_task", "params": { "task_id": "release_check", "dry_run": true, "inputs": {"service_name": "router"} } } ``` --- ## Вхідні параметри (inputs_schema) | Параметр | Тип | Обов'язковий | Опис | |----------|-----|:---:|------| | `service_name` | string | ✅ | Назва сервісу | | `diff_text` | string | — | Unified diff (git diff) | | `openapi_base` | string | — | OpenAPI base spec (text) | | `openapi_head` | string | — | OpenAPI head spec (text) | | `risk_profile` | enum | — | `default` / `agentic_tools` / `public_api` (default: `default`) | | `fail_fast` | boolean | — | Зупинитись на першому fail (default: `false`) | | `run_smoke` | boolean | — | Запустити smoke tests (default: `false`) | | `run_drift` | boolean | — | Запустити drift check (default: `false`) | --- ## Вихідний формат ```json { "pass": true, "gates": [ { "name": "pr_review", "status": "pass", "blocking_count": 0, "summary": "No blocking issues found", "score": 95 }, { "name": "config_lint", "status": "pass", "blocking_count": 0, "total_findings": 2 }, { "name": "contract_diff", "status": "skipped", "reason": "openapi_base or openapi_head not provided" }, { "name": "threat_model", "status": "pass", "unmitigated_high": 0, "risk_profile": "default" } ], "recommendations": [], "summary": "✅ RELEASE CHECK PASSED in 1234ms. Gates: ['pr_review', 'config_lint', 'threat_model'].", "elapsed_ms": 1234.5 } ``` ### Gate statuses | Status | Значення | |--------|----------| | `pass` | Gate пройшов | | `fail` | Gate не пройшов (блокує реліз) | | `skipped` | Вхідних даних не було (не блокує) | | `error` | Внутрішня помилка gate | --- ## Інтерпретація результату ### `pass: true` Всі mandatory gates пройшли → **можна випускати реліз**. ### `pass: false` Хоча б один gate має `status: fail` → **реліз заблоковано**. Дивись `gates[].status == "fail"` та `recommendations` для деталей. ### `status: error` Gate не зміг виконатись (internal error). Не є `fail`, але потребує уваги. --- ## Risk Profiles для Threat Model | Профіль | Коли використовувати | |---------|---------------------| | `default` | Звичайний внутрішній сервіс | | `agentic_tools` | Сервіс з tool-викликами, prompt injection ризики | | `public_api` | Публічний API (rate limiting, WAF, auth hardening) | --- ## Необхідні Entitlements Для запуску `release_check` агент повинен мати: - `tools.pr_review.gate` - `tools.contract.gate` - `tools.config_lint.gate` - `tools.threatmodel.gate` Тільки агенти з роллю `agent_cto` (sofiia, yaromir) мають ці entitlements. --- ## Приклади сценаріїв ### Швидка перевірка PR (без openapi, без smoke) ```json { "service_name": "gateway-bot", "diff_text": "...", "fail_fast": true } ``` ### Повний release pipeline для публічного API ```json { "service_name": "router", "diff_text": "...", "openapi_base": "...", "openapi_head": "...", "risk_profile": "public_api", "run_smoke": true, "run_drift": true } ``` ### Тільки threat model (без diff) ```json { "service_name": "auth-service", "risk_profile": "agentic_tools" } ``` --- ## Внутрішня архітектура ``` job_orchestrator_tool.start_task("release_check") → _job_orchestrator_tool() виявляє runner="internal" → release_check_runner.run_release_check(tool_manager, inputs, agent_id) → Gate 1: _run_pr_review() → Gate 2: _run_config_lint() → Gate 3: _run_dependency_scan() → Gate 4: _run_contract_diff() → Gate 5: _run_threat_model() → [Gate 6: _run_smoke()] → [Gate 7: _run_drift()] → Gate 8: _run_followup_watch() (policy: off/warn/strict) → Gate 9: _run_privacy_watch() (policy: off/warn/strict) → Gate 10: _run_cost_watch() (always warn) → _build_report() → ToolResult(success=True, result=report) ``` Кожен gate викликає відповідний tool через `tool_manager.execute_tool()`. Governance middleware (RBAC, limits, audit) застосовується до кожного gate-виклику. --- ## Файли | Файл | Призначення | |------|-------------| | `ops/task_registry.yml` | Реєстрація `release_check` task | | `services/router/release_check_runner.py` | Internal runner (gates logic) | | `config/release_gate_policy.yml` | Gate strictness profiles (dev/staging/prod) | | `config/slo_policy.yml` | SLO thresholds per service | | `tests/test_tool_governance.py` | Тести (включно з release_check fixtures) | | `tests/test_release_check_followup_watch.py` | Follow-up watch gate tests |