@@ -309,6 +309,28 @@ jobs:
309309 cache-from : type=gha,scope=dashboard
310310 cache-to : type=gha,scope=dashboard,mode=max
311311
312+ - name : Generate docker-compose artifact
313+ shell : bash
314+ run : |
315+ set -euo pipefail
316+ echo "Preparing docker-compose artifact from published images..."
317+ mkdir -p ./artifacts/compose
318+ export GHCR_OWNER="${{ github.repository_owner }}"
319+ export GHCR_REPO="${{ github.event.repository.name }}"
320+ export IMAGE_TAG="${{ needs.build.outputs.version }}"
321+ docker compose version || true
322+ docker compose -f docker-compose.yml -f docker-compose.images.yml config > ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml
323+ cp ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml ./artifacts/compose/docker-compose.yml
324+ echo "Resolved compose generated at ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml (and copied as docker-compose.yml)"
325+ head -n 50 ./artifacts/compose/docker-compose-${{ needs.build.outputs.version }}.yml || true
326+
327+ - name : Upload docker-compose artifact
328+ uses : actions/upload-artifact@v4
329+ with :
330+ name : docker-compose-${{ needs.build.outputs.version }}
331+ path : ./artifacts/compose/
332+ retention-days : 30
333+
312334 scan-and-sbom :
313335 runs-on : ubuntu-latest
314336 needs : [publish-containers, build]
@@ -386,15 +408,15 @@ jobs:
386408 - name : Upload Trivy SARIF to code scanning
387409 uses : github/codeql-action/upload-sarif@v3
388410 with :
389- sarif_file : trivy-${{ matrix.component }}.sarif
390- category : trivy-${{ matrix.component }}
411+ sarif_file : " trivy-${{ matrix.component }}.sarif"
412+ category : " trivy-${{ matrix.component }}"
391413
392414 - name : Upload Trivy SARIF as artifact
393415 uses : actions/upload-artifact@v4
394416 with :
395- name : trivy-sarif-${{ matrix.component }}
396- path : trivy-${{ matrix.component }}.sarif
397- retention-days : 14
417+ name : " trivy-sarif-${{ matrix.component }}"
418+ path : " trivy-${{ matrix.component }}.sarif"
419+ retention-days : " 14 "
398420
399421 - name : Generate SBOM (CycloneDX)
400422 uses : anchore/sbom-action@v0
@@ -404,6 +426,68 @@ jobs:
404426 upload-artifact : true
405427 artifact-name : sbom-${{ matrix.component }}
406428
429+ - name : Trivy SBOM (CycloneDX JSON)
430+ uses :
aquasecurity/[email protected] 431+ with :
432+ image-ref : ${{ steps.vars.outputs.image }}
433+ format : ' cyclonedx'
434+ output : trivy-sbom-${{ matrix.component }}.cdx.json
435+ exit-code : ' 0'
436+ env :
437+ TRIVY_USERNAME : ${{ github.actor }}
438+ TRIVY_PASSWORD : ${{ secrets.GITHUB_TOKEN }}
439+
440+ - name : Render Trivy SBOM summary (markdown)
441+ id : sbom-summary
442+ shell : bash
443+ run : |
444+ FILE="trivy-sbom-${{ matrix.component }}.cdx.json"
445+ OUT="sbom-summary-${{ matrix.component }}.md"
446+
447+ echo "# SBOM Summary - ${{ matrix.component }}" > "$OUT"
448+ echo "" >> "$OUT"
449+ echo "- Image: ${{ steps.vars.outputs.image }}" >> "$OUT"
450+ echo "- Components: $(jq -r '(.components // []) | length' "$FILE" 2>/dev/null || echo 0)" >> "$OUT"
451+
452+ echo "" >> "$OUT"
453+ echo "## Counts by type" >> "$OUT"
454+ echo "" >> "$OUT"
455+ echo "| Type | Count |" >> "$OUT"
456+ echo "|------|-------|" >> "$OUT"
457+ jq -r '(.components // []) | sort_by(.type // "unknown") | group_by(.type) | map({k:(.[0].type // "unknown"), c:length}) | .[] | "| \(.k) | \(.c) |"' "$FILE" 2>/dev/null >> "$OUT" || true
458+
459+ echo "" >> "$OUT"
460+ echo "## Sample components (first 20)" >> "$OUT"
461+ echo "" >> "$OUT"
462+ echo "| Name | Version | Type | License |" >> "$OUT"
463+ echo "|------|---------|------|---------|" >> "$OUT"
464+ jq -r '(.components // []) | sort_by(.name) | .[0:20] | .[] | "| \(.name // "-") | \(.version // "-") | \(.type // "-") | \(((.licenses[0].license.id // .licenses[0].license.name) // "-")) |"' "$FILE" 2>/dev/null >> "$OUT" || true
465+
466+ {
467+ echo "## SBOM Summary - ${{ matrix.component }}";
468+ echo "";
469+ cat "$OUT";
470+ } >> "$GITHUB_STEP_SUMMARY"
471+
472+ echo "summary-file=$OUT" >> $GITHUB_OUTPUT
473+
474+ - name : Upload SBOM summary and JSON
475+ uses : actions/upload-artifact@v4
476+ with :
477+ name : trivy-sbom-${{ matrix.component }}
478+ path : |
479+ trivy-sbom-${{ matrix.component }}.cdx.json
480+ sbom-summary-${{ matrix.component }}.md
481+ retention-days : 14
482+
483+ - name : Comment SBOM summary on PR
484+ if : github.event_name == 'pull_request'
485+ uses : peter-evans/create-or-update-comment@v4
486+ with :
487+ issue-number : ${{ github.event.pull_request.number }}
488+ body-file : ${{ steps.sbom-summary.outputs.summary-file }}
489+ edit-mode : replace
490+
407491 # Notification Job
408492 notify :
409493 runs-on : ubuntu-latest
0 commit comments