CI-GATE.0-2: establish repository CI canary

This commit is contained in:
2026-08-04 19:01:59 +03:00
parent 64a5bdd04c
commit 49cc0e2fb8
9 changed files with 1637 additions and 15 deletions

View File

@@ -1,6 +1,6 @@
# Структура проекта Dzentra
**Статус:** Current; Build 060.30.3
**Статус:** Current; CI-GATE.0CI-GATE.2
Документ показывает назначение верхних уровней текущего checkout. Это
навигационная карта, а не полный перечень файлов.
@@ -9,6 +9,7 @@
```text
dzentra_bot/
├── .gitea/workflows/ ручной CI canary contract
├── app/ Python-приложение, зависимости и тесты
├── docs/ архитектура, runbook, roadmap и история Builds
├── infra/ Dockerfile и Docker Compose
@@ -38,6 +39,7 @@ dzentra_bot/
| `requirements.txt` | Прямые Production dependencies |
| `requirements.lock` | Полный hash-locked набор Production image |
| `requirements-dev.txt` | Production dependencies плюс pytest и Pyright |
| `requirements-dev.lock` | Полный hash-locked developer/CI environment |
Диагностические `app/scripts` и `app/tools` не запускаются автоматически
вместе с Production Runtime.

193
docs/operations/ci_gate.md Normal file
View File

@@ -0,0 +1,193 @@
# CI gate Dzentra
**Статус:** Repository implementation complete; Canary Pending
**Область:** CI-GATE.0CI-GATE.2
**Дата фактической проверки Gitea:** 2026-08-04
---
## 1. Что означает CI gate
CI gate — автоматический барьер качества между изменением кода и его
принятием в `main`. Он не доказывает отсутствие любых ошибок, но не даёт
считать изменение готовым, пока обязательные воспроизводимые проверки не
завершились успешно.
Первый gate Dzentra вводится безопасно, в два шага:
1. repository-side contract фиксируется и проверяется локально;
2. после отдельного разрешения он публикуется и вручную запускается на
реальном Gitea runner как canary.
До зелёного canary workflow не запускается автоматически и не участвует в
branch protection.
## 2. Состав CI-GATE.0CI-GATE.2
| Этап | Смысл | Текущий статус |
|---|---|---|
| CI-GATE.0 | Проверить готовность Gitea/runner и зафиксировать ручной canary contract | Repository часть готова; runner и серверный запуск не подтверждены |
| CI-GATE.1 | Создать единый hash-locked набор developer/CI dependencies | Реализовано локально |
| CI-GATE.2 | Добавить три независимые обязательные проверки без внешних сервисов | Реализовано локально; Canary Pending |
Зелёный canary означает реальный успешный запуск всех трёх jobs, а не
только корректный локальный YAML или зелёные локальные тесты.
## 3. Фактическое состояние CI-GATE.0
Read-only проверка публичного сервера подтвердила:
- репозиторий находится на Gitea 1.25.5;
- вкладка Actions доступна;
- до добавления этого contract сервер показывал «Пока нет рабочих
процессов»;
- версия, регистрация и labels `act_runner` без административного доступа
не видны и поэтому не считаются подтверждёнными.
На данном этапе не изменялись настройки Gitea, Actions, runner registration
или branch protection.
Workflow использует объявленный repository contract label
`dzentra-python312`. Runner с этим label должен предоставлять изолированную
Linux-среду со следующими компонентами:
- Python 3.12, `venv` и `pip`;
- Bash, Git и CA certificates;
- Node.js 20 для `actions/checkout` v4;
- GNU `timeout`;
- возможность слушать временный socket только на `127.0.0.1`;
- отсутствие privileged mode и подключённого Docker socket.
До отдельного подтверждения нельзя регистрировать runner или подбирать его
label «на глаз». Если runner отсутствует, jobs останутся в очереди — это
ожидаемый незакрытый инфраструктурный пункт, а не зелёный результат.
## 4. Hash-locked developer/CI environment
Читаемый источник прямых зависимостей остаётся в
[`app/requirements-dev.txt`](../../app/requirements-dev.txt). Установка для
разработки и CI выполняется только из
[`app/requirements-dev.lock`](../../app/requirements-dev.lock):
```bash
python3.12 -m venv app/.venv
app/.venv/bin/python -m pip install \
--require-hashes \
-r app/requirements-dev.lock
app/.venv/bin/python -m pip check
```
Developer lock сохраняет все версии Production lock и добавляет только
инструменты разработки с их транзитивными зависимостями. Это предотвращает
ситуацию, когда CI тестирует приложение на более новых Production-библиотеках,
чем Production image.
Регенерация выполняется намеренно из корня репозитория:
```bash
uv pip compile app/requirements-dev.txt \
--constraints app/requirements.lock \
--generate-hashes \
--universal \
--python-version 3.12 \
--no-header \
--no-annotate \
--output-file app/requirements-dev.lock
```
После генерации в начале файла сохраняются только три служебные строки на
русском языке. Любое изменение lock-файла рассматривается как dependency
update и требует отдельного diff review.
## 5. Контракт CI-GATE.2
Workflow находится в
[`ci-required.yml`](../../.gitea/workflows/ci-required.yml) и пока имеет
только `workflow_dispatch`. Его стабильные jobs:
| Job | Проверяет | Не использует |
|---|---|---|
| `quality` | `pip check`, Pyright, documentation gate, static tests, `compileall`, whitespace | сеть приложения, PostgreSQL, Docker |
| `offline-regression` | полную default pytest-регрессию | integration, stress, live |
| `loopback-integration` | локальные WebSocket/reconnect/recovery scenarios | внешние endpoints и PostgreSQL |
Все потенциально долгие shell-команды ограничены GNU `timeout`. Это
обязательно, потому что Gitea 1.25.5 игнорирует GitHub-совместимое поле
`timeout-minutes`. По той же причине workflow не использует вводящие в
заблуждение `permissions`, `concurrency`, `continue-on-error` и
`timeout-minutes`.
Сам шаг checkout выполняется action, а не shell-командой, поэтому этим
timeout не ограничен. Перед canary необходимо отдельно подтвердить
системный job timeout и cleanup policy `act_runner`.
Checkout закреплён полным commit SHA официального
[`actions/checkout` v4.3.1](https://github.com/actions/checkout/releases/tag/v4.3.1),
а `persist-credentials` выключен. До появления внутреннего mirror runner
должен иметь исходящий HTTPS-доступ к GitHub только для загрузки этого
закреплённого action. Изменение SHA требует отдельного review.
Workflow не получает application secrets, не печатает environment, не
запускает PostgreSQL, Docker, stress/soak или live Dzengi checks.
## 6. Локальный эквивалент
Один entrypoint используется человеком и workflow:
```bash
./scripts/run_ci_gate.sh quality
./scripts/run_ci_gate.sh offline-regression
./scripts/run_ci_gate.sh loopback-integration
```
Для последовательного локального запуска всех трёх режимов:
```bash
./scripts/run_ci_gate.sh all
```
Локальная проверка не требует чистого `git status`, поэтому она не мешает
разработчику с незавершёнными изменениями. Внутри чистого canary checkout
каждая job дополнительно проверяет, что тесты не создали новых файлов
репозитория.
## 7. Первый canary
Первый реальный запуск выполняется только после отдельного подтверждения:
1. провести read-only review repository diff;
2. отдельно согласовать commit и push workflow;
3. с административным доступом подтвердить фактическую версию
`act_runner`, включённость Actions и отсутствие неизвестных runners;
4. зарегистрировать изолированный runner с точным label
`dzentra-python312` и зафиксировать его image/version;
5. вручную запустить `CI Required` для принятого commit;
6. убедиться, что `quality`, `offline-regression` и
`loopback-integration` завершились успешно, не были skipped и не
остались queued;
7. проверить логи на отсутствие secrets и записать реальные status
contexts, показанные Gitea.
Только после этого canary считается зелёным. Автоматические triggers и
branch protection согласуются отдельным решением уже по фактическим status
contexts; заранее угадывать их имена нельзя.
## 8. Критерий перехода к Build 061.00
Build 061.00.0 можно начинать после одновременного выполнения условий:
- локальная матрица CI-GATE.0CI-GATE.2 зелёная;
- реальный manual canary в Gitea зелёный;
- версия и изоляция runner зафиксированы;
- пользователь отдельно подтвердил переход к production-коду.
Пока серверный canary не выполнен, корректный статус — `Canary Pending`.
## 9. Связанные источники
- [Gitea Actions quick start](https://docs.gitea.com/1.25/usage/actions/quickstart/)
- [Отличия Gitea Actions от GitHub Actions](https://docs.gitea.com/1.25/usage/actions/comparison/)
- [Gitea act_runner](https://docs.gitea.com/1.25/usage/actions/act-runner/)
- [Protected branches](https://docs.gitea.com/1.25/usage/access-control/protected-branches/)

View File

@@ -1,6 +1,6 @@
# Trade Stream Production Runtime — эксплуатационное руководство
**Статус:** Current; accepted in Build 060.30.2
**Статус:** Current; accepted in Build 060.30.2, CI-GATE.1 update
**Область:** Trades Feed, persistent Market Data Storage и связанные проверки
@@ -83,15 +83,18 @@ bootstrap, healthcheck, image и Compose path.
```bash
python3.12 -m venv app/.venv
app/.venv/bin/python -m pip install --upgrade pip
app/.venv/bin/python -m pip install -r app/requirements-dev.txt
app/.venv/bin/python -m pip install \
--require-hashes \
-r app/requirements-dev.lock
app/.venv/bin/python -m pip check
```
`app/requirements.txt` остаётся читаемым списком прямых production
dependencies. Production image устанавливает полный транзитивный
`app/requirements.lock` только с `pip --require-hashes`.
`requirements-dev.txt` включает прямые production requirements и
инструменты pytest/Pyright для developer environment.
инструменты pytest/Pyright для developer environment, а установка
выполняется из полного `requirements-dev.lock` с обязательными hashes.
Lock регенерируется намеренно и review-ится как dependency update:
@@ -103,10 +106,21 @@ uv pip compile app/requirements.txt \
--no-header \
--no-annotate \
--output-file app/requirements.lock
uv pip compile app/requirements-dev.txt \
--constraints app/requirements.lock \
--generate-hashes \
--universal \
--python-version 3.12 \
--no-header \
--no-annotate \
--output-file app/requirements-dev.lock
```
После генерации сохраняются только три русскоязычные служебные строки в
начале файла; dependency records и hashes остаются машинными данными.
После генерации каждого lock сохраняются только три русскоязычные
служебные строки в начале файла; dependency records и hashes остаются
машинными данными. Полный CI/canary contract приведён в
[отдельном runbook](ci_gate.md).
Нельзя вручную убирать hash или обновлять только транзитивную version без
повторных build, smoke, `pip check` и regression.