Эта политика помогает быстро принимать небольшие изменения и добавляет
проверки там, где ошибка затрагивает пользователей, данные или границы
безопасности. Класс риска выбирает глубину проверки; он не позволяет снять
обязательную проверку, одобрение или защиту `main`.
## Порядок работы
1. До реализации укажи в PR `LOW`, `MEDIUM` или `HIGH` и коротко объясни
причину. Если изменение пересекает несколько областей, выбери самый высокий
класс. При неопределённости используй более высокий класс.
2. Сначала проследи путь изменения от пользовательского/API входа до данных,
внешних систем и отката. Для изменения поведения добавь регрессионный тест,
который подтверждает конкретный контракт или прежний дефект.
3. Запусти проверку именно затронутого поведения и обычный Gitea CI. Для UI
дополнительно выполни `cd tools/frontend-visual-review && npm ci && npm test`;
этот браузерный набор сейчас не входит в Gitea CI.
4. В PR перечисли класс риска, команды и результаты, остаточные ограничения,
а для high-risk — совместимость, угрозы и безопасный rollback. Не заявляй
проверку, которой фактически не было.
5. Ревьюер отделяет блокирующие дефекты от улучшений. Блокер должен указывать
конкретное место, условие воспроизведения и последствие. Стилистические
предпочтения и предложения на будущее фиксируются отдельно и не задерживают
PR.
## Классы риска
| Класс | Когда применять | Требуемое подтверждение |
|---|---|---|
| `LOW` | Документация, комментарии, переименование без изменения поведения, форматирование без изменения конфигурационной семантики. Нет изменения контракта, доступа, данных или исполнения. | Проверить diff и сверить утверждения/команды с исходным кодом и действующей процедурой. Выполнить обычный CI. Если документация меняет операторский шаг, проверить его в безопасном локальном или synthetic окружении. |
| `MEDIUM` | Ограниченное изменение поведения одного компонента, внутреннего API, UI или локального скрипта без изменения модели доверия и формата хранимых данных. | Целевые тесты затронутого компонента и регрессионная проверка, если меняется поведение; обычный CI. Для UI приложить результаты браузерного набора и synthetic визуальной проверки, если они относятся к изменённому экрану/потоку. Проверить обратную совместимость публичных запросов и ответов. |
| `HIGH` | Авторизация и роли; secrets и credential flow; ingestion и происхождение данных; формат/миграция хранилища; backup/restore/recovery; production config; runner, CI и supply chain; безопасность; сетевые/host-границы; deploy и rollback. | Обычный CI плюс целевые проверки каждого затронутого trust/data boundary; regression-тест; проверка негативного пути и совместимости; независимое ревью конкретных угроз и последствий. Для операций с данными использовать synthetic/staging данные и план отката. Изменение production допускается только владельцем после отдельного согласования, проверки backup и готового rollback. |
Нельзя понижать класс из-за малого diff, срочности или простоты реализации:
маленькое изменение правила доступа или восстановления всё равно `HIGH`.
Нельзя считать отсутствие найденных тестов доказательством отсутствия риска.
## CI и ограничения Gitea
Проверенная конфигурация проекта:
- Репозиторий `admin/akyldash`, Gitea API вернул `1.25.5` 2026-10-24.
- Workflow `.gitea/workflows/ci.yaml` запускается на `pull_request` и `push` в
`main`; job ID, который следует сохранять для совместимости статусов, —
`tests-and-images`.
Он последовательно выполняет backend, Telegram, backup/restore, shell guards,
deployment tests, Compose/Caddy validation и две production image builds.
-`.gitea/workflows/runner-smoke.yaml` сохраняет отдельный job ID `runner-smoke`
и проверяет runtime-изоляцию job-контейнера: отсутствие системного и
rootless Docker socket, production env/secrets и host checkout. Smoke дополняет
статические проверки runner/CI и не дублирует их.
- Инфраструктурная конфигурация репозитория закрепляет официальный
3 GiB RAM, 512 процессов, 15 GiB store. Версия runner и лимиты приведены по
IaC; в рамках этой задачи VPS не проверялся. Job-контейнеры не должны получать
ни один Docker socket.
- Текущая политика `main` из branch API: ветка защищена и требует одного
одобрения. На момент проверки API также сообщил `enable_status_check=false`
и пустой список status contexts. Это PR не меняет branch protection.
Если владелец отдельно включит обязательные статусы, сначала проверьте их
точные контексты: `CI / tests-and-images (pull_request)` и
`Runner smoke test / runner-smoke (pull_request)`. Не переименовывайте job IDs.
Функции и границы текущих проверок:
| Блок workflow | Назначение и риск пропуска | Перекрытие |
|---|---|---|
| Checkout и Python setup | Подготовка повторяемой среды; пропуск может дать ложный успех на неподходящем образе. | Инфраструктурный шаг, не покрывается тестами приложения. |
| Backend и Telegram tests | Регрессии API, логики поиска/аккаунтов и Telegram bot. Риск продуктовый; для auth/data изменений — `HIGH`. | Разные пакеты и контракты; отдельная ветка тестов. |
| Backup/restore tests | Целостность backup, восстановление и отказные сценарии; риск потери данных — `HIGH`. | Не дублируется тестами backend. |
| Bootstrap/recovery/verifier/host-audit/production-config guards | Отказ от root и защиты host identity, аргументов и production paths; обход может дать административное действие или затронуть host — `HIGH`. | Несколько guard-тестов проверяют разные скрипты и условия; считать их дублями без анализа каждого контракта нельзя. |
| Runner config, installer guards и CI container isolation | Ограничения runner, repeatability установки и запрет socket/privileged/host mounts; риск — доступ к host/production — `HIGH`. | Статические/синтетические проверки дополняются реальным runtime smoke, это разные уровни. |
| Shell syntax и Python AST parse | Раннее обнаружение ошибок парсинга; риск пропуска — поломка запуска скрипта/проверки. | Это синтаксис, а не функциональные тесты. |
| Deployment contract/rollback tests, Compose config и Caddy validation | Совместимость deploy contract/rollback и конфигурации production stack/proxy; риск — deploy outage/data impact — `HIGH`. | Compose проверяет интерпретацию конфигурации, Caddy — синтаксис proxy, Python suite — contract/rollback logic. Функции отличаются. |
| Две Kaniko image builds | Проверка Dockerfile и воспроизводимости backend/OpenSearch production images; риск — сломанная сборка/небезопасный путь supply chain — `HIGH`. | Два Dockerfile — две разные целевые images; build-only, оба `--no-push`. |
| Runner smoke (отдельный workflow) | Runtime-проверка известного системного socket path, production paths/secrets и host checkout отсутствия в job; риск — нарушение изоляции — `HIGH`. | Дополняет статические runner/CI guards; не повторяет их. |
Gitea API не предоставляет пригодный список steps для завершённого run в этой
версии; длительность каждой строки таблицы поэтому `N/A`. Не распределяй общий
CI runtime между блоками пропорционально числу тестов или строк кода.
Gitea 1.25 документация подтверждает используемые события `push`,
`pull_request` и `workflow_dispatch`. Она также документирует ограничения,
которые запрещают строить безопасное ускорение на привычных GitHub Actions
предположениях:
-`runs-on` поддерживает статическую метку или список меток; текущая
`akyldash-ci` — статическая метка.
- Выражения доступны ограниченно; в сравнении с GitHub Actions Gitea 1.25
обещает функцию `always()`, поэтому workflow не должен зависеть от
`if:`-выражений для динамического выбора набора тестов по diff или уровню
риска.
-`jobs.<job_id>.timeout-minutes`, `permissions`, `concurrency` и
`jobs.<job_id>.environment` в Gitea 1.25 игнорируются. Не используйте их как
защиту, срок исполнения, обязательный approval или средство экономии.
-У runner capacity 1. Разделение текущей последовательной работы на
параллельные jobs не даёт измеримого параллельного исполнения на этом runner
и может добавить запуск/очередь. Сохраняйте проверку сборки обеих production
images: она подтверждает Dockerfiles, но использует Kaniko с `--no-push` и не
публикует образы.
Источники семантики: [Gitea 1.25 Actions comparison](https://docs.gitea.com/1.25/usage/actions/comparison/),
[Gitea 1.25 Actions FAQ](https://docs.gitea.com/1.25/usage/actions/faq/) и
Перед использованием новой workflow-семантики сверяй её с документацией
установленной версии и проверяй фактическим run. Не добавляй проверки самой
этой политики или статические тесты, утверждающие её текст.
## Временные ориентиры и фактические измерения
Ориентиры — цель для поиска затрат, а не разрешение убрать тесты:
- Обычный полный CI: до 5 минут от старта job до завершения. При превышении
сначала измерить и оптимизировать узкий участок, сохраняя тесты и изоляцию.
- Расширенный путь для `HIGH` (обычный CI плюс целевые проверки): целевой
суммарный интервал 10–15 минут. Это пока ориентир, а не отдельный
автоматический workflow или установленный timeout.
Срез 2026-10-24 получен из документированного [Gitea Actions task API](https://docs.gitea.com/api/1.25/operations/list-action-tasks/)
`/repos/admin/akyldash/actions/tasks?limit=50`. Взяты 20 последних завершённых
`tests-and-images`; длительность оценена как `updated_at - run_started_at`:
| Метрика | Измерение |
|---|---:|
| CI completed sample | 20 прогонов, 20 success |
| CI median | 147.5 s (2:27.5) |
| CI p90 | 172 s (2:52) |
| CI max | 192 s (3:12) |
| Runner smoke median / max | 2 s / 3 s, последние 20 прогонов |
Прежней reconciliation или оценок длительности в доступной документации
репозитория, workflows, PR и issues не найдено; этот срез является первой
подтверждённой базой, и сравнить его с прежней оценкой нельзя.
Все 20 измеренных полных CI прогонов ниже пяти минут; текущая конфигурация уже
достигает обычного ориентира. Отдельного extended workflow нет, поэтому
10–15-минутная цель пока не имеет фактической базы. В выборке нет breakdown по
steps: документированный endpoint для jobs завершённого run возвратил пустой
список; это известное ограничение Gitea 1.25.5 ([upstream issue #38286](https://github.com/go-gitea/gitea/issues/38286)).
Не распределяй время между тестами и image builds по предположению. При будущих
изменениях workflow записывай доступные timestamps и точный размер выборки;
после изменения Gitea/runner перепроверь, стал ли доступен надёжный step timing.
## Метрики потока поставки
Для каждого релиза/месячного обзора отдельно собирать:
| Метрика | Определение и источник |
|---|---|
| Ready → merge | Время с момента, когда PR реально готов к ревью, до merge. Не подменять датой создания draft PR; при отсутствии точного ready timestamp записывать `N/A`. |
| Merge → deploy | Merge timestamp до фактического production deploy timestamp. Deploy пока не автоматизирован; пока нет подтверждённого deploy evidence, записывать `N/A`, не ноль. |
| CI duration | `run_started_at` → task completion (`updated_at`) по Actions API; отдельно указывать медиану, p90, максимум, период и число прогонов. |
| Повторные прогоны | Число неуспешных/повторных прогонов на commit до первого успеха; отличать rerun от нового commit/push. |
| Блокирующие замечания | Число ревью-находок, удовлетворяющих критериям blockers выше; неблокирующие считать отдельно. |
| Вышедшие регрессии | Подтверждённые после merge дефекты, связанные с изменением; фиксировать компонент, тяжесть и пропущенный сигнал. |
| Rollback | Количество фактически выполненных rollback, причина и результат проверки данных/сервиса. Не считать написанный план фактическим rollback. |
На момент этого аудита PR/API не дают надёжного ready timestamp для старых
изменений; production deployment не автоматизирован, а задачи этого PR не
содержат deploy telemetry. Поэтому ready→merge, merge→deploy, escaped
regressions и rollback baseline остаются `N/A`, пока не появится проверяемая
запись. Не придумывай значения из `created_at` или даты последнего update.
## Критерий блокирующего ревью
Блокирующие замечания ограничены случаями:
- воспроизводимый дефект с конкретным условием и последствием;
- расширение доступа, утечка секрета или обход границы runner/production;
- потеря/искажение данных или несовместимость API/storage без безопасного пути;
- обязательный тест или подтверждение из таблицы риска отсутствует/не проходит;
- опасная операция не имеет проверяемого backup/rollback плана.
Каждый блокер содержит файл/участок, шаги воспроизведения или точное условие,
последствие и минимальный безопасный fix. Остальные замечания — отдельный
неблокирующий список. Review и approval остаются за людьми; агент не начинает
review сам и не сливает PR.
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.