name: CI - Build & Test run-name: 🔍 CI ${{ gitea.ref_name }} by @${{ gitea.actor }} # ── Concurrency: cancel in-progress CI when new push arrives ── concurrency: group: ci-${{ gitea.ref }} cancel-in-progress: true on: push: branches: - main - 'codex/**' pull_request: branches: [main] workflow_dispatch: jobs: # ─── Backend ─────────────────────────────────── backend: name: Backend (.NET) runs-on: linux steps: - name: Checkout uses: actions/checkout@v4 - name: Setup .NET SDK uses: actions/setup-dotnet@v4 with: dotnet-version: '10.0.x' - name: Restore run: dotnet restore backend-tests/Nexus.Api.Tests.csproj - name: Build run: dotnet build backend-tests/Nexus.Api.Tests.csproj --no-restore --configuration Release - name: Verify OpenAPI contract run: | test -f backend/openapi/Nexus.Api.json test -z "$(git status --porcelain --untracked-files=all -- backend/openapi/Nexus.Api.json)" - name: Test run: dotnet test backend-tests/Nexus.Api.Tests.csproj --no-build --configuration Release --verbosity normal - name: Docker integration tests if: ${{ vars.NEXUS_RUN_DOCKER_INTEGRATION_TESTS == 'true' }} timeout-minutes: 15 env: NEXUS_RUN_DOCKER_INTEGRATION_TESTS: "true" NEXUS_RUN_TOXIPROXY_INTEGRATION_TESTS: ${{ vars.NEXUS_RUN_TOXIPROXY_INTEGRATION_TESTS }} run: >- dotnet test backend-tests/Nexus.Api.Tests.csproj --no-build --configuration Release --filter "Category=DockerIntegration" --verbosity normal # ─── Frontend ────────────────────────────────── frontend: name: Frontend (Vue/TS) runs-on: linux steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '24' - name: Setup pnpm run: | corepack enable corepack prepare pnpm@10.12.1 --activate - name: Install dependencies run: pnpm install --frozen-lockfile working-directory: frontend - name: Type check run: pnpm typecheck working-directory: frontend - name: Verify generated API types run: | pnpm openapi:generate test -z "$(git status --porcelain --untracked-files=all -- src/api/generated/schema.d.ts)" working-directory: frontend - name: Test run: pnpm test working-directory: frontend - name: Build run: pnpm build working-directory: frontend - name: Install Playwright Chromium run: pnpm exec playwright install --with-deps chromium working-directory: frontend - name: Browser end-to-end tests run: pnpm test:e2e working-directory: frontend # ─── Security ────────────────────────────────── security: name: Security Check runs-on: linux if: gitea.ref == 'refs/heads/main' || startsWith(gitea.ref, 'refs/heads/codex/') steps: - name: Checkout uses: actions/checkout@v4 - name: Check for .env leaks run: | echo "🔍 Scanning for potential secrets in source code..." HITS=$(grep -rPn "(API_KEY|SECRET|PASSWORD|TOKEN)\s*[:=]\s*['\"][^'\"]{8,}" --include="*.cs" --include="*.ts" --include="*.vue" backend/ frontend/src/ 2>/dev/null || true) if [ -n "$HITS" ]; then echo "❌ SECRET LEAK DETECTED — the following lines look like hardcoded credentials:" echo "$HITS" echo "" echo "Remove these values and use environment variables or a secrets manager instead." exit 1 fi # Secondary pass: catch bare assign patterns that are suspicious regardless of length LOOSE=$(grep -rPn "(API_KEY|SECRET|PASSWORD|TOKEN)\s*[:=]\s*['\"]" --include="*.cs" --include="*.ts" --include="*.vue" backend/ frontend/src/ 2>/dev/null || true) if [ -n "$LOOSE" ]; then echo "⚠️ WARNING — potential secrets found (short values may be false positives, review manually):" echo "$LOOSE" else echo "✅ No obvious secrets found" fi deploy: name: Deploy Nexus runs-on: linux needs: [backend, frontend, security] concurrency: group: deploy-production cancel-in-progress: false if: | gitea.event_name == 'push' && gitea.ref == 'refs/heads/main' env: DEPLOY_PATH: /home/projekte_bao/nexus ENV_POSTGRES_PASSWORD: ${{ secrets.ENV_POSTGRES_PASSWORD }} ENV_JWT_KEY: ${{ secrets.ENV_JWT_KEY }} ENV_BOOTSTRAP_OWNER_PASSWORD: ${{ secrets.ENV_BOOTSTRAP_OWNER_PASSWORD }} ENV_OPENCLAW_TOKEN: ${{ secrets.ENV_OPENCLAW_TOKEN }} steps: - name: Checkout uses: actions/checkout@v4 - name: Deploy after green CI run: sh .gitea/scripts/deploy-nexus.sh