20 KiB
Delivery First: проверка изменений по риску
Эта политика помогает быстро принимать небольшие изменения и добавляет
проверки там, где ошибка затрагивает пользователей, данные или границы
безопасности. Класс риска выбирает глубину проверки; он не позволяет снять
обязательную проверку, одобрение или защиту main.
Порядок работы
- До реализации укажи в PR
LOW,MEDIUMилиHIGHи коротко объясни причину. Если изменение пересекает несколько областей, выбери самый высокий класс. При неопределённости используй более высокий класс. - Сначала проследи путь изменения от пользовательского/API входа до данных, внешних систем и отката. Для изменения поведения добавь регрессионный тест, который подтверждает конкретный контракт или прежний дефект.
- Запусти проверку именно затронутого поведения и обычный Gitea CI. Для UI
дополнительно выполни
cd tools/frontend-visual-review && npm ci && npm test; этот браузерный набор сейчас не входит в Gitea CI. - В PR перечисли класс риска, команды и результаты, остаточные ограничения, а для high-risk — совместимость, угрозы и безопасный rollback. Не заявляй проверку, которой фактически не было.
- Ревьюер отделяет блокирующие дефекты от улучшений. Блокер должен указывать конкретное место, условие воспроизведения и последствие. Стилистические предпочтения и предложения на будущее фиксируются отдельно и не задерживают 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.52026-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 IDrunner-smokeи проверяет runtime-изоляцию job-контейнера: отсутствие системного и rootless Docker socket, production env/secrets и host checkout. Smoke дополняет статические проверки runner/CI и не дублирует их.- Инфраструктурная конфигурация репозитория закрепляет официальный
act_runner 0.2.13, labelakyldash-ci, capacity 1 и ограничения job 2 CPU, 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, Gitea 1.25 Actions FAQ и act_runner guide. Перед использованием новой workflow-семантики сверяй её с документацией установленной версии и проверяй фактическим run. Не добавляй проверки самой этой политики или статические тесты, утверждающие её текст.
Временные ориентиры и фактические измерения
Ориентиры — цель для поиска затрат, а не разрешение убрать тесты:
- Обычный полный CI: до 5 минут от старта job до завершения. При превышении сначала измерить и оптимизировать узкий участок, сохраняя тесты и изоляцию.
- Расширенный путь для
HIGH(обычный CI плюс целевые проверки): целевой суммарный интервал 10–15 минут. Это пока ориентир, а не отдельный автоматический workflow или установленный timeout.
Срез 2026-10-24 получен из документированного Gitea Actions task API
/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). Не распределяй время между тестами и 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.