Skip to content

deps(deps): update uvicorn[standard] requirement from >=0.46.0 to >=0.47.0 #98

deps(deps): update uvicorn[standard] requirement from >=0.46.0 to >=0.47.0

deps(deps): update uvicorn[standard] requirement from >=0.46.0 to >=0.47.0 #98

# 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: pip-audit (PyPA-official, autorzy pip-a). Wczesniej uzywalismy
# uv-secure ale projekt zostal zarchiwizowany 18 kwietnia 2026 (read-only
# repo, ostatnie release v0.17.2). Stale CVE database = false sense of
# security. pip-audit jest aktywnie maintained przez PyPA i czyta z tego
# samego PyPI Advisory DB co uv-secure.
#
# uv.lock -> requirements.txt przez `uv export --no-dev` (jak w multi-scanner).
#
# Polityka:
# - Vulnerability z fix-em dostepnym (fix_versions non-empty): failure.
# pip-audit nie ma natywnego severity filter, ale fix-availability juz
# jest dobrym proxy: jezeli upstream wypuscil fix, znaczy ze warto bumpnac.
# - Vuln bez fixa: warning w job summary, nie blokuje (nic nie da sie zrobic).
# - Whitelist znanych non-impact CVE przez --ignore-vuln (patrz job ponizej).
#
# Defense-in-depth: drugi job (multi-scanner) odpala OSV-Scanner, Grype
# i Trivy na SBOM-ie wygenerowanym z uv.lock. Wszystkie report-only -
# pip-audit 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:
pip-audit:
name: pip-audit 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: Export uv.lock -> requirements.txt (prod-only)
run: |
mkdir -p /tmp/audit
uv export --no-dev --format requirements-txt --no-hashes --quiet \
-o /tmp/audit/requirements.txt
# Whitelist znanych non-impact CVE.
# ---
# CVE-2026-42304 / GHSA-grgv-6hw6-v9g4 (twisted < 26.4.0rc2):
# DoS w twisted.names.dns.Name.decode przez glebokie DNS compression
# pointer chains. BPP NIE uruchamia DNS-servera Twisted (twisted jest
# transitive zaleznoscia daphne + autobahn dla WebSocket/Channels,
# bez modulu twisted.names). Fix dostepny tylko w 26.4.0rc2 (release
# candidate) - nie wprowadzamy RC do produkcji do czasu stable release.
# Re-evaluate przy bumpie twisted do 26.x stable.
- name: Run pip-audit (gate on fixable)
run: |
uvx --from pip-audit pip-audit \
--requirement /tmp/audit/requirements.txt \
--disable-pip \
--no-deps \
--format columns \
--ignore-vuln CVE-2026-42304
- name: Run pip-audit (JSON full report - non-blocking)
if: always()
run: |
uvx --from pip-audit pip-audit \
--requirement /tmp/audit/requirements.txt \
--disable-pip \
--no-deps \
--format json \
--output /tmp/audit/full.json || true
{
echo "## pip-audit full report"
echo ""
count=$(jq '[.dependencies[]?.vulns[]?] | length' \
/tmp/audit/full.json 2>/dev/null || echo 0)
if [ "$count" -gt 0 ]; then
echo "Znaleziono **$count** vulnerabilities (vs gate-policy)."
echo ""
echo '| Pakiet | Wersja | CVE | Fix versions |'
echo '|---|---|---|---|'
jq -r '
.dependencies[]? | . as $p |
.vulns[]? |
"| \($p.name) | \($p.version) | \(.id) | \(.fix_versions | join(", ")) |"
' /tmp/audit/full.json | sort -u
else
echo "Brak findings."
fi
} >> "$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