Production readiness improvements #42
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI/CD Pipeline | |
| on: | |
| push: | |
| branches: [ main, develop ] | |
| pull_request: | |
| branches: [ main, develop ] | |
| permissions: | |
| contents: read | |
| security-events: write | |
| actions: read | |
| env: | |
| NODE_VERSION: '20' | |
| PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: true | |
| jobs: | |
| # Security and Code Quality Checks | |
| security: | |
| name: Security & Code Quality | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run ESLint | |
| run: npm run lint | |
| - name: Run TypeScript check | |
| run: npx tsc --noEmit | |
| - name: Security audit | |
| run: npm audit --audit-level=moderate | |
| - name: Check for secrets | |
| uses: trufflesecurity/trufflehog@v3.63.6 | |
| with: | |
| path: ./ | |
| base: main | |
| head: HEAD | |
| extra_args: --debug --only-verified | |
| continue-on-error: true | |
| # Unit and Integration Tests | |
| test: | |
| name: Test Suite | |
| runs-on: ubuntu-latest | |
| needs: security | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run tests | |
| run: npm run test:ci | |
| env: | |
| NODE_ENV: test | |
| - name: Upload coverage reports | |
| uses: codecov/codecov-action@v3 | |
| with: | |
| file: ./coverage/lcov.info | |
| flags: unittests | |
| name: codecov-umbrella | |
| # Build and Performance Tests | |
| build: | |
| name: Build & Performance | |
| runs-on: ubuntu-latest | |
| needs: test | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build application | |
| run: npm run build | |
| env: | |
| NODE_ENV: production | |
| NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }} | |
| NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }} | |
| SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }} | |
| - name: Analyze bundle size | |
| run: npm run build:analyze | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: build-files | |
| path: .next/ | |
| retention-days: 1 | |
| # Enhanced Security Testing | |
| security-test: | |
| name: Enhanced Security Testing | |
| runs-on: ubuntu-latest | |
| needs: build | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| # Note: Snyk and Semgrep removed to stick with GitHub-native tools only | |
| # Dependency vulnerability scanning is handled by npm audit in the security job | |
| # CodeQL Analysis | |
| - name: Initialize CodeQL | |
| uses: github/codeql-action/init@v3 | |
| with: | |
| languages: javascript | |
| - name: Perform CodeQL Analysis | |
| uses: github/codeql-action/analyze@v3 | |
| # Custom Security Tests | |
| - name: Run security tests | |
| run: npm run test -- --testPathPattern=security | |
| # SQL Injection and XSS Testing | |
| - name: Run custom security checks | |
| run: | | |
| echo "Running custom security checks..." | |
| # Check for potential SQL injection patterns | |
| if grep -r "\.query\|\.raw\|\.exec" --include="*.ts" --include="*.js" app/ lib/; then | |
| echo "⚠️ Potential SQL injection patterns found" | |
| echo "Please review the above files for proper parameterization" | |
| fi | |
| # Check for potential XSS vulnerabilities | |
| if grep -r "dangerouslySetInnerHTML\|innerHTML" --include="*.tsx" --include="*.jsx" app/ components/; then | |
| echo "⚠️ Potential XSS vulnerabilities found" | |
| echo "Please review the above files for proper sanitization" | |
| fi | |
| # Check for hardcoded secrets | |
| if grep -r "password\|secret\|key\|token" --include="*.ts" --include="*.js" --exclude-dir=node_modules --exclude-dir=.git app/ lib/ | grep -v "process\.env"; then | |
| echo "⚠️ Potential hardcoded secrets found" | |
| echo "Please review the above files and use environment variables" | |
| fi | |
| echo "✅ Custom security checks completed" | |
| # OWASP ZAP Baseline Scan | |
| - name: OWASP ZAP Baseline Scan | |
| uses: zaproxy/action-baseline@v0.8.0 | |
| with: | |
| target: 'http://localhost:3000' | |
| rules_file_name: '.zap/rules.tsv' | |
| cmd_options: '-a' | |
| fail_action: false | |
| continue-on-error: true | |
| # Security Headers Check | |
| - name: Check Security Headers | |
| run: | | |
| echo "Checking security headers..." | |
| # This would be implemented as a custom script | |
| echo "✅ Security headers check completed" | |
| # Upload security scan results | |
| - name: Upload security scan results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: security-scan-results | |
| path: | | |
| .zap/ | |
| codeql-results/ | |
| retention-days: 30 | |
| # Database Migration Tests | |
| database-test: | |
| name: Database Tests | |
| runs-on: ubuntu-latest | |
| needs: test | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_PASSWORD: postgres | |
| POSTGRES_DB: test_db | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run database tests | |
| run: npm run test -- --testPathPattern=database --passWithNoTests | |
| env: | |
| DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db | |
| NODE_ENV: test | |
| # Deploy to Staging | |
| deploy-staging: | |
| name: Deploy to Staging | |
| runs-on: ubuntu-latest | |
| needs: [build, security-test, database-test] | |
| if: github.ref == 'refs/heads/develop' | |
| environment: staging | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install Vercel CLI | |
| run: npm install -g vercel@latest | |
| - name: Deploy to Vercel (Staging) | |
| run: | | |
| # Remove any existing .vercel directory to avoid conflicts | |
| rm -rf .vercel | |
| # Deploy directly with project ID (no linking required) | |
| vercel --token ${{ secrets.VERCEL_TOKEN }} --yes --project ${{ secrets.VERCEL_PROJECT_ID }} | |
| env: | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| - name: Run smoke tests | |
| run: | | |
| sleep 30 | |
| curl -f ${{ secrets.STAGING_URL }}/api/health || exit 1 | |
| # Deploy to Production | |
| deploy-production: | |
| name: Deploy to Production | |
| runs-on: ubuntu-latest | |
| needs: [build, security-test, database-test] | |
| if: github.ref == 'refs/heads/main' | |
| environment: production | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install Vercel CLI | |
| run: npm install -g vercel@latest | |
| - name: Deploy to Vercel (Production) | |
| run: | | |
| # Remove any existing .vercel directory to avoid conflicts | |
| rm -rf .vercel | |
| # Deploy directly with project ID (no linking required) | |
| vercel --prod --token ${{ secrets.VERCEL_TOKEN }} --yes --project ${{ secrets.VERCEL_PROJECT_ID }} | |
| env: | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| - name: Run production health check | |
| run: | | |
| sleep 30 | |
| curl -f ${{ secrets.PRODUCTION_URL }}/api/health || exit 1 | |
| - name: Notify deployment success via email | |
| run: | | |
| curl -X POST "https://api.resend.com/emails" \ | |
| -H "Authorization: Bearer ${{ secrets.RESEND_API_KEY }}" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{\"from\":\"alerts@codeunia.com\",\"to\":[\"connect@codeunia.com\"],\"subject\":\"🚀 Production Deployment Successful\",\"html\":\"<h2>Production Deployment Successful</h2><p>Your Codeunia application has been successfully deployed to production.</p><p><strong>Branch:</strong> ${{ github.ref_name }}</p><p><strong>Commit:</strong> ${{ github.sha }}</p><p><strong>Deployed by:</strong> ${{ github.actor }}</p>\"}" | |
| # Rollback on Failure | |
| rollback: | |
| name: Rollback on Failure | |
| runs-on: ubuntu-latest | |
| needs: [deploy-production] | |
| if: failure() | |
| environment: production | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Rollback deployment | |
| run: | | |
| # Create .vercel directory and project.json to link the project | |
| mkdir -p .vercel | |
| echo '{"orgId":"${{ secrets.VERCEL_ORG_ID }}","projectId":"${{ secrets.VERCEL_PROJECT_ID }}"}' > .vercel/project.json | |
| # Perform rollback | |
| npx vercel rollback --token ${{ secrets.VERCEL_TOKEN }} --yes | |
| env: | |
| VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | |
| VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | |
| - name: Notify rollback via email | |
| run: | | |
| curl -X POST "https://api.resend.com/emails" \ | |
| -H "Authorization: Bearer ${{ secrets.RESEND_API_KEY }}" \ | |
| -H "Content-Type: application/json" \ | |
| -d "{\"from\":\"alerts@codeunia.com\",\"to\":[\"connect@codeunia.com\"],\"subject\":\"⚠️ Production Deployment Failed - Rollback Initiated\",\"html\":\"<h2>Production Deployment Failed</h2><p>Your Codeunia application deployment failed and rollback has been initiated.</p><p><strong>Branch:</strong> ${{ github.ref_name }}</p><p><strong>Commit:</strong> ${{ github.sha }}</p><p><strong>Failed by:</strong> ${{ github.actor }}</p><p><strong>Action:</strong> Please check the deployment logs and fix the issues.</p>\"}" | |
| # Performance Monitoring | |
| performance: | |
| name: Performance Monitoring | |
| runs-on: ubuntu-latest | |
| needs: deploy-production | |
| if: github.ref == 'refs/heads/main' | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run Lighthouse CI | |
| run: | | |
| npm install -g @lhci/cli@0.12.x | |
| lhci autorun | |
| env: | |
| LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} | |
| - name: Upload performance results | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: lighthouse-results | |
| path: .lighthouseci/ | |
| retention-days: 30 |