name: CI/CD - Build & Test on: push: branches: [main, develop] pull_request: branches: [main, develop] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: #------------------------------------------------------------------------------ # Backend Tests #------------------------------------------------------------------------------ backend-tests: name: Backend Tests runs-on: ubuntu-latest services: postgres: image: postgres:15-alpine env: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: mockupaws_test options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 redis: image: redis:7-alpine options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 6379:6379 steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install uv run: | curl -LsSf https://astral.sh/uv/install.sh | sh echo "$HOME/.cargo/bin" >> $GITHUB_PATH - name: Install dependencies run: uv sync - name: Run linting run: | uv run ruff check src/ uv run ruff format src/ --check - name: Run type checking run: uv run mypy src/ --ignore-missing-imports || true - name: Run tests env: DATABASE_URL: postgresql+asyncpg://test:test@localhost:5432/mockupaws_test REDIS_URL: redis://localhost:6379/0 JWT_SECRET_KEY: test-secret-for-ci-only-not-production APP_ENV: test run: | uv run alembic upgrade head uv run pytest --cov=src --cov-report=xml --cov-report=term -v - name: Upload coverage uses: codecov/codecov-action@v3 with: files: ./coverage.xml fail_ci_if_error: false #------------------------------------------------------------------------------ # Frontend Tests #------------------------------------------------------------------------------ frontend-tests: name: Frontend Tests runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Run linting working-directory: frontend run: npm run lint - name: Run type checking working-directory: frontend run: npm run typecheck || npx tsc --noEmit - name: Run unit tests working-directory: frontend run: npm run test -- --coverage --watchAll=false || true - name: Build working-directory: frontend run: npm run build #------------------------------------------------------------------------------ # Security Scans #------------------------------------------------------------------------------ security-scans: name: Security Scans runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' severity: 'CRITICAL,HIGH' - name: Upload Trivy scan results uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: 'trivy-results.sarif' - name: Run GitLeaks uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} continue-on-error: true #------------------------------------------------------------------------------ # Docker Build Test #------------------------------------------------------------------------------ docker-build: name: Docker Build Test runs-on: ubuntu-latest needs: [backend-tests, frontend-tests] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build backend image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile.backend push: false load: true tags: mockupaws-backend:test cache-from: type=gha cache-to: type=gha,mode=max - name: Build frontend image uses: docker/build-push-action@v5 with: context: ./frontend push: false load: true tags: mockupaws-frontend:test cache-from: type=gha cache-to: type=gha,mode=max - name: Test backend image run: | docker run --rm mockupaws-backend:test python -c "import src.main; print('Backend OK')" - name: Scan backend image uses: aquasecurity/trivy-action@master with: image-ref: mockupaws-backend:test format: 'table' exit-code: '1' ignore-unfixed: true severity: 'CRITICAL,HIGH' continue-on-error: true #------------------------------------------------------------------------------ # Infrastructure Validation #------------------------------------------------------------------------------ terraform-validate: name: Terraform Validate runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Terraform uses: hashicorp/setup-terraform@v3 with: terraform_version: "1.5.0" - name: Terraform Format Check working-directory: infrastructure/terraform/environments/prod run: terraform fmt -check -recursive continue-on-error: true - name: Terraform Init working-directory: infrastructure/terraform/environments/prod run: terraform init -backend=false - name: Terraform Validate working-directory: infrastructure/terraform/environments/prod run: terraform validate