# 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 если head # закроет pipe раньше. Делаем команды непадающими через || 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-studio/build/ # # При сбое деплоя ни один сервер не остаётся в полу-задеплоенном # состоянии: rsync делает атомарную замену с --delete-after. # ──────────────────────────────────────────────────────────────────── deploy: name: Deploy to S1 + S2 if: github.event_name == 'push' && github.ref == 'refs/heads/main' 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: sudo apt-get update -qq && sudo apt-get install -y rsync openssh-client - name: Deploy to S1 (85.175.7.40:1998) run: | rsync -az --delete-after --human-readable \ -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 1998" \ build/ min@85.175.7.40:/var/www/rublox-studio/build/ - name: Deploy to S2 (192.168.0.124:22, runner в той же сети) run: | rsync -az --delete-after --human-readable \ -e "ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22" \ build/ min@192.168.0.124:/var/www/rublox-studio/build/ - name: Verify deploy run: | echo "=== S1 ===" ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 1998 \ min@85.175.7.40 \ "ls /var/www/rublox-studio/build/index.html && du -sh /var/www/rublox-studio/build/" echo "=== S2 ===" ssh -i ~/.ssh/id_deploy -o UserKnownHostsFile=~/.ssh/known_hosts -p 22 \ min@192.168.0.124 \ "ls /var/www/rublox-studio/build/index.html && du -sh /var/www/rublox-studio/build/"