build(deps-dev): bump pygments from 2.19.2 to 2.20.0 #38
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
| # SkyLink CI/CD Pipeline | |
| # See docs/GITHUB_CI_SETUP.md for configuration instructions | |
| name: SkyLink CI/CD | |
| on: | |
| push: | |
| branches: [main, master, develop] | |
| pull_request: | |
| branches: [main, master] | |
| release: | |
| types: [published] | |
| env: | |
| REGISTRY: ghcr.io | |
| IMAGE_NAME: ${{ github.repository }} | |
| PYTHON_VERSION: "3.12" | |
| jobs: | |
| # ============================================ | |
| # LINT | |
| # ============================================ | |
| lint: | |
| name: Lint & Security Check | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install linters | |
| run: pip install ruff black bandit | |
| - name: Run Ruff | |
| run: ruff check . | |
| - name: Run Black | |
| run: black --check . | |
| - name: Run Bandit | |
| run: bandit -r skylink -q --severity-level high | |
| # ============================================ | |
| # TEST | |
| # ============================================ | |
| test: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Poetry | |
| uses: snok/install-poetry@v1 | |
| with: | |
| virtualenvs-create: true | |
| virtualenvs-in-project: true | |
| - name: Cache dependencies | |
| uses: actions/cache@v4 | |
| with: | |
| path: .venv | |
| key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }} | |
| - name: Install dependencies | |
| run: poetry install --no-interaction | |
| - name: Generate test certificates | |
| run: | | |
| chmod +x scripts/generate_test_certs.sh | |
| ./scripts/generate_test_certs.sh || echo "Certificate generation skipped" | |
| - name: Run tests | |
| env: | |
| PRIVATE_KEY_PEM: ${{ secrets.PRIVATE_KEY_PEM }} | |
| PUBLIC_KEY_PEM: ${{ secrets.PUBLIC_KEY_PEM }} | |
| run: | | |
| poetry run pytest -q \ | |
| --junitxml=report.xml \ | |
| --cov=skylink \ | |
| --cov-report=xml \ | |
| --cov-report=term-missing \ | |
| --cov-fail-under=75 | |
| - name: Upload coverage to Codecov | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| files: coverage.xml | |
| fail_ci_if_error: false | |
| - name: Upload test results | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: test-results | |
| path: report.xml | |
| # ============================================ | |
| # SECRET SCANNING (Gitleaks) | |
| # ============================================ | |
| gitleaks: | |
| name: Secret Scanning | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Run Gitleaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # ============================================ | |
| # SCA (Dependency Audit) | |
| # ============================================ | |
| sca: | |
| name: Dependency Audit | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install Poetry and pip-audit | |
| run: | | |
| pip install poetry pip-audit poetry-plugin-export | |
| poetry self add poetry-plugin-export || true | |
| - name: Export requirements | |
| run: poetry export -f requirements.txt --only main --without-hashes -o requirements.txt | |
| - name: Run pip-audit | |
| run: pip-audit -r requirements.txt --strict | |
| # ============================================ | |
| # OPENAPI VALIDATION | |
| # ============================================ | |
| openapi: | |
| name: OpenAPI Validation | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Validate OpenAPI specs | |
| run: | | |
| docker run --rm -v ${{ github.workspace }}:/local \ | |
| openapitools/openapi-generator-cli:latest validate \ | |
| -i /local/openapi/gateway.yaml | |
| # ============================================ | |
| # BUILD & PUSH | |
| # ============================================ | |
| build: | |
| name: Build & Push Image | |
| runs-on: ubuntu-latest | |
| needs: [lint, test, gitleaks, sca] | |
| permissions: | |
| contents: read | |
| packages: write | |
| outputs: | |
| image_tag: ${{ steps.short_sha.outputs.sha }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Get short SHA | |
| id: short_sha | |
| run: echo "sha=$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
| tags: | | |
| type=sha,prefix= | |
| type=ref,event=branch | |
| type=semver,pattern={{version}} | |
| type=raw,value=latest,enable={{is_default_branch}} | |
| - name: Build and push | |
| id: build | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: ./Dockerfile.gateway | |
| push: true | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| # ============================================ | |
| # TRIVY SCAN | |
| # ============================================ | |
| trivy: | |
| name: Container Scan (Trivy) | |
| runs-on: ubuntu-latest | |
| needs: [build] | |
| permissions: | |
| contents: read | |
| packages: read | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Pull image | |
| run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} | |
| - name: Run Trivy vulnerability scanner | |
| uses: aquasecurity/trivy-action@master | |
| with: | |
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} | |
| format: 'table' | |
| severity: 'HIGH,CRITICAL' | |
| exit-code: '0' | |
| # ============================================ | |
| # SBOM | |
| # ============================================ | |
| sbom: | |
| name: Generate SBOM | |
| runs-on: ubuntu-latest | |
| needs: [test] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| - name: Install tools | |
| run: | | |
| pip install poetry cyclonedx-bom poetry-plugin-export | |
| poetry self add poetry-plugin-export || true | |
| - name: Export requirements | |
| run: poetry export -f requirements.txt --without-hashes -o requirements.txt | |
| - name: Generate SBOM | |
| run: python -m cyclonedx_py requirements -i requirements.txt -o sbom.json | |
| - name: Upload SBOM | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbom | |
| path: sbom.json | |
| # ============================================ | |
| # DAST (ZAP Scan) | |
| # ============================================ | |
| zap: | |
| name: DAST (ZAP Scan) | |
| runs-on: ubuntu-latest | |
| needs: [build] | |
| permissions: | |
| contents: read | |
| packages: read | |
| continue-on-error: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Pull and start application | |
| run: | | |
| docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} | |
| docker run -d --name skylink -p 8000:8000 \ | |
| -e DEMO_MODE=true \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} | |
| # Wait for app to be ready | |
| echo "Waiting for application to start..." | |
| for i in {1..30}; do | |
| if curl -sf http://localhost:8000/health > /dev/null 2>&1; then | |
| echo "Application is ready!" | |
| break | |
| fi | |
| echo "Waiting for application... ($i/30)" | |
| sleep 2 | |
| done | |
| # Final check | |
| curl -sf http://localhost:8000/health || (docker logs skylink && exit 1) | |
| - name: Run ZAP Baseline Scan | |
| run: | | |
| docker run --rm --network host \ | |
| -v ${{ github.workspace }}:/zap/wrk:rw \ | |
| ghcr.io/zaproxy/zaproxy:stable \ | |
| zap-baseline.py -t http://localhost:8000 \ | |
| -r zap-report.html -I || true | |
| - name: Upload ZAP Report | |
| uses: actions/upload-artifact@v4 | |
| if: always() | |
| with: | |
| name: zap-report | |
| path: zap-report.html | |
| if-no-files-found: ignore | |
| - name: Stop application | |
| if: always() | |
| run: docker stop skylink || true | |
| # ============================================ | |
| # SIGN IMAGE (Cosign) | |
| # ============================================ | |
| sign: | |
| name: Sign Image | |
| runs-on: ubuntu-latest | |
| needs: [build, trivy] | |
| if: github.event_name != 'pull_request' | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Sign image with keyless signing (Sigstore) | |
| run: | | |
| cosign sign --yes \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} | |
| # ============================================ | |
| # ATTEST SBOM | |
| # ============================================ | |
| attest: | |
| name: Attest SBOM | |
| runs-on: ubuntu-latest | |
| needs: [build, sign, sbom] | |
| if: github.event_name != 'pull_request' | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Cosign | |
| uses: sigstore/cosign-installer@v3 | |
| - name: Download SBOM | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: sbom | |
| - name: Log in to Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ${{ env.REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Attest SBOM with keyless signing | |
| run: | | |
| cosign attest --yes \ | |
| --predicate sbom.json --type cyclonedx \ | |
| ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ needs.build.outputs.image_tag }} |