chore(deps): pull django-countdown and pytest-testcontainers-django f… #86
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
| # Workflow: skanowanie znanych podatnosci w zaleznosciach (uv.lock). | |
| # Praktyka #6 z lirantal/pypi-security-best-practices. | |
| # | |
| # Triggers: | |
| # - push do dev/master: kazda zmiana w lockfile sprawdza sie od razu | |
| # - pull_request: PR-y dotykajace zaleznosci nie merguja sie z aktywnym CVE | |
| # - weekly cron: nowo-disclosed CVE wykryte tez na "spokojnym" lockfile | |
| # | |
| # Tool: uv-secure (natively reads uv.lock z hashami SHA-256, lepszy | |
| # match dla naszego setupu niz pip-audit ktory potrzebuje requirements.txt). | |
| # | |
| # Polityka: | |
| # - HIGH/CRITICAL z dostepnym fix-em: failure (musi byc PR podbijajacy dep) | |
| # - LOW/MEDIUM: warning w job summary, nie blokuje | |
| # - --ignore-unfixed: nie blokujemy na CVE bez fix-a (nie da sie nic zrobic) | |
| # | |
| # Defense-in-depth: drugi job (multi-scanner) odpala OSV-Scanner, Grype | |
| # i Trivy na SBOM-ie wygenerowanym z uv.lock. Wszystkie report-only - | |
| # uv-secure pozostaje jedynym gate-em release-u. | |
| name: Dependency vulnerability scan | |
| on: | |
| push: | |
| branches: [dev, master] | |
| paths: | |
| - "uv.lock" | |
| - "pyproject.toml" | |
| - ".github/workflows/dependency-audit.yml" | |
| pull_request: | |
| paths: | |
| - "uv.lock" | |
| - "pyproject.toml" | |
| schedule: | |
| # poniedzialek 06:00 UTC - po Dependabot weekly run, wylapuje | |
| # CVE ktore wyszly w weekend | |
| - cron: "0 6 * * 1" | |
| workflow_dispatch: # manualne uruchomienie z UI | |
| permissions: | |
| contents: read | |
| jobs: | |
| uv-secure: | |
| name: uv-secure scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | |
| - name: Run uv-secure (HIGH+CRITICAL gate) | |
| run: | | |
| uvx --from uv-secure uv-secure \ | |
| --severity high \ | |
| --ignore-unfixed \ | |
| --no-desc \ | |
| uv.lock | |
| - name: Run uv-secure (full report - non-blocking) | |
| if: always() | |
| run: | | |
| # Pelny raport ze wszystkimi findings (LOW/MEDIUM tez) jako | |
| # job summary - nie failuje workflow, ale daje widocznosc. | |
| { | |
| echo "## uv-secure full report" | |
| echo "" | |
| echo '```' | |
| uvx --from uv-secure uv-secure \ | |
| --show-severity \ | |
| --no-desc \ | |
| uv.lock || true | |
| echo '```' | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| # Defense-in-depth: trzy dodatkowe skanery (OSV/Grype/Trivy) na SBOM | |
| # wygenerowanym z uv.lock. Kazdy z innej bazy CVE - lapia rozne | |
| # rzeczy niz uv-secure (osv.dev, anchore, aquasecurity vs PyPA-DB). | |
| # WSZYSTKIE w trybie report-only (continue-on-error: true) - jedynym | |
| # gate-em release-u pozostaje uv-secure powyzej. Multi-scanner ma dac | |
| # WIDOCZNOSC, nie zablokowac merga falszywym pozytywem z roznicy baz. | |
| multi-scanner: | |
| name: Multi-scanner (OSV / Grype / Trivy) — report-only | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0 | |
| - name: Generate SBOM (CycloneDX, prod-only) | |
| run: | | |
| mkdir -p /tmp/sbom | |
| uv export --no-dev --format requirements-txt --no-hashes --quiet \ | |
| -o /tmp/sbom/requirements.txt | |
| uvx --quiet --from cyclonedx-bom cyclonedx-py requirements \ | |
| /tmp/sbom/requirements.txt \ | |
| --output-reproducible \ | |
| --output-format JSON \ | |
| --output-file /tmp/sbom/sbom.json \ | |
| --pyproject pyproject.toml | |
| echo "Pakietow w SBOM: $(jq '.components | length' /tmp/sbom/sbom.json)" | |
| - name: Install scanners | |
| run: | | |
| # OSV-Scanner (Google) - binarka GitHub release | |
| curl -sSL -o /usr/local/bin/osv-scanner \ | |
| https://github.com/google/osv-scanner/releases/latest/download/osv-scanner_linux_amd64 | |
| chmod +x /usr/local/bin/osv-scanner | |
| # Grype (Anchore) - oficjalny installer | |
| curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh \ | |
| | sh -s -- -b /usr/local/bin | |
| # Trivy (Aqua) - oficjalny installer | |
| curl -sSfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh \ | |
| | sh -s -- -b /usr/local/bin | |
| - name: OSV-Scanner — wszystkie findings | |
| continue-on-error: true | |
| run: | | |
| osv-scanner scan source --sbom=/tmp/sbom/sbom.json \ | |
| --format=json --output=/tmp/sbom/osv.json 2>/dev/null || true | |
| { | |
| echo "## OSV-Scanner (Google)" | |
| echo "" | |
| count=$(jq '[.results[]?.packages[]?.vulnerabilities[]?] | length' \ | |
| /tmp/sbom/osv.json 2>/dev/null || echo 0) | |
| if [ "$count" -gt 0 ]; then | |
| echo "Znaleziono **$count** vulnerabilities." | |
| echo "" | |
| echo '| Pakiet | CVE |' | |
| echo '|---|---|' | |
| jq -r ' | |
| .results[]? | .packages[]? | . as $p | | |
| .vulnerabilities[]? | | |
| "| \($p.package.name)@\($p.package.version) | \(.id) |" | |
| ' /tmp/sbom/osv.json | sort -u | |
| else | |
| echo "Brak findings." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Grype — HIGH/CRITICAL | |
| continue-on-error: true | |
| run: | | |
| grype "sbom:/tmp/sbom/sbom.json" -o json --file /tmp/sbom/grype.json \ | |
| >/dev/null 2>&1 || true | |
| { | |
| echo "## Grype (Anchore)" | |
| echo "" | |
| count=$(jq '[.matches[]? | select(.vulnerability.severity | test("^(High|Critical)$"; "i"))] | length' \ | |
| /tmp/sbom/grype.json 2>/dev/null || echo 0) | |
| if [ "$count" -gt 0 ]; then | |
| echo "Znaleziono **$count** HIGH/CRITICAL." | |
| echo "" | |
| echo '| Pakiet | CVE | Severity | Fix |' | |
| echo '|---|---|---|---|' | |
| jq -r ' | |
| .matches[]? | | |
| select(.vulnerability.severity | test("^(High|Critical)$"; "i")) | | |
| "| \(.artifact.name)@\(.artifact.version) | \(.vulnerability.id) | \(.vulnerability.severity) | \(.vulnerability.fix.versions[]? // "no-fix") |" | |
| ' /tmp/sbom/grype.json | sort -u | |
| else | |
| echo "Brak findings (HIGH/CRITICAL)." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Trivy — HIGH/CRITICAL z fix-em | |
| continue-on-error: true | |
| run: | | |
| # --ignore-unfixed: wyciszamy CVE bez dostepnego fixa (jak w | |
| # build-docker-images.yml - nic nie mozna zrobic, samo szum). | |
| # --severity HIGH,CRITICAL: bez tego Trivy zglasza wszystko | |
| # ze swojej bardzo agresywnej DB - filter sprowadza to do | |
| # realnie waznych rzeczy. | |
| trivy sbom /tmp/sbom/sbom.json \ | |
| --severity HIGH,CRITICAL \ | |
| --ignore-unfixed \ | |
| --format json \ | |
| --output /tmp/sbom/trivy.json \ | |
| --quiet 2>/dev/null || true | |
| { | |
| echo "## Trivy (Aqua Security)" | |
| echo "" | |
| count=$(jq '[.Results[]?.Vulnerabilities[]?] | length' \ | |
| /tmp/sbom/trivy.json 2>/dev/null || echo 0) | |
| if [ "$count" -gt 0 ]; then | |
| echo "Znaleziono **$count** HIGH/CRITICAL z dostepnym fixem." | |
| echo "" | |
| echo '| Pakiet | CVE | Severity | Fix |' | |
| echo '|---|---|---|---|' | |
| jq -r ' | |
| .Results[]? | .Vulnerabilities[]? | | |
| "| \(.PkgName)@\(.InstalledVersion) | \(.VulnerabilityID) | \(.Severity) | \(.FixedVersion // "no-fix") |" | |
| ' /tmp/sbom/trivy.json | sort -u | |
| else | |
| echo "Brak findings (HIGH/CRITICAL z fix-em)." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Upload SBOM + raporty (artifact, retention 30d) | |
| if: always() | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: dependency-scan-${{ github.run_id }} | |
| path: /tmp/sbom/ | |
| retention-days: 30 |