# CI/CD Pipeline ## Platform GitHub Actions (default recommendation; adaptable to Azure Pipelines). ## Pipeline Stages | Stage | Trigger | Steps | Quality Gate | |-------|---------|-------|-------------| | Lint | Every push | `black --check`, Cython syntax check | Zero errors | | Unit Test | Every push | `pytest tests/ -v --csv=report.csv` | All pass | | Security Scan | Every push | `pip-audit`, Trivy image scan | Zero critical/high CVEs | | Build | PR merge to dev | Build `detections-cpu` and `detections-gpu` images, tag with git SHA | Build succeeds | | E2E Test | After build | `docker compose -f e2e/docker-compose.test.yml up --abort-on-container-exit` | All e2e tests pass | | Push | After e2e | Push images to container registry | Push succeeds | | Deploy Staging | After push | Deploy to staging via `scripts/deploy.sh` | Health check passes | | Deploy Production | Manual approval | Deploy to production via `scripts/deploy.sh` | Health check passes | ## Workflow Definition (GitHub Actions) ```yaml name: CI/CD on: push: branches: [dev, main] pull_request: branches: [dev] env: REGISTRY: ${{ secrets.REGISTRY }} jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install black - run: black --check src/ tests/ test: runs-on: ubuntu-latest needs: lint steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install -r requirements.txt - run: python setup.py build_ext --inplace - run: cd src && pytest ../tests/ -v security: runs-on: ubuntu-latest needs: lint steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: "3.11" - run: pip install pip-audit - run: pip-audit -r requirements.txt build: runs-on: ubuntu-latest needs: [test, security] if: github.event_name == 'push' steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.REGISTRY_USER }} password: ${{ secrets.REGISTRY_PASSWORD }} - uses: docker/build-push-action@v5 with: context: . file: Dockerfile push: true tags: ${{ env.REGISTRY }}/azaion/detections-cpu:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max e2e: runs-on: ubuntu-latest needs: build steps: - uses: actions/checkout@v4 - run: | cd e2e COMPOSE_PROFILES=cpu docker compose -f docker-compose.test.yml up \ --build --abort-on-container-exit --exit-code-from e2e-runner deploy-staging: runs-on: ubuntu-latest needs: e2e if: github.ref == 'refs/heads/dev' environment: staging steps: - uses: actions/checkout@v4 - run: | IMAGE_TAG=${{ github.sha }} \ DEPLOY_HOST=${{ secrets.STAGING_HOST }} \ DEPLOY_USER=${{ secrets.STAGING_USER }} \ bash scripts/deploy.sh deploy-production: runs-on: ubuntu-latest needs: e2e if: github.ref == 'refs/heads/main' environment: name: production url: ${{ secrets.PRODUCTION_URL }} steps: - uses: actions/checkout@v4 - run: | IMAGE_TAG=${{ github.sha }} \ DEPLOY_HOST=${{ secrets.PRODUCTION_HOST }} \ DEPLOY_USER=${{ secrets.PRODUCTION_USER }} \ bash scripts/deploy.sh ``` ## Caching Strategy | Cache Type | Scope | Tool | |-----------|-------|------| | Python dependencies | Per requirements.txt hash | actions/cache + pip cache dir | | Docker layers | Per Dockerfile hash | BuildKit GHA cache | | Cython compiled modules | Per src/ hash | actions/cache | ## Parallelization - `test` and `security` jobs run in parallel after `lint` - `build` waits for both `test` and `security` - GPU image build can be added as a parallel job to CPU build ## Notifications | Event | Channel | |-------|---------| | Build failure | GitHub PR status check (blocks merge) | | Security scan failure | GitHub PR status check + team notification | | Deployment success/failure | Deployment environment status |