ci: lock generated OpenAPI contract
This commit is contained in:
@@ -41,6 +41,8 @@ jobs:
|
|||||||
alembic current
|
alembic current
|
||||||
- name: Run Python tests
|
- name: Run Python tests
|
||||||
run: pytest -q
|
run: pytest -q
|
||||||
|
- name: Verify generated OpenAPI contract
|
||||||
|
run: python apps/api/export_openapi.py --check
|
||||||
|
|
||||||
astro-build:
|
astro-build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ Production release отделяет Alembic от runtime: одноразовый
|
|||||||
|
|
||||||
Тяжёлый production bootstrap вынесен в отдельный ручной/еженедельный CI workflow с 30-минутным timeout и сохраняемыми diagnostics; обычный push по-прежнему использует быстрый Compose E2E.
|
Тяжёлый production bootstrap вынесен в отдельный ручной/еженедельный CI workflow с 30-минутным timeout и сохраняемыми diagnostics; обычный push по-прежнему использует быстрый Compose E2E.
|
||||||
|
|
||||||
|
Публичный API зафиксирован генерируемым [OpenAPI-контрактом](docs/api-contract.md): CI сравнивает `apps/api/openapi.json` с фактической схемой FastAPI, поэтому рефакторинг routers не может незаметно изменить URL, параметры или response models.
|
||||||
|
|
||||||
После повторных ошибок scheduler увеличивает паузу экспоненциально до 24 часов и возвращается к 30 минутам после успеха. Публичная страница `/status` показывает свежесть и состояние источников без URL запросов, внутренних ошибок и другой диагностической информации.
|
После повторных ошибок scheduler увеличивает паузу экспоненциально до 24 часов и возвращается к 30 минутам после успеха. Публичная страница `/status` показывает свежесть и состояние источников без URL запросов, внутренних ошибок и другой диагностической информации.
|
||||||
|
|
||||||
Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md).
|
Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md). Результаты проверки интерфейса и пять приоритетных UX-пакетов описаны в [`docs/UI_UX_AUDIT.md`](docs/UI_UX_AUDIT.md).
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
|
||||||
|
TARGET = Path(__file__).with_name("openapi.json")
|
||||||
|
|
||||||
|
|
||||||
|
def rendered_contract() -> str:
|
||||||
|
return json.dumps(app.openapi(), ensure_ascii=False, indent=2, sort_keys=True) + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Generate or verify the RF4 Spotter OpenAPI contract")
|
||||||
|
parser.add_argument("--check", action="store_true")
|
||||||
|
args = parser.parse_args()
|
||||||
|
rendered = rendered_contract()
|
||||||
|
if args.check:
|
||||||
|
if not TARGET.exists() or TARGET.read_text(encoding="utf-8") != rendered:
|
||||||
|
parser.exit(1, "OpenAPI contract is stale; run apps/api/export_openapi.py\n")
|
||||||
|
print(f"OpenAPI contract is current: {len(app.openapi()['paths'])} paths")
|
||||||
|
return 0
|
||||||
|
TARGET.write_text(rendered, encoding="utf-8")
|
||||||
|
print(f"Wrote {TARGET}: {len(app.openapi()['paths'])} paths")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -56,7 +56,7 @@
|
|||||||
- [x] **Q13 · Production bootstrap в CI.** Отдельный workflow запускает `deploy/test-production-bootstrap.sh` вручную или раз в неделю, а не на каждом push. Вывод bootstrap всегда сохраняется 14 дней; при падении добавляются Compose status и Playwright diagnostics.
|
- [x] **Q13 · Production bootstrap в CI.** Отдельный workflow запускает `deploy/test-production-bootstrap.sh` вручную или раз в неделю, а не на каждом push. Вывод bootstrap всегда сохраняется 14 дней; при падении добавляются Compose status и Playwright diagnostics.
|
||||||
- [ ] **Q14 · Полная CSP.** Расширить текущую CSP (`frame-ancestors`, `base-uri`, `object-src`) до `default-src`, `script-src`, `style-src`, `img-src`, `connect-src` и `form-action`. Сначала инвентаризировать inline scripts/styles Astro, затем внедрить nonce/hash или безопасное вынесение; проверить report/admin/OG без ослабления до произвольных внешних origin.
|
- [ ] **Q14 · Полная CSP.** Расширить текущую CSP (`frame-ancestors`, `base-uri`, `object-src`) до `default-src`, `script-src`, `style-src`, `img-src`, `connect-src` и `form-action`. Сначала инвентаризировать inline scripts/styles Astro, затем внедрить nonce/hash или безопасное вынесение; проверить report/admin/OG без ослабления до произвольных внешних origin.
|
||||||
- [ ] **Q15 · Частичная деградация главной.** Разделить получение activity, community signals и справочников так, чтобы отказ одного источника не превращал всю главную в общий 503. Для SSR не добавлять искусственный client-side loading/optimistic UI; показывать независимые `StatePanel` и корректный HTTP/cache статус.
|
- [ ] **Q15 · Частичная деградация главной.** Разделить получение activity, community signals и справочников так, чтобы отказ одного источника не превращал всю главную в общий 503. Для SSR не добавлять искусственный client-side loading/optimistic UI; показывать независимые `StatePanel` и корректный HTTP/cache статус.
|
||||||
- [ ] **Q16 · Контракт OpenAPI.** Генерировать OpenAPI artifact из приложения в CI и проверять осознанные изменения контракта при декомпозиции API; не поддерживать вручную редактируемую копию.
|
- [x] **Q16 · Контракт OpenAPI.** `apps/api/openapi.json` детерминированно генерируется из FastAPI; CI проверяет его актуальность после backend suite. Изменение artifact обязательно рассматривается вместе с реализацией, а ручное редактирование не используется.
|
||||||
- [ ] **Q17 · Эксплуатационные документы.** Добавить короткие ADR по Astro/FastAPI/PostgreSQL, локальному cache и стратегии scheduler, а также incident runbook для заполнения диска/PostgreSQL, отказа MinIO, зависших импортов, ошибок миграции и компрометации секретов.
|
- [ ] **Q17 · Эксплуатационные документы.** Добавить короткие ADR по Astro/FastAPI/PostgreSQL, локальному cache и стратегии scheduler, а также incident runbook для заполнения диска/PostgreSQL, отказа MinIO, зависших импортов, ошибок миграции и компрометации секретов.
|
||||||
- [ ] **Q18 · Минимальная observability.** До открытой альфы определить дешёвые метрики request count/latency/error rate, глубины moderation/staging и возраста последнего успешного импорта. Формат и exporter выбрать после выбора мониторинга сервера; полноценный tracing не внедрять без подтверждённой потребности.
|
- [ ] **Q18 · Минимальная observability.** До открытой альфы определить дешёвые метрики request count/latency/error rate, глубины moderation/staging и возраста последнего успешного импорта. Формат и exporter выбрать после выбора мониторинга сервера; полноценный tracing не внедрять без подтверждённой потребности.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Контракт API
|
||||||
|
|
||||||
|
`apps/api/openapi.json` — автоматически сгенерированный снимок фактического FastAPI-контракта. Он фиксирует пути, методы, параметры, response schemas и security metadata перед декомпозицией routers. Файл нельзя править вручную.
|
||||||
|
|
||||||
|
После осознанного изменения API:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
.venv/bin/python apps/api/export_openapi.py
|
||||||
|
git diff -- apps/api/openapi.json
|
||||||
|
.venv/bin/python apps/api/export_openapi.py --check
|
||||||
|
```
|
||||||
|
|
||||||
|
CI выполняет режим `--check` после тестов и падает, если код и committed artifact расходятся. Изменение снимка должно находиться в том же коммите, что реализация и тесты нового контракта. Перестановка routers без изменения публичного поведения не должна менять artifact.
|
||||||
Reference in New Issue
Block a user