name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] env: PYTHON_VERSION: "3.13" NODE_VERSION: "18" jobs: # Code Quality Checks lint: name: Code Quality runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install ruff bandit - name: Run Ruff linter run: ruff check src/ - name: Run Bandit security scan run: bandit -r src/ -f json -o bandit-report.json - name: Upload security report uses: actions/upload-artifact@v3 if: always() with: name: security-report path: bandit-report.json # Tests test: name: Test Suite runs-on: ubuntu-latest strategy: matrix: python-version: ["3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Cache pip dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install pytest pytest-cov pytest-asyncio - name: Run tests with coverage run: | pytest tests/ \ --cov=src \ --cov-report=xml \ --cov-report=html \ --cov-fail-under=50 \ -v - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 if: matrix.python-version == env.PYTHON_VERSION with: file: ./coverage.xml flags: unittests name: codecov-umbrella - name: Upload coverage report uses: actions/upload-artifact@v3 with: name: coverage-report-${{ matrix.python-version }} path: htmlcov/ # Integration Tests integration: name: Integration Tests runs-on: ubuntu-latest needs: [lint, test] services: opensearch: image: opensearchproject/opensearch:2.11.1 env: discovery.type: single-node OPENSEARCH_INITIAL_ADMIN_PASSWORD: StrongPassword123! options: >- --health-cmd "curl -sf http://localhost:9200/_cluster/health" --health-interval 10s --health-timeout 5s --health-retries 10 ports: - 9200:9200 redis: image: redis:7-alpine options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 6379:6379 steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run integration tests env: OPENSEARCH_HOST: localhost OPENSEARCH_PORT: 9200 REDIS_HOST: localhost REDIS_PORT: 6379 run: | pytest tests/test_integration.py -v - name: Test API endpoints run: | python -m src.main & sleep 10 curl -f http://localhost:8000/health || exit 1 curl -f http://localhost:8000/docs || exit 1 # Build Docker Image build: name: Build Docker Image runs-on: ubuntu-latest needs: [lint, test] if: github.event_name == 'push' steps: - uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub if: github.ref == 'refs/heads/main' uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: mediguard-ai tags: | type=ref,event=branch type=ref,event=pr type=sha,prefix={{branch}}- type=raw,value=latest,enable={{is_default_branch}} - name: Build and push uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile target: production push: ${{ github.ref == 'refs/heads/main' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # Security Scan security: name: Security Scan runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.13' - name: Install dependencies run: | pip install bandit safety semgrep trivy gitleaks pip install -r requirements.txt - name: Run Bandit security scan run: | bandit -r src/ -f json -o bandit-report.json || true bandit -r src/ - name: Run Safety dependency check run: | safety check --json --output safety-report.json || true safety check - name: Run Semgrep run: | semgrep --config=p/security-audit --json --output semgrep-report.json src/ || true semgrep --config=p/security-audit src/ - name: Run Gitleaks run: | gitleaks detect --source . --report-format json --report-path gitleaks-report.json || true gitleaks detect --source . --verbose - name: Run Trivy filesystem scan run: | trivy fs --format json --output trivy-report.json src/ || true trivy fs src/ - name: Run custom security scan run: | python scripts/security_scan.py --scan all - name: Upload security reports uses: actions/upload-artifact@v3 if: always() with: name: security-reports path: | security-reports/ *.json retention-days: 30 # Deploy to Staging deploy-staging: name: Deploy to Staging runs-on: ubuntu-latest needs: [integration, build] if: github.ref == 'refs/heads/develop' environment: staging steps: - uses: actions/checkout@v4 - name: Deploy to staging run: | echo "Deploying to staging environment..." # Add deployment script here # Deploy to Production deploy-production: name: Deploy to Production runs-on: ubuntu-latest needs: [integration, build, security] if: github.ref == 'refs/heads/main' environment: production steps: - uses: actions/checkout@v4 - name: Deploy to production run: | echo "Deploying to production environment..." # Add deployment script here - name: Run smoke tests run: | echo "Running smoke tests..." # Add smoke tests here