From 32e8efee151892d4154fde480830d85ceed68a5e Mon Sep 17 00:00:00 2001 From: min Date: Sat, 20 Jun 2026 18:07:14 +0300 Subject: [PATCH] =?UTF-8?q?ci:=20=D1=80=D0=B5=D1=82=D1=80=D0=B0=D0=B9=20?= =?UTF-8?q?=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE=D0=B2=D0=BA=D0=B8=20truffl?= =?UTF-8?q?ehog=20=D0=B2=20secret-scan=20(=D1=84=D0=BB=D0=B0=D0=BF=20?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BA=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BB=20?= =?UTF-8?q?deploy)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Шаг "Install trufflehog" качал install.sh с raw.githubusercontent через curl без ретрая. Разовый сетевой таймаут (curl exit 28) валил secret-scan → deploy пропускался (needs: [build, secret-scan]), хотя код корректен. Добавлен цикл из 3 попыток с паузой 10с + --connect-timeout/--max-time и проверка command -v trufflehog. Разовый сетевой сбой CI больше не блокирует деплой. Co-Authored-By: Claude Opus 4.8 --- .gitea/workflows/ci.yml | 326 +++++++++++++++++++++------------------- 1 file changed, 168 insertions(+), 158 deletions(-) diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 7de0265..688631e 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,158 +1,168 @@ -# CI плеера Рублокса. -# Запускается на каждый push и pull_request. -# -# Что проверяем: -# 1. lint — ESLint без warning'ов -# 2. format-check — Prettier формат не нарушен -# 3. build — vite build проходит без ошибок -# 4. secret-scan — trufflehog не нашёл утечек секретов -# 5. size-check — PR не больше 1000 строк (предупреждение) -name: CI - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - lint: - name: Lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '18' - - run: npm ci - # format:check временно отключён до массового npx prettier --write - # (см. docs/ONBOARDING.md → «Форматирование кода»). После прогона - # верни строку `- run: npm run format:check` перед npm run lint. - - run: npm run lint - - build: - name: Build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '18' - - run: npm ci - - run: npm run build - - name: Save build size - # set -o pipefail (default Gitea Actions) валит step при SIGPIPE - # от head. Делаем команды непадающими через || true. - run: | - du -sh build/ || true - ls -la build/assets/ 2>/dev/null | head -10 || true - - secret-scan: - name: Secret scan - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Install trufflehog - run: | - curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \ - | sh -s -- -b /usr/local/bin - - name: Run trufflehog - run: | - trufflehog git "file://$(pwd)" \ - --only-verified --fail \ - --exclude-paths .trufflehog-ignore 2>&1 | tee scan.log || EXIT=$? - if [ -n "$EXIT" ] && [ "$EXIT" -ne 0 ]; then - echo "::error::Найдены секреты в коммитах! См. лог выше." - exit 1 - fi - - size-check: - name: PR size check - if: github.event_name == 'pull_request' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Check PR size - run: | - ADDED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0) - REMOVED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0) - TOTAL=$((ADDED + REMOVED)) - echo "PR изменяет $TOTAL строк (+$ADDED / -$REMOVED)" - if [ "$TOTAL" -gt 1000 ]; then - echo "::warning::PR изменяет $TOTAL строк (> 1000). Подумай о дроблении на несколько меньших." - fi - - # ──────────────────────────────────────────────────────────────────── - # DEPLOY — собирает прод-бандл и заливает на ОБА сервера (S1+S2) - # параллельно через rsync over SSH. - # - # Запускается ТОЛЬКО на push в main (т.е. после успешного мержа PR). - # PR-проверки выше (lint/build/secret-scan/size-check) гарантируют - # что в main попадает только корректный код. - # - # Секреты: - # DEPLOY_SSH_KEY — приватный ed25519 ключ (CI-only, отдельный от - # админских), pubkey уже на ~min/.ssh/authorized_keys - # на S1 VM 124 и S2 VM 124 - # KNOWN_HOSTS — host-keys S1 и S2 (защита от MITM) - # - # Цели (на VM 124 обоих серверов): - # /var/www/rublox-player/build/ - # ──────────────────────────────────────────────────────────────────── - deploy: - name: Deploy to S1 + S2 - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - # Lint НЕ в needs — он опциональный (исторический долг empty-блоков - # ещё не вычищен, см. branch protection без 'CI / Lint' в required). - # Deploy всё равно зависит от Build и Secret-scan — это критично. - needs: [build, secret-scan] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: '18' - - name: Install deps - run: npm ci - - name: Production build - run: npm run build - - name: Prepare SSH - env: - DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }} - run: | - mkdir -p ~/.ssh && chmod 700 ~/.ssh - echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_deploy - chmod 600 ~/.ssh/id_deploy - echo "$KNOWN_HOSTS" > ~/.ssh/known_hosts - chmod 600 ~/.ssh/known_hosts - - name: Install rsync - run: apt-get update -qq && apt-get install -y rsync openssh-client - # S1 — НЕ блокирующий: при недоступности S1 (downtime) деплой не должен - # валиться, главное доставить на S2. ConnectTimeout 20с чтобы не висеть. - - name: Deploy to S1 (85.175.7.40:1998) - continue-on-error: true - run: | - rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \ - -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -o ConnectTimeout=20 -p 1998" \ - build/ min@85.175.7.40:/var/www/rublox-player/build/ - - name: Deploy to S2 (192.168.0.124:22, runner в той же сети) - run: | - rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \ - -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22" \ - build/ min@192.168.0.124:/var/www/rublox-player/build/ - - name: Verify S1 (не блокирующий) - continue-on-error: true - run: | - ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -o ConnectTimeout=20 -p 1998 \ - min@85.175.7.40 \ - "ls /var/www/rublox-player/build/index.html && du -sh /var/www/rublox-player/build/ 2>/dev/null || true" - - name: Verify S2 (обязательный) - run: | - ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22 \ - min@192.168.0.124 \ - "ls /var/www/rublox-player/build/index.html && (du -sh /var/www/rublox-player/build/ 2>/dev/null || true)" +# CI плеера Рублокса. +# Запускается на каждый push и pull_request. +# +# Что проверяем: +# 1. lint — ESLint без warning'ов +# 2. format-check — Prettier формат не нарушен +# 3. build — vite build проходит без ошибок +# 4. secret-scan — trufflehog не нашёл утечек секретов +# 5. size-check — PR не больше 1000 строк (предупреждение) +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '18' + - run: npm ci + # format:check временно отключён до массового npx prettier --write + # (см. docs/ONBOARDING.md → «Форматирование кода»). После прогона + # верни строку `- run: npm run format:check` перед npm run lint. + - run: npm run lint + + build: + name: Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '18' + - run: npm ci + - run: npm run build + - name: Save build size + # set -o pipefail (default Gitea Actions) валит step при SIGPIPE + # от head. Делаем команды непадающими через || true. + run: | + du -sh build/ || true + ls -la build/assets/ 2>/dev/null | head -10 || true + + secret-scan: + name: Secret scan + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Install trufflehog + run: | + # Скачивание install.sh с raw.githubusercontent периодически + # отваливается по сетевому таймауту (curl exit 28) и валит весь + # secret-scan → deploy skipped. Ретраим 3 раза с паузой, чтобы + # разовый сетевой сбой CI не блокировал деплой. + for i in 1 2 3; do + curl -sSfL --connect-timeout 15 --max-time 120 \ + https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \ + | sh -s -- -b /usr/local/bin && break + echo "Попытка $i установить trufflehog не удалась, повтор через 10с…" + sleep 10 + done + command -v trufflehog + - name: Run trufflehog + run: | + trufflehog git "file://$(pwd)" \ + --only-verified --fail \ + --exclude-paths .trufflehog-ignore 2>&1 | tee scan.log || EXIT=$? + if [ -n "$EXIT" ] && [ "$EXIT" -ne 0 ]; then + echo "::error::Найдены секреты в коммитах! См. лог выше." + exit 1 + fi + + size-check: + name: PR size check + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Check PR size + run: | + ADDED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0) + REMOVED=$(git diff origin/${{ github.base_ref }}...HEAD --shortstat | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0) + TOTAL=$((ADDED + REMOVED)) + echo "PR изменяет $TOTAL строк (+$ADDED / -$REMOVED)" + if [ "$TOTAL" -gt 1000 ]; then + echo "::warning::PR изменяет $TOTAL строк (> 1000). Подумай о дроблении на несколько меньших." + fi + + # ──────────────────────────────────────────────────────────────────── + # DEPLOY — собирает прод-бандл и заливает на ОБА сервера (S1+S2) + # параллельно через rsync over SSH. + # + # Запускается ТОЛЬКО на push в main (т.е. после успешного мержа PR). + # PR-проверки выше (lint/build/secret-scan/size-check) гарантируют + # что в main попадает только корректный код. + # + # Секреты: + # DEPLOY_SSH_KEY — приватный ed25519 ключ (CI-only, отдельный от + # админских), pubkey уже на ~min/.ssh/authorized_keys + # на S1 VM 124 и S2 VM 124 + # KNOWN_HOSTS — host-keys S1 и S2 (защита от MITM) + # + # Цели (на VM 124 обоих серверов): + # /var/www/rublox-player/build/ + # ──────────────────────────────────────────────────────────────────── + deploy: + name: Deploy to S1 + S2 + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + # Lint НЕ в needs — он опциональный (исторический долг empty-блоков + # ещё не вычищен, см. branch protection без 'CI / Lint' в required). + # Deploy всё равно зависит от Build и Secret-scan — это критично. + needs: [build, secret-scan] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: '18' + - name: Install deps + run: npm ci + - name: Production build + run: npm run build + - name: Prepare SSH + env: + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + KNOWN_HOSTS: ${{ secrets.KNOWN_HOSTS }} + run: | + mkdir -p ~/.ssh && chmod 700 ~/.ssh + echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_deploy + chmod 600 ~/.ssh/id_deploy + echo "$KNOWN_HOSTS" > ~/.ssh/known_hosts + chmod 600 ~/.ssh/known_hosts + - name: Install rsync + run: apt-get update -qq && apt-get install -y rsync openssh-client + # S1 — НЕ блокирующий: при недоступности S1 (downtime) деплой не должен + # валиться, главное доставить на S2. ConnectTimeout 20с чтобы не висеть. + - name: Deploy to S1 (85.175.7.40:1998) + continue-on-error: true + run: | + rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \ + -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -o ConnectTimeout=20 -p 1998" \ + build/ min@85.175.7.40:/var/www/rublox-player/build/ + - name: Deploy to S2 (192.168.0.124:22, runner в той же сети) + run: | + rsync -az --delete-after --human-readable --exclude=wiki --exclude=kubikon-assets \ + -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22" \ + build/ min@192.168.0.124:/var/www/rublox-player/build/ + - name: Verify S1 (не блокирующий) + continue-on-error: true + run: | + ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -o ConnectTimeout=20 -p 1998 \ + min@85.175.7.40 \ + "ls /var/www/rublox-player/build/index.html && du -sh /var/www/rublox-player/build/ 2>/dev/null || true" + - name: Verify S2 (обязательный) + run: | + ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22 \ + min@192.168.0.124 \ + "ls /var/www/rublox-player/build/index.html && (du -sh /var/www/rublox-player/build/ 2>/dev/null || true)"