From 30b7cacf59ec3c25d778aff46b2364487434374c Mon Sep 17 00:00:00 2001 From: Chris Cavell Date: Tue, 15 Sep 2026 13:02:38 -0500 Subject: [PATCH 1/2] Optimize Trivy container scanning by reusing scan results - scan the release container archive once with Trivy - reuse the JSON scan result for SARIF and SPDX generation - preserve HIGH/CRITICAL fail-closed release gating - reuse Trivy cache while retaining normal database freshness checks - keep all security evidence tied to the exact published image archive Closes #533 --- .github/workflows/publish-container.yml | 55 ++++++++++++++++--------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/.github/workflows/publish-container.yml b/.github/workflows/publish-container.yml index 0ccd823..17e9bac 100644 --- a/.github/workflows/publish-container.yml +++ b/.github/workflows/publish-container.yml @@ -82,22 +82,37 @@ jobs: - name: Prepare release evidence directory run: mkdir -p artifacts/container-release - # The image is exported before scanning so every Trivy step reads the same tar archive. + # The image is exported before scanning so every derived Trivy result comes from the same tar archive. # Scanning the archive is what removes the need to mount /var/run/docker.sock into the scanner. - name: Save built image for scanning env: LOCAL_IMAGE: ${{ steps.version.outputs.local_image }} run: docker save "$LOCAL_IMAGE" --output artifacts/container-image.tar - - name: Generate vulnerability scan SARIF + # Scan the saved release image exactly once. Trivy's action cache persists the + # vulnerability DB and scan cache across runs, while the absence of + # TRIVY_SKIP_DB_UPDATE keeps Trivy's normal database freshness check enabled. + # The JSON report includes the package inventory needed to derive SPDX evidence. + - name: Scan container image once with reusable Trivy state uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 with: input: artifacts/container-image.tar - format: sarif - output: artifacts/container-release/trivy-results.sarif - severity: HIGH,CRITICAL + format: json + output: artifacts/trivy-results.json + list-all-pkgs: true ignore-unfixed: false exit-code: '0' + cache: 'true' + cache-dir: ${{ github.workspace }}/.cache/trivy + + # trivy-action installs Trivy on PATH. Convert the one immutable JSON scan + # instead of rescanning the image archive for each release evidence format. + - name: Generate vulnerability scan SARIF from reusable result + run: > + trivy convert + --format sarif + --output artifacts/container-release/trivy-results.sarif + artifacts/trivy-results.json - name: Upload vulnerability SARIF if: always() @@ -106,13 +121,12 @@ jobs: sarif_file: artifacts/container-release/trivy-results.sarif category: container-image - - name: Generate SPDX SBOM - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - input: artifacts/container-image.tar - format: spdx-json - output: artifacts/container-release/netcoreapplicationtemplate-container-${{ steps.version.outputs.version }}.spdx.json - exit-code: '0' + - name: Generate SPDX SBOM from reusable result + run: > + trivy convert + --format spdx-json + --output artifacts/container-release/netcoreapplicationtemplate-container-${{ steps.version.outputs.version }}.spdx.json + artifacts/trivy-results.json - name: Upload release evidence artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -122,14 +136,15 @@ jobs: if-no-files-found: error retention-days: 30 - - name: Enforce container vulnerability threshold - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - input: artifacts/container-image.tar - format: table - severity: HIGH,CRITICAL - ignore-unfixed: false - exit-code: '1' + # Keep the release gate fail-closed. This evaluates HIGH/CRITICAL findings + # from the exact JSON result produced from artifacts/container-image.tar. + - name: Enforce container vulnerability threshold from reusable result + run: > + trivy convert + --format table + --severity HIGH,CRITICAL + --exit-code 1 + artifacts/trivy-results.json - name: Upload scanned image artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 From 7b40296a418ef71ed1c06c8c65b782f316c7f8bc Mon Sep 17 00:00:00 2001 From: Chris Cavell Date: Tue, 15 Sep 2026 13:07:53 -0500 Subject: [PATCH 2/2] Fix the SPDX generation step to route the release version through `env:` --- .github/workflows/publish-container.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/publish-container.yml b/.github/workflows/publish-container.yml index 17e9bac..718c1b2 100644 --- a/.github/workflows/publish-container.yml +++ b/.github/workflows/publish-container.yml @@ -122,10 +122,12 @@ jobs: category: container-image - name: Generate SPDX SBOM from reusable result + env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} run: > trivy convert --format spdx-json - --output artifacts/container-release/netcoreapplicationtemplate-container-${{ steps.version.outputs.version }}.spdx.json + --output "artifacts/container-release/netcoreapplicationtemplate-container-${RELEASE_VERSION}.spdx.json" artifacts/trivy-results.json - name: Upload release evidence artifact