# Отчёт: Gitea Actions runner + CI-пайплайн `embeddevio/awg-dash` (v2) **Владелец:** devops · **Дата:** 2026-10-28 · **Refs #17, Refs #15** **Ветка:** `feat/17-ci` · **Ветка проверки:** `feat/17-verify` (= #17 + `deploy/*` из #18) ## 1. Итог Runner, поднятый 28.10, **фактически не работал**: задачи забирались, но падали на создании контейнера, а результаты не фиксировались в Gitea. Причины найдены и устранены на build-хосте `192.168.1.147`. Пайплайн `ci.yml` написан, закоммичен и **прогнан на живом runner'е** — все три гейта подтверждены реальными падениями jobs. Осталось три внешних пункта, которые агент закрыть не может (нет SSH к `192.168.1.111`, нет прав на merge): git-http дефект Gitea (#59), артефакты Gitea не публикуются, `deploy/Dockerfile` появится в `main` только после merge #18. ## 2. Что было сломано в runner'е и как исправлено | # | Симптом | Причина | Исправление | |---|---|---|---| | 1 | jobs вечно `queued`, `runner_id: 0`, логов нет | runner зарегистрирован **instance-token'ом** (`gitea-runner-awg`): задачи забирались, но результат не привязывался к репозиторию | зарегистрирован **repo-scoped** runner `awg-dash-147-repo` (repo registration token через API), `online`, id 2; legacy-контейнер остановлен | | 2 | `failed to create container: Duplicate mount point: /var/run/docker.sock` | `container.options` монтировал сокет, а act_runner v0.6.1 монтирует его сам | `options: ""` + `valid_volumes: ["/var/run/docker.sock"]` | | 3 | `all predefined address pools have been fully subnetted` | 23 «висимых» сети `GITEA-ACTIONS-*` от прерванных job'ов вычерпали пул Docker | удалены все `GITEA-ACTIONS-*` с 0 контейнеров (31 → 8 сетей); `container.network: "host"` как профилактика | | 4 | `git clone` в шаге checkout: `bad pack header` | дефект Gitea git-http (issue #59), не runner | в `ci.yml` — fallback на `archive/.tar.gz` (archive работает: 200, валидный tar) | | 5 | trivy: `install.sh` + `v0.57.1` → 404, tarball с github releases качается минутами | неверная версия в скрипте + медленная отдача github releases | trivy запускается официальным образом `aquasec/trivy:0.76.1` через docker-сокет, БД кэшируется в `/opt/trivy-cache` | ## 3. Итоговая конфигурация runner'а ``` контейнер : gitea-runner-awg-repo (docker.io/gitea/act_runner:latest v0.6.1), 192.168.1.147 область : repo-scoped (embeddevio/awg-dash), runner id 2, online label : ubuntu-latest -> catthehacker/ubuntu:act-22.04 capacity : 1 (maxParallel=1) сеть job : host, socket /var/run/docker.sock проброшен toolcache : volume act-toolcache -> /opt/hostedtoolcache (Python 3.12.16 установлен один раз) trivy : образ aquasec/trivy:0.76.1 + БД-кэш /opt/trivy-cache registry : 192.168.1.111:3000 добавлен в insecure-registries на .147 (применено `systemctl reload docker`, контейнеры не перезапускались) ``` ## 4. Пайплайн `.gitea/workflows/ci.yml` ``` lint ─┬─ unit ───────┐ │ ├─ build ── image-scan ── push (только push-событие) └─ security ───┘ ``` | Job | Команды | Гейт | |---|---|---| | lint | `ruff check backend`, `ruff format --check backend`, `mypy backend` | любая ошибка | | unit | `pytest --cov=awg_agent --cov=awg_api --cov-report=xml/html --cov-fail-under=70` | **coverage < 70 %** | | security | `bandit -lll -r backend`, `pip-audit -r requirements.txt -r requirements-contract.txt` | **bandit HIGH**, известные CVE в зависимостях | | build | `docker build --pull -f deploy/Dockerfile -t 192.168.1.111:3000/embeddevio/awg-dash:staging-` | ошибка сборки | | image-scan | `trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1` | **HIGH/CRITICAL в образе** | | push | `docker login` + `docker push ...:staging-` | ошибка авторизации/пуша | `build`/`image-scan`/`push` активируются только при наличии `deploy/Dockerfile` (output `has_dockerfile` из `lint`); до merge #18 они скипаются с предупреждением. ## 5. Прогоны на живом runner'е (доказательства по AC) ### 5.1 `feat/17-ci` (ветка от `main`, Dockerfile ещё нет) — run #39 http://192.168.1.111:3000/embeddevio/awg-dash/actions/runs/39 | Job | Результат | Детали | |---|---|---| | lint | ✅ success | ruff check/format + mypy strict | | unit | ✅ success | **198 passed**, coverage **96.80 %** (порог ≥ 70 %) | | security | ✅ success | bandit: 0 HIGH, pip-audit: CVE не найдены | | build / image-scan / push | ⏭ skipped | нет `deploy/Dockerfile` (ждёт #18) — штатное поведение | ### 5.2 `feat/17-verify` (= #17 + `deploy/*` из #18) — run #49 http://192.168.1.111:3000/embeddevio/awg-dash/actions/runs/49 | Job | Результат | Детали | |---|---|---| | lint | ✅ success | | | unit | ✅ success | 198 passed, coverage 96.80 % | | security | ✅ success | | | build | ✅ success | образ `192.168.1.111:3000/embeddevio/awg-dash:staging-` собран на runner'е | | image-scan | ❌ failure | `Total: 22 (HIGH: 21, CRITICAL: 1)` — golang stdlib v1.25.14, `golang.org/x/crypto` — см. п. 6.1 | | push | ⏭ skipped | fail-closed: при красном image-scan образ не публикуется | ### 5.3 Негативные прогоны гейтов — `ci/17-gate-negative` (ветка-пробник, удалена) | Проверка | Run | Что в логе | |---|---|---| | покрытие < порога | #51 http://192.168.1.111:3000/embeddevio/awg-dash/actions/runs/51 | `FAIL Required test coverage of 99% not reached. Total coverage: 96.80%` → job `unit` **failure** | | HIGH-находка bandit | #55 http://192.168.1.111:3000/embeddevio/awg-dash/actions/runs/55 | `Issue: [B602 ...] Severity: High Confidence: High` → job `security` **failure**, pipeline красный | | HIGH/CRITICAL в образе | #49 (см. 5.2) | 22 находки → `image-scan` **failure** | **Вывод по AC:** пуш в `feat/*` даёт jobs `lint`/`unit`/`security`/`build`; снижение покрытия ниже порога роняет job; HIGH-уязвимость (код или образ) роняет pipeline. ## 6. Открытые вопросы (эскалация) ### 6.1 Образ содержит 21 HIGH + 1 CRITICAL (нужен апгрейд сборки, #18) Trivy по образу, собранному из `deploy/Dockerfile` (#18): - `stdlib` Go **v1.25.14** → CVE-2026-56857 (CRITICAL), CVE-2026-111943, CVE-2026-78667, CVE-2026-97031 (HIGH); - `golang.org/x/crypto v0.42.0` → CVE-2025-47913 (HIGH, fix в 0.43.0). Причина: `ARG GO_IMAGE=golang:1.25-alpine` в `deploy/Dockerfile`. Гейт работает правильно — публикация образа заблокирована. Требуется бамп Go до ≥ 1.26.10 и `golang.org/x/crypto` ≥ 0.43.0 (владелец #18), после этого `image-scan` и `push` пойдут зелёными без правок CI. ### 6.2 Артефакты Gitea не публикуются `actions/upload-artifact@v3` отрабатывает без ошибок («Artifact has been successfully uploaded!», 173 КБ на coverage), но ни API (`/actions/runs//artifacts`, `/actions/artifacts`), ни UI артефактов не показывают (`total_count: 0`). `upload-artifact@v4` **зависает** (job висел >6 мин на старте экшена, контейнер пришлось снять). Итог: содержимое артефактов в Gitea 1.26 + runner v0.6.1 не сохраняется — поэтому в шагах дополнительно печатается сводка в лог job (coverage-таблица, bandit-отчёт, trivy-таблица) — эти логи стабильны и доступны по ссылке run'а. ### 6.3 Git-http Gitea (issue #59) Checkout штатным `actions/checkout` падает (`bad pack header`), работает только архивный fallback. Нужен доступ к хосту Gitea `192.168.1.111` (fsck/repack, проверка диска) — у агентов его нет. ### 6.4 Token для registry push PAT агента не имеет `write:package` → `401 Unauthorized` на `POST /v2/.../blobs/uploads/` (проверено вручную на .147). В `ci.yml` логин берёт `secrets.REGISTRY_TOKEN`, если он задан, иначе `secrets.GITHUB_TOKEN`. Для гарантированного push нужен секрет `REGISTRY_TOKEN` (owner, PAT с `write:package`). ## 7. Эксплуатация - Перезапуск run'а без коммита: `POST /api/v1/repos/embeddevio/awg-dash/actions/runs//rerun`. - Ручной запуск: `workflow_dispatch` у `ci.yml`. - Логи job'а: `GET /api/v1/repos/embeddevio/awg-dash/actions/jobs//logs`. - Полный runbook: `docs/ci/CI.md` в ветке `feat/17-ci`.