From 82ccf454a826c87c43f1ccd006c75c8ef8ff2fe7 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Wed, 22 Oct 2025 18:02:09 -0700 Subject: [PATCH 1/4] added SBOM generation Signed-off-by: Jaya Venkatesh --- .github/actions/build-linux-image/action.yml | 50 +++++++++++++++++-- .../actions/build-linux-image/sbom.Dockerfile | 29 +++++++++++ windows/build-windows-image.ps1 | 46 +++++++++++++++++ windows/sbom.Dockerfile | 9 ++++ 4 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 .github/actions/build-linux-image/sbom.Dockerfile create mode 100644 windows/sbom.Dockerfile diff --git a/.github/actions/build-linux-image/action.yml b/.github/actions/build-linux-image/action.yml index 5ed505286..2664dd8ad 100644 --- a/.github/actions/build-linux-image/action.yml +++ b/.github/actions/build-linux-image/action.yml @@ -42,7 +42,7 @@ runs: declare -a outputs=(); if test "${push}" = true; then - outputs+=(--output "type=image,compression=zstd,force-compression=true,oci-mediatypes=true,push=true,push-by-digest=true,name=${repo}"); + outputs+=(--output "type=image,compression=zstd,force-compression=true,oci-mediatypes=true,load=true,name=${repo}"); # HACK: remove the `-t` arg from the `docker buildx build` command generated by `devcontainer build` sed -i 's/,t.map(v=>l.push("-t",v))//g' "$(npm list -g | head -n1)"/node_modules/@devcontainers/cli/dist/spec-node/devContainersSpecCLI.js; fi @@ -66,8 +66,52 @@ runs: fi done + echo "base_image=${repo,,}:${tag}" >> "$GITHUB_OUTPUT" + + - id: embed-sbom + name: Embed SBOM into ${{ inputs.repo }}:${{ inputs.tag }}-${{ inputs.arch }} + shell: bash + env: + arch: "${{ inputs.arch }}" + base_image: "${{ steps.build.outputs.base_image }}" + push: "${{ inputs.push }}" + repo: "${{ inputs.repo }}" + tag: "${{ inputs.tag }}" + run: | + set -euo pipefail + + if test -z "${base_image}"; then + echo "Base image tag missing" + exit 1 + fi + + action_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + sbom_dockerfile="${action_dir}/sbom.Dockerfile" + sbom_log="${RUNNER_TEMP}/sbom-${arch}.log" + + output="type=image,compression=zstd,force-compression=true,oci-mediatypes=true,name=${repo,,}" if test "${push}" = true; then - echo "hash_${arch}=$(grep 'exporting manifest sha256:' "${{ runner.temp }}/${arch}.log" | tail -n1 | grep -oP 'sha256:\w+')" >> "$GITHUB_OUTPUT"; + output+="\,push=true,push-by-digest=true" else - echo "hash_${arch}=" >> "$GITHUB_OUTPUT"; + output+="\,load=true" fi + + docker buildx build \ + --platform "linux/${arch}" \ + --tag "${repo,,}:${tag}" \ + --build-context base="docker-image://${base_image}" \ + --build-arg SYFT_VERSION="1.32.0" \ + --output "${output}" \ + --file "${sbom_dockerfile}" \ + "${action_dir}" 2>&1 | tee "${sbom_log}" + + digest="" + if test "${push}" = true; then + digest="$(grep 'exporting manifest sha256:' "${sbom_log}" | tail -n1 | grep -oP 'sha256:\w+')" + if test -z "${digest}"; then + echo "Failed to determine pushed digest" + exit 1 + fi + fi + + echo "hash_${arch}=${digest}" >> "$GITHUB_OUTPUT" diff --git a/.github/actions/build-linux-image/sbom.Dockerfile b/.github/actions/build-linux-image/sbom.Dockerfile new file mode 100644 index 000000000..647142442 --- /dev/null +++ b/.github/actions/build-linux-image/sbom.Dockerfile @@ -0,0 +1,29 @@ +# syntax=docker/dockerfile:1.6 +ARG SYFT_VERSION + +FROM --platform=$BUILDPLATFORM alpine:3.20 AS syft-base +ARG BUILDPLATFORM +ARG SYFT_VERSION +RUN apk add --no-cache curl tar ca-certificates \ + && case "$BUILDPLATFORM" in \ + linux/amd64) SYFT_ARCH="linux_amd64" ;; \ + linux/arm64) SYFT_ARCH="linux_arm64" ;; \ + *) echo "Unsupported BUILDPLATFORM: ${BUILDPLATFORM}" >&2 && exit 1 ;; \ + esac \ + && curl -sSfL "https://github.com/anchore/syft/releases/download/v${SYFT_VERSION}/syft_${SYFT_VERSION}_${SYFT_ARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin syft \ + && chmod +x /usr/local/bin/syft + +FROM base AS devcontainer-base + +FROM syft-base AS sbom +RUN --mount=type=bind,from=devcontainer-base,source=/,target=/rootfs,ro \ + mkdir -p /out && \ + syft scan \ + --scope all-layers \ + --output cyclonedx-json@1.6=/out/sbom.json \ + dir:/rootfs + +FROM devcontainer-base +RUN mkdir -p /sbom +COPY --from=sbom /out/sbom.json /sbom/sbom.json \ No newline at end of file diff --git a/windows/build-windows-image.ps1 b/windows/build-windows-image.ps1 index 425998238..b0234c437 100644 --- a/windows/build-windows-image.ps1 +++ b/windows/build-windows-image.ps1 @@ -67,3 +67,49 @@ catch { finally { Pop-Location } + +$syftVersion = "1.32.0" +$arch = switch ($env:PROCESSOR_ARCHITECTURE.ToLower()) { + "amd64" { "windows_amd64" } + "arm64" { "windows_arm64" } + default { throw "Unsupported PROCESSOR_ARCHITECTURE '$env:PROCESSOR_ARCHITECTURE'" } +} +$syftZipName = "syft_${syftVersion}_${arch}.zip" +$syftDownload = "https://github.com/anchore/syft/releases/download/v$syftVersion/$syftZipName" +$tempRoot = Join-Path $env:TEMP ("sbom-" + [guid]::NewGuid()) +$syftArchive = Join-Path $tempRoot $syftZipName +$sbomJson = Join-Path $tempRoot "sbom.json" +$contextDir = Join-Path $tempRoot "context" +New-Item -ItemType Directory -Path $tempRoot, $contextDir | Out-Null + +try { + Invoke-WebRequest ` + -Uri $syftDownload ` + -OutFile $syftArchive ` + -UseBasicParsing + Expand-Archive -Path $syftArchive -DestinationPath $tempRoot -Force + + $syftExe = Get-ChildItem -Path $tempRoot -Filter syft.exe -Recurse | + Select-Object -First 1 | + ForEach-Object FullName + if (-not $syftExe) { + throw "syft.exe not found after extracting $syftZipName" + } + + & $syftExe ` + "docker:$ENV:IMAGE_NAME" ` + --scope all-layers ` + "--output" "cyclonedx-json@1.6=$sbomJson" + + Copy-Item -Path $sbomJson -Destination (Join-Path $contextDir "sbom.json") + Copy-Item -Path (Join-Path $PSScriptRoot "sbom.Dockerfile") -Destination (Join-Path $contextDir "Dockerfile") + + docker build ` + --file (Join-Path $contextDir "Dockerfile") ` + --build-arg BASE_IMAGE=$ENV:IMAGE_NAME ` + --tag $ENV:IMAGE_NAME ` + $contextDir +} +finally { + Remove-Item -Path $tempRoot -Recurse -Force +} \ No newline at end of file diff --git a/windows/sbom.Dockerfile b/windows/sbom.Dockerfile new file mode 100644 index 000000000..67f2fd0ea --- /dev/null +++ b/windows/sbom.Dockerfile @@ -0,0 +1,9 @@ +# escape=` +ARG BASE_IMAGE + +FROM ${BASE_IMAGE} + +SHELL ["powershell.exe", "-Command"] + +RUN New-Item -ItemType Directory -Path 'C:\sbom' -Force | Out-Null +COPY ["sbom.json", "C:\\sbom\\sbom.json"] \ No newline at end of file From 4c5242e511d057832d69c3d0629e25a814be9e5d Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Wed, 22 Oct 2025 18:07:28 -0700 Subject: [PATCH 2/4] added newlines Signed-off-by: Jaya Venkatesh --- .github/actions/build-linux-image/sbom.Dockerfile | 2 +- windows/build-windows-image.ps1 | 2 +- windows/sbom.Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/actions/build-linux-image/sbom.Dockerfile b/.github/actions/build-linux-image/sbom.Dockerfile index 647142442..49a678323 100644 --- a/.github/actions/build-linux-image/sbom.Dockerfile +++ b/.github/actions/build-linux-image/sbom.Dockerfile @@ -26,4 +26,4 @@ RUN --mount=type=bind,from=devcontainer-base,source=/,target=/rootfs,ro \ FROM devcontainer-base RUN mkdir -p /sbom -COPY --from=sbom /out/sbom.json /sbom/sbom.json \ No newline at end of file +COPY --from=sbom /out/sbom.json /sbom/sbom.json diff --git a/windows/build-windows-image.ps1 b/windows/build-windows-image.ps1 index b0234c437..a2ee459c9 100644 --- a/windows/build-windows-image.ps1 +++ b/windows/build-windows-image.ps1 @@ -112,4 +112,4 @@ try { } finally { Remove-Item -Path $tempRoot -Recurse -Force -} \ No newline at end of file +} diff --git a/windows/sbom.Dockerfile b/windows/sbom.Dockerfile index 67f2fd0ea..288ceb451 100644 --- a/windows/sbom.Dockerfile +++ b/windows/sbom.Dockerfile @@ -6,4 +6,4 @@ FROM ${BASE_IMAGE} SHELL ["powershell.exe", "-Command"] RUN New-Item -ItemType Directory -Path 'C:\sbom' -Force | Out-Null -COPY ["sbom.json", "C:\\sbom\\sbom.json"] \ No newline at end of file +COPY ["sbom.json", "C:\\sbom\\sbom.json"] From 3ead6ec54f16cbd9746af2d2a4dca1ea455ff65e Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Wed, 22 Oct 2025 18:15:51 -0700 Subject: [PATCH 3/4] updated path to Dockerfile Signed-off-by: Jaya Venkatesh --- .github/actions/build-linux-image/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/build-linux-image/action.yml b/.github/actions/build-linux-image/action.yml index 2664dd8ad..bb8c6f998 100644 --- a/.github/actions/build-linux-image/action.yml +++ b/.github/actions/build-linux-image/action.yml @@ -85,7 +85,7 @@ runs: exit 1 fi - action_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + action_dir="${GITHUB_ACTION_PATH:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}" sbom_dockerfile="${action_dir}/sbom.Dockerfile" sbom_log="${RUNNER_TEMP}/sbom-${arch}.log" From 737548b9a17f7ee08a44adc0ec412c878eb59785 Mon Sep 17 00:00:00 2001 From: Jaya Venkatesh Date: Tue, 28 Oct 2025 14:03:48 -0700 Subject: [PATCH 4/4] added source names for Syft scan Signed-off-by: Jaya Venkatesh --- .github/actions/build-linux-image/action.yml | 1 + .github/actions/build-linux-image/sbom.Dockerfile | 2 ++ windows/build-windows-image.ps1 | 1 + 3 files changed, 4 insertions(+) diff --git a/.github/actions/build-linux-image/action.yml b/.github/actions/build-linux-image/action.yml index bb8c6f998..428859e11 100644 --- a/.github/actions/build-linux-image/action.yml +++ b/.github/actions/build-linux-image/action.yml @@ -101,6 +101,7 @@ runs: --tag "${repo,,}:${tag}" \ --build-context base="docker-image://${base_image}" \ --build-arg SYFT_VERSION="1.32.0" \ + --build-arg SOURCE_IMAGE_NAME="${base_image}" \ --output "${output}" \ --file "${sbom_dockerfile}" \ "${action_dir}" 2>&1 | tee "${sbom_log}" diff --git a/.github/actions/build-linux-image/sbom.Dockerfile b/.github/actions/build-linux-image/sbom.Dockerfile index 49a678323..c5c06ee8b 100644 --- a/.github/actions/build-linux-image/sbom.Dockerfile +++ b/.github/actions/build-linux-image/sbom.Dockerfile @@ -1,5 +1,6 @@ # syntax=docker/dockerfile:1.6 ARG SYFT_VERSION +ARG SOURCE_IMAGE_NAME FROM --platform=$BUILDPLATFORM alpine:3.20 AS syft-base ARG BUILDPLATFORM @@ -20,6 +21,7 @@ FROM syft-base AS sbom RUN --mount=type=bind,from=devcontainer-base,source=/,target=/rootfs,ro \ mkdir -p /out && \ syft scan \ + --source-name "${SOURCE_IMAGE_NAME}" \ --scope all-layers \ --output cyclonedx-json@1.6=/out/sbom.json \ dir:/rootfs diff --git a/windows/build-windows-image.ps1 b/windows/build-windows-image.ps1 index a2ee459c9..38f489251 100644 --- a/windows/build-windows-image.ps1 +++ b/windows/build-windows-image.ps1 @@ -99,6 +99,7 @@ try { & $syftExe ` "docker:$ENV:IMAGE_NAME" ` --scope all-layers ` + --source-name "$ENV:IMAGE_NAME" ` "--output" "cyclonedx-json@1.6=$sbomJson" Copy-Item -Path $sbomJson -Destination (Join-Path $contextDir "sbom.json")