Skip to content

feat(docker): generuj SBOM (CycloneDX 1.6) w build, upload jako workflow artifact#181

Closed
mpasternak wants to merge 1 commit into
devfrom
security/sbom-generation
Closed

feat(docker): generuj SBOM (CycloneDX 1.6) w build, upload jako workflow artifact#181
mpasternak wants to merge 1 commit into
devfrom
security/sbom-generation

Conversation

@mpasternak
Copy link
Copy Markdown
Member

Podsumowanie

PR 9/12 z serii pypi-security-best-practices — praktyka #15: Generate and Track SBOMs.

Co się zmienia

docker/bpp_base/Dockerfile

Builder stage (po uv pip uninstall matplotlib):

RUN --mount=type=cache,target=/root/.cache/uv,id=uv-cache \
    uvx --from cyclonedx-bom cyclonedx-py environment \
        /app/.venv \
        --output-format JSON \
        --output-file /app/sbom.json

uvx pulluje cyclonedx-bom ephemeral — nie zostaje w obrazie, tylko
sbom.json (~50-100 KB) idzie do runtime stage przez COPY --from=builder.

Runtime stage: COPY --from=builder /app/sbom.json ./sbom.json
SBOM dostępny pod /app/sbom.json w każdym obrazie wynikowym
(bpp_appserver, bpp_workerserver itd.).

.github/workflows/build-docker-images.yml

Nowa FAZA 4 po promote staging→canonical:

  1. docker pull + docker create + docker cp /app/sbom.json
  2. actions/upload-artifact (SHA-pinned) → workflow artifact
    sbom-<final_tag> z 90-dniową retencją.
  3. Fallback dla obrazów sprzed tego PR (brak /app/sbom.json):
    warning, bez fail (graceful degradation).

Use cases

Impact assessment przy nowym CVE

# Sprawdz czy production ma vulnerabe wersje:
docker run --rm iplweb/bpp_appserver:latest \
  cat /app/sbom.json | jq '.components[] | select(.name == "jaraco.context") | .version'

Forensic analysis

# Pobierz SBOM z konkretnego release:
gh run download <run-id> -n sbom-202604.1363
jq '.components | length' sbom.json

Co to NIE jest

  • To NIE jest signed attestation (Sigstore/in-toto). To jest "snapshot
    inwentaryzacji" — pomaga w impact assessment, nie udowadnia tożsamości.
    Sigstore byłby kolejnym PR-em ale jest poza scope tej serii (BPP nie
    jest publishowany na PyPI).
  • To NIE jest SBOM dla całego image (z apt-owymi pakietami systemowymi) —
    tylko dla Python deps. Trivy już skanuje warstwę systemową.

Plan testowy

  • Lokalne uvx --from cyclonedx-bom cyclonedx-py environment .venv
    Components: 240, format: CycloneDX 1.6, valid JSON.
  • actionlint passed.
  • Po mergeu: pierwszy Docker build powinien wygenerować artifact
    sbom-<tag> widoczny w Actions UI.
  • Po download artifactu: walidacja JSON i counts components.

🤖 Generated with Claude Code

Praktyka #15 z lirantal/pypi-security-best-practices (Generate SBOMs).

Dockerfile (builder stage):
- Po `uv pip uninstall matplotlib` (R6) generujemy sbom.json przez
  `uvx --from cyclonedx-bom cyclonedx-py environment /app/.venv`.
- uvx ephemeral - cyclonedx-bom nie zostaje w obrazie, tylko sbom.json
  (~50-100 KB) idzie do runtime stage przez COPY --from=builder.

Runtime stage:
- COPY --from=builder /app/sbom.json ./sbom.json - SBOM jest dostepny
  pod sciezka `/app/sbom.json` w kazdym obrazie (bpp_base, bpp_appserver
  itd. - wszystkie ekstendują z tego samego runtime layer).

build-docker-images.yml (FAZA 4 - po promote):
- Pull obrazu, docker create + docker cp /app/sbom.json
- Upload jako workflow artifact "sbom-<final_tag>", 90-dniowa retencja
- Fallback dla starych obrazow (sprzed tego PR-a): warning bez fail
- actions/upload-artifact pinowane na SHA (zgodnie z PR #176)

Use case:
  # Przy disclosure nowego CVE szybkie sprawdzenie czy production ma vuln:
  docker run --rm iplweb/bpp_appserver:latest \
    cat /app/sbom.json | jq '.components[] | select(.name == "<pkg>")'

  # Lub pobranie z workflow artifacts dla forensic analizy historycznej:
  gh run download <run-id> -n sbom-<version>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant