diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0dacc1e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,28 @@ +name: ci + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: .NET 10 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '10.0.x' + + - name: Node 20 + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: npm + cache-dependency-path: src/frontend/package-lock.json + + - name: CI (сборка, тесты, скан уязвимостей, фронт) + run: sh scripts/ci.sh diff --git a/README.md b/README.md index 45c6b80..d0d3f0d 100644 --- a/README.md +++ b/README.md @@ -31,4 +31,5 @@ cd src/frontend && npm run dev ``` Вход: `admin` / `admin`. Оператор-консоль: `http://localhost:5173/#/operator` (`operator` / `operator`). -Сквозная проверка стека: `sh scripts/dev-smoke.sh`. Тесты core: `sh scripts/test.sh`. +Сквозная проверка стека: `sh scripts/dev-smoke.sh`. Сборка: `sh scripts/build.sh`; тесты: `sh scripts/test.sh`; +полный CI-прогон (сборка + тесты + скан уязвимостей + фронт): `sh scripts/ci.sh`. diff --git a/backlog.md b/backlog.md index 0ebbab9..475dad3 100644 --- a/backlog.md +++ b/backlog.md @@ -26,7 +26,7 @@ | BL-K8S | Kubernetes-манифесты (сейчас docker-compose; k8s — при масштабировании) | ТЗ §11/§12, R6 | P3 | DEFERRED | | BL-KAFKA | Kafka как шина данных между сервисами (сейчас gRPC + БД-outbox) | ТЗ §12, обсуждение | P3 | DEFERRED | | BL-CF | Cloudflare / внешний периметр (сейчас Caddy, mTLS; конфиг вне кода) | ТЗ §11, техдок §10 | P2 | MANUAL | -| BL-CI | Внешний CI/CD + SAST + скан зависимостей в пайплайне (сейчас вручную) | техдок §8 | P2 | BACKLOG | +| BL-CI | **Сделано (2026-09-11):** `scripts/ci.sh` — сборка всех 5 решений, тесты всех сервисов, скан уязвимых NuGet-зависимостей (`dotnet list package --vulnerable --include-transitive`), сборка+линтер фронта; `build.sh`/`test.sh` расширены на все решения/сервисы; `.github/workflows/ci.yml`. Первый прогон в удалённом CI — при публикации репозитория | техдок §8 | P2 | DONE (remote — MANUAL) | | BL-IMG-HARDEN | **Сделано (2026-09-11):** non-root USER (deal, UID 10001, HOME=/tmp) во всех прикладных образах; в compose — read_only root FS + tmpfs /tmp, no-new-privileges, cap_drop ALL, mem_limit/cpus; логи stateless-сервисов в /tmp/logs. Проверено `compose config` (dev/prod/observability); живой прогон — MANUAL | техдок §10 | P2 | DONE (live — MANUAL) | | BL-BACKUP-CRON | Автоматизация бэкапов (cron/systemd-примеры есть, реальный прогон — MANUAL) | техдок §9 | P2 | MANUAL | diff --git a/docs/technical/Техническая-документация-Дейл.md b/docs/technical/Техническая-документация-Дейл.md index e98de7a..e9c9b98 100644 --- a/docs/technical/Техническая-документация-Дейл.md +++ b/docs/technical/Техническая-документация-Дейл.md @@ -367,13 +367,17 @@ DEAL_MTLS_ENABLED=0|1 DEAL_MTLS_CERT_PASSWORD=... DEAL_DEFAULT_AI_BU Секреты — только через env/secret-хранилище, не в коде и не в репозитории. ### CI/CD -- Сборка: `scripts/build.sh` (core) + сервисные sln — 0 warnings/0 errors (`TreatWarningsAsErrors`); - тесты: `scripts/test.sh` (unit core + `npm run lint:i18n`) + сервисные тесты. Фронт — `npm run build`. +- Единый прогон: `scripts/ci.sh` (BL-CI, 2026-09-11) — сборка всех 5 решений (`scripts/build.sh`), + тесты всех сервисов (`scripts/test.sh`: core/telegram/ai/ml/storage + `npm run lint:i18n`), + скан уязвимых NuGet-зависимостей (`dotnet list package --vulnerable --include-transitive`), + сборка фронта (`npm ci && npm run build`). Сборка — 0 warnings/0 errors (`TreatWarningsAsErrors`). +- Готовый workflow: `.github/workflows/ci.yml` (setup-dotnet 10 + setup-node 20 → `sh scripts/ci.sh`); + первый прогон в удалённом CI — при публикации репозитория. - Нагрузочный прогон: `scripts/loadtest/` (bash+curl и k6-вариант; логин admin/admin → контейнеры/карточки; RPS/avg/p95; см. README рядом). - Доставка на VPS: сборка образов → `docker compose ... up -d --build`. -- Внешний CI/SAST и k8s — вне этапа (заделы). Скан уязвимостей зависимостей выполнен вручную - (`dotnet list package --vulnerable`, `npm audit`) — чисто на 2026-09-10. +- Результат локального прогона `scripts/ci.sh` (2026-09-11): core 1315, telegram 130, ai 52, ml 38, + storage 9 — всё PASS; фронт `lint:i18n`/`build` зелёные. k8s — вне этапа (задел). --- @@ -942,8 +946,9 @@ docker exec deal-postgres psql -U deal -d deal -c '\dt tenant_*.*' ### 6. Тесты и сборка (из корня репозитория) ```sh -sh scripts/build.sh # dotnet build Deal.sln (ожидается 0 warnings / 0 errors) -sh scripts/test.sh # dotnet test tests/Deal.Tests.Unit (ожидается 1275 PASS — этап 12) +sh scripts/build.sh # сборка всех 5 решений (0 warnings / 0 errors) +sh scripts/test.sh # тесты всех сервисов + lint:i18n (core 1315, telegram 130, ai 52, ml 38, storage 9) +sh scripts/ci.sh # полный CI-прогон: build + test + скан уязвимостей + сборка фронта ``` Сквозные приёмки этапов — curl-сценарии на :5080 в `.superpowers/sdd/deal-stage{4,5}-projects/` diff --git a/scripts/build.sh b/scripts/build.sh index 97a2f46..31e3dda 100644 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,4 +1,15 @@ #!/usr/bin/env sh +# build.sh — сборка всех решений Дейла (core + сервисы). CI-шаг «build». set -e -cd "$(dirname "$0")/../src/core" -dotnet build Deal.sln + +REPO_DIR=$(cd "$(dirname "$0")/.." && pwd) + +for SLN in \ + src/core/Deal.sln \ + src/telegram-service/Deal.Telegram.sln \ + src/ai-service/Deal.Ai.sln \ + src/ml-service/Deal.Ml.sln \ + src/storage-service/Deal.Storage.sln; do + echo "== build: $SLN ==" + (cd "$REPO_DIR" && dotnet build "$SLN" -v q --nologo) +done diff --git a/scripts/ci.sh b/scripts/ci.sh new file mode 100644 index 0000000..fe46042 --- /dev/null +++ b/scripts/ci.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env sh +# ci.sh — полный прогон Дейла (BL-CI): сборка всех решений, тесты, скан уязвимых +# NuGet-зависимостей, сборка и линтер фронта. Для локального запуска и CI-пайплайна. +# sh scripts/ci.sh +# Секреты и внешние сервисы не требуются: тесты — юнит (InMemory/fakes), БД/сеть не нужны. +set -e + +REPO_DIR=$(cd "$(dirname "$0")/.." && pwd) + +echo "== CI: сборка ==" +sh "$REPO_DIR/scripts/build.sh" + +echo +echo "== CI: тесты ==" +sh "$REPO_DIR/scripts/test.sh" + +echo +echo "== CI: скан уязвимых NuGet-зависимостей ==" +for SLN in \ + src/core/Deal.sln \ + src/telegram-service/Deal.Telegram.sln \ + src/ai-service/Deal.Ai.sln \ + src/ml-service/Deal.Ml.sln \ + src/storage-service/Deal.Storage.sln; do + echo "-- $SLN" + OUTPUT=$(cd "$REPO_DIR" && dotnet list "$SLN" package --vulnerable --include-transitive 2>&1 || true) + if printf '%s' "$OUTPUT" | grep -qi "has the following vulnerable"; then + printf '%s\n' "$OUTPUT" + echo "ОШИБКА: уязвимые зависимости в $SLN" + exit 1 + fi +done + +echo +echo "== CI: сборка фронта ==" +if command -v npm >/dev/null 2>&1; then + (cd "$REPO_DIR/src/frontend" && { + if [ -f package-lock.json ]; then npm ci; else npm install; fi + } && npm run build) +else + echo " пропуск: npm не установлен (сборка фронта не запущена)" +fi + +echo +echo "== CI ОК ==" diff --git a/scripts/test.sh b/scripts/test.sh index 5b72424..f18e314 100644 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,15 +1,18 @@ #!/usr/bin/env sh -# test.sh — общий прогон тестов и линтеров проекта Дейл (этап 12, пакет C): -# 1) core: юнит-тесты Deal.Tests.Unit (dotnet test); -# 2) frontend: линтер локализации (npm run lint:i18n) — если установлен npm; иначе шаг мягко -# пропускается (установка фронт-зависимостей `npm ci` — отдельное действие, и прогон -# тестов не должен падать из-за её отсутствия). +# test.sh — тесты всех сервисов Дейла + линтер локализации фронта. CI-шаг «test». set -e REPO_DIR=$(cd "$(dirname "$0")/.." && pwd) -echo "== core: dotnet test ==" -(cd "$REPO_DIR/src/core" && dotnet test tests/Deal.Tests.Unit) +for PROJECT in \ + src/core/tests/Deal.Tests.Unit/Deal.Tests.Unit.csproj \ + src/telegram-service/Deal.Telegram.Tests/Deal.Telegram.Tests.csproj \ + src/ai-service/Deal.Ai.Tests/Deal.Ai.Tests.csproj \ + src/ml-service/Deal.Ml.Tests/Deal.Ml.Tests.csproj \ + src/storage-service/Deal.Storage.Tests/Deal.Storage.Tests.csproj; do + echo "== test: $PROJECT ==" + (cd "$REPO_DIR" && dotnet test "$PROJECT" --nologo --logger "console;verbosity=minimal") +done echo echo "== frontend: lint:i18n ==" @@ -18,6 +21,3 @@ if command -v npm >/dev/null 2>&1; then else echo " пропуск: npm не установлен (линтер локализации не запущен)" fi - -echo -echo "== TEST ОК =="