From defbe264fe3dafd5c48c905283bcaeef69a03ddf Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Sun, 18 Jan 2026 23:47:03 -0500 Subject: [PATCH 01/15] Add code to generate SBOMs and attach them to the release as assets --- .github/workflows/build.yml | 79 +++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f9ff982..3e9a541 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -612,3 +612,82 @@ jobs: - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE + generate-sbom: + # Generate an SBOM for the Docker image and, if there is a + # release, upload it as an asset to the release. + # + # This job is located in this workflow as opposed to a separate + # release workflow because it can only run after the + # build-push-all job. Putting it in a separate workflow would + # require us to introduce a dependency of the release workflow on + # this one. + if: github.event_name != 'pull_request' + name: Generate and upload SBOM + needs: + - diagnostics + - repo-metadata + - build-push-all + permissions: + # Allows us to read the SBOM artifact + actions: read + artifact-metadata: write + attestations: write + # Allows us to add the SBOM to the release + contents: write + # Allows the workflow to mint the OIDC token necessary to + # request a Sigstore signing certificate. + id-token: write + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sbom-format: + - cyclonedx-json + - spdx-json + steps: + - name: Apply standard cisagov job preamble + uses: cisagov/action-job-preamble@v1 + with: + # This functionality is poorly implemented and has been + # causing problems due to the MITM implementation hogging or + # leaking memory. As a result we disable it by default. If + # you want to temporarily enable it, simply set + # monitor_permissions equal to "true". + # + # TODO: Re-enable this functionality when practical. See + # cisagov/skeleton-docker#224 for more details. + monitor_permissions: "false" + # Use a variable to specify the permissions monitoring + # configuration. By default this will yield the + # configuration stored in the cisagov organization-level + # variable, but if you want to use a different configuration + # then simply: + # 1. Create a repository-level variable with the name + # ACTIONS_PERMISSIONS_CONFIG. + # 2. Set this new variable's value to the configuration you + # want to use for this repository. + # + # Note in particular that changing the permissions + # monitoring configuration *does not* require you to modify + # this workflow. + permissions_monitoring_config: ${{ vars.ACTIONS_PERMISSIONS_CONFIG }} + - name: Manipulate the ref name into the format that Docker prefers + id: dockerize-ref-name + run: | + DOCKERIZED_REF=$(echo "${{ github.ref_name}}" \ + | tr '[:upper:]' '[:lower:]' \ + | tr '/' '-') + echo "ref=${DOCKERIZED_REF}" >> $GITHUB_OUTPUT + - name: Gemerate SBOM + uses: anchore/sbom-action@v0 + with: + artifact-name: sbom.${{ matrix.sbom-format }} + format: ${{ matrix.sbom-format }} + image: >- + ${{ needs.repo-metadata.outputs.image-name + }}:${{ steps.dockerize-ref-name.outputs.ref }} + output-file: sbom.${{ matrix.sbom-format }} + - name: Attest build provenance for the SBOM + uses: actions/attest-build-provenance@v3 + with: + subject-path: sbom.${{ matrix.sbom-format }} From 5df401292f53946ce9cdb733cdea6b2ebfeaa6a8 Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Tue, 20 Jan 2026 23:18:28 -0500 Subject: [PATCH 02/15] Generate SBOMs for both the ARM64 and AMD64 architectures --- .github/workflows/build.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3e9a541..3c422b7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -637,10 +637,16 @@ jobs: # Allows the workflow to mint the OIDC token necessary to # request a Sigstore signing certificate. id-token: write - runs-on: ubuntu-latest + # This line is long, but if I use a block style indicator then GH + # Actions doesn't parse and execute the expression. + # yamllint disable-line rule:line-length + runs-on: ubuntu-${{ startsWith(matrix.architecture, 'arm') && '24.04-arm' || 'latest' }} strategy: fail-fast: false matrix: + architecture: + - amd64 + - arm64 sbom-format: - cyclonedx-json - spdx-json @@ -681,13 +687,13 @@ jobs: - name: Gemerate SBOM uses: anchore/sbom-action@v0 with: - artifact-name: sbom.${{ matrix.sbom-format }} + artifact-name: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} format: ${{ matrix.sbom-format }} image: >- ${{ needs.repo-metadata.outputs.image-name }}:${{ steps.dockerize-ref-name.outputs.ref }} - output-file: sbom.${{ matrix.sbom-format }} + output-file: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} - name: Attest build provenance for the SBOM uses: actions/attest-build-provenance@v3 with: - subject-path: sbom.${{ matrix.sbom-format }} + subject-path: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} From 41a5c9c3aec7800cd43eb2e1bc6c29d8b6f3e777 Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Tue, 20 Jan 2026 23:59:59 -0500 Subject: [PATCH 03/15] Add (commented out) Dependabot ignore directives for SBOM-related actions --- .github/dependabot.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4ef2def..ddba647 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -38,8 +38,10 @@ updates: - dependency-name: hashicorp/setup-terraform - dependency-name: mxschmitt/action-tmate # Managed by cisagov/skeleton-docker + # - dependency-name: actions/attest-build-provenance # - dependency-name: actions/download-artifact # - dependency-name: actions/upload-artifact + # - dependency-name: anchore/sbom-action # - dependency-name: aquasecurity/trivy-action # - dependency-name: docker/build-push-action # - dependency-name: docker/login-action From 26e3a7581e8dfc668948f37210c5e9db652b2b5b Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Mon, 26 Jan 2026 10:02:54 -0500 Subject: [PATCH 04/15] Manipulate the repo name and use that in the SBOM file name Thus our SBOMs are named, e.g., cisagov-skeleton-docker.amd64.spdx-json rather than sbom.amd64.spdx-json. --- .github/workflows/build.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c422b7..5f3d542 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -684,16 +684,29 @@ jobs: | tr '[:upper:]' '[:lower:]' \ | tr '/' '-') echo "ref=${DOCKERIZED_REF}" >> $GITHUB_OUTPUT - - name: Gemerate SBOM + - name: Manipulate the repo name into the preferred format + id: manipulate-repo-name + run: | + NEW_NAME=$(echo "${{ github.repository}}" \ + | tr '[:upper:]' '[:lower:]' \ + | tr '/ ' '-') + echo "repo-name=${NEW_NAME}" >> $GITHUB_OUTPUT + - name: Generate SBOM uses: anchore/sbom-action@v0 with: - artifact-name: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} + artifact-name: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ + matrix.architecture }}.${{ matrix.sbom-format }} format: ${{ matrix.sbom-format }} image: >- ${{ needs.repo-metadata.outputs.image-name }}:${{ steps.dockerize-ref-name.outputs.ref }} - output-file: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} + output-file: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ + matrix.architecture }}.${{ matrix.sbom-format }} - name: Attest build provenance for the SBOM uses: actions/attest-build-provenance@v3 with: - subject-path: sbom.${{ matrix.architecture }}.${{ matrix.sbom-format }} + subject-path: >- + ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ + matrix.architecture }}.${{ matrix.sbom-format }} From 708f07792a647e69da76a000c8fca80007e4da31 Mon Sep 17 00:00:00 2001 From: Shane Frasier Date: Mon, 26 Jan 2026 14:21:41 -0500 Subject: [PATCH 05/15] Alphabetize Co-authored-by: dav3r --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5f3d542..2303325 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -624,9 +624,9 @@ jobs: if: github.event_name != 'pull_request' name: Generate and upload SBOM needs: + - build-push-all - diagnostics - repo-metadata - - build-push-all permissions: # Allows us to read the SBOM artifact actions: read From 6974955d029d7ebf1c01339220fc24f4805d60db Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Mon, 26 Jan 2026 22:38:34 -0500 Subject: [PATCH 06/15] Add a comment explaining why an if statement is present The if statement is present to to keep the push and pull_request events from both causing the job to be run. Co-authored-by: dav3r Co-authored-by: Nick M <50747025+mcdonnnj@users.noreply.github.com> --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2303325..e71da19 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -621,6 +621,9 @@ jobs: # build-push-all job. Putting it in a separate workflow would # require us to introduce a dependency of the release workflow on # this one. + # + # This if statement is present to keep the push and pull_request + # events from both causing the job to be run. if: github.event_name != 'pull_request' name: Generate and upload SBOM needs: From 2a06a282f2d0e0eecd7f4d0e61a91929324a08a8 Mon Sep 17 00:00:00 2001 From: Shane Frasier Date: Fri, 13 Feb 2026 14:11:43 -0500 Subject: [PATCH 07/15] Make use of matrix.architecture to ensure the correct image is pulled This was happening automatically before, but this makes it explicit. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e71da19..062f0e1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -704,6 +704,7 @@ jobs: image: >- ${{ needs.repo-metadata.outputs.image-name }}:${{ steps.dockerize-ref-name.outputs.ref }} + platform: linux/${{ matrix.architecture }} output-file: >- ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ matrix.architecture }}.${{ matrix.sbom-format }} From 197437856c1a8a683e90a724f31e086a3f5b72aa Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Fri, 13 Feb 2026 14:35:44 -0500 Subject: [PATCH 08/15] Log into Docker Hub before pulling the image to generate the SBOM This reduces the chance that Docker Hub rate limits our request. --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 062f0e1..6bdfe19 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -694,6 +694,11 @@ jobs: | tr '[:upper:]' '[:lower:]' \ | tr '/ ' '-') echo "repo-name=${NEW_NAME}" >> $GITHUB_OUTPUT + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + password: ${{ secrets.DOCKER_PASSWORD }} + username: ${{ secrets.DOCKER_USERNAME }} - name: Generate SBOM uses: anchore/sbom-action@v0 with: From cc5fdb82f8fa88542b25f61a422ed2ded628beaa Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Fri, 13 Feb 2026 14:36:36 -0500 Subject: [PATCH 09/15] Use the fully-qualified (including container repo) image name In this case we want to pull the image from Docker Hub. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6bdfe19..9723b04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -707,7 +707,7 @@ jobs: matrix.architecture }}.${{ matrix.sbom-format }} format: ${{ matrix.sbom-format }} image: >- - ${{ needs.repo-metadata.outputs.image-name + docker.io/${{ needs.repo-metadata.outputs.image-name }}:${{ steps.dockerize-ref-name.outputs.ref }} platform: linux/${{ matrix.architecture }} output-file: >- From dffcd027c4f332b5afcd4facc72480abea3e3e9d Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Mon, 9 Mar 2026 13:30:48 -0400 Subject: [PATCH 10/15] Upgrade to the latest name and version for the attestation action Note that actions/attest-build-provenance has changed its name to actions/attest, partly because it now supports different types of attestations. One such type is an SBOM attestation, which we are now using here. --- .github/dependabot.yml | 2 +- .github/workflows/build.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ddba647..e8dde9d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -38,7 +38,7 @@ updates: - dependency-name: hashicorp/setup-terraform - dependency-name: mxschmitt/action-tmate # Managed by cisagov/skeleton-docker - # - dependency-name: actions/attest-build-provenance + # - dependency-name: actions/attest # - dependency-name: actions/download-artifact # - dependency-name: actions/upload-artifact # - dependency-name: anchore/sbom-action diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9723b04..0d5a21b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -713,9 +713,13 @@ jobs: output-file: >- ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ matrix.architecture }}.${{ matrix.sbom-format }} - - name: Attest build provenance for the SBOM - uses: actions/attest-build-provenance@v3 + - name: Create SBOM attestation + uses: actions/attest@v4 with: - subject-path: >- + push-to-registry: true + sbom-path: >- ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ matrix.architecture }}.${{ matrix.sbom-format }} + subject-name: >- + docker.io/${{ needs.repo-metadata.outputs.image-name + }}:${{ steps.dockerize-ref-name.outputs.ref }} From 5bdfa22656cd24c1975a58595cc9f71d026dfedd Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Mon, 9 Mar 2026 15:58:25 -0400 Subject: [PATCH 11/15] Update code to use the digest of the image upload For more details see: https://github.com/actions/attest?tab=readme-ov-file#container-image --- .github/workflows/build.yml | 45 ++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0d5a21b..1b2c21d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -505,6 +505,8 @@ jobs: - prepare - scan - test + outputs: + digest: ${{ steps.docker_push.outputs.digest }} permissions: # actions/checkout needs this to fetch code contents: read @@ -633,6 +635,7 @@ jobs: permissions: # Allows us to read the SBOM artifact actions: read + # Necessary to create the artifact storage record artifact-metadata: write attestations: write # Allows us to add the SBOM to the release @@ -640,16 +643,15 @@ jobs: # Allows the workflow to mint the OIDC token necessary to # request a Sigstore signing certificate. id-token: write - # This line is long, but if I use a block style indicator then GH - # Actions doesn't parse and execute the expression. - # yamllint disable-line rule:line-length - runs-on: ubuntu-${{ startsWith(matrix.architecture, 'arm') && '24.04-arm' || 'latest' }} + # Necessary to push the SBOM attestation to ghcr.io + packages: write + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - architecture: - - amd64 - - arm64 + registry: + - docker.io + - ghcr.io sbom-format: - cyclonedx-json - spdx-json @@ -699,27 +701,34 @@ jobs: with: password: ${{ secrets.DOCKER_PASSWORD }} username: ${{ secrets.DOCKER_USERNAME }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + password: ${{ secrets.GITHUB_TOKEN }} + registry: ghcr.io + username: ${{ github.actor }} - name: Generate SBOM uses: anchore/sbom-action@v0 with: artifact-name: >- - ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ - matrix.architecture }}.${{ matrix.sbom-format }} + ${{ steps.manipulate-repo-name.outputs.repo-name + }}.${{ matrix.registry }}.${{ matrix.sbom-format }} format: ${{ matrix.sbom-format }} image: >- - docker.io/${{ needs.repo-metadata.outputs.image-name + ${{ matrix.registry }}/${{ needs.repo-metadata.outputs.image-name }}:${{ steps.dockerize-ref-name.outputs.ref }} - platform: linux/${{ matrix.architecture }} output-file: >- - ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ - matrix.architecture }}.${{ matrix.sbom-format }} - - name: Create SBOM attestation + ${{ steps.manipulate-repo-name.outputs.repo-name + }}.${{ matrix.registry }}.${{ matrix.sbom-format }} + - name: Create SBOM attestation for Docker image uses: actions/attest@v4 with: push-to-registry: true sbom-path: >- - ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ - matrix.architecture }}.${{ matrix.sbom-format }} + ${{ steps.manipulate-repo-name.outputs.repo-name + }}.${{ matrix.registry }}.${{ matrix.sbom-format }} + subject-digest: >- + ${{ needs.build-push-all.outputs.digest }} subject-name: >- - docker.io/${{ needs.repo-metadata.outputs.image-name - }}:${{ steps.dockerize-ref-name.outputs.ref }} + ${{ matrix.registry + }}/${{ needs.repo-metadata.outputs.image-name }} From 9ae97209170584cce107d5d72d3f78bfaaa15480 Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Tue, 10 Mar 2026 10:30:18 -0400 Subject: [PATCH 12/15] Add provenance attestation for SBOM --- .github/workflows/build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b2c21d..dbc6958 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -720,6 +720,12 @@ jobs: output-file: >- ${{ steps.manipulate-repo-name.outputs.repo-name }}.${{ matrix.registry }}.${{ matrix.sbom-format }} + - name: Create provenance attestation for SBOM + uses: actions/attest@v4 + with: + subject-path: >- + ${{ steps.manipulate-repo-name.outputs.repo-name + }}.${{ matrix.registry }}.${{ matrix.sbom-format }} - name: Create SBOM attestation for Docker image uses: actions/attest@v4 with: From e59696b3ce18d59c7eb16a4b3282cb0170a10ac9 Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Tue, 10 Mar 2026 13:21:38 -0400 Subject: [PATCH 13/15] Add provenance attestation for distribution --- .github/workflows/build.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dbc6958..c372114 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -302,8 +302,16 @@ jobs: - repo-metadata - prepare permissions: - # actions/checkout needs this to fetch code - contents: read + # Allows us to read the artifacts + actions: read + # Necessary to create the artifact storage record + artifact-metadata: write + attestations: write + # Allows us to add artifacts to the release. + contents: write + # Allows the workflow to mint the OIDC token necessary to + # request a Sigstore signing certificate. + id-token: write runs-on: ubuntu-latest steps: - name: Apply standard cisagov job preamble @@ -364,6 +372,10 @@ jobs: with: archive: false path: image.tar.gz + - name: Create provenance attestation for artifacts + uses: actions/attest@v4 + with: + subject-path: dist - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE From 9e3856141aaf50281d46b0caca67fb5bf640319d Mon Sep 17 00:00:00 2001 From: Shane Frasier Date: Tue, 10 Mar 2026 15:04:52 -0400 Subject: [PATCH 14/15] Pare down permissions Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c372114..9e83e5d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -302,13 +302,11 @@ jobs: - repo-metadata - prepare permissions: - # Allows us to read the artifacts - actions: read # Necessary to create the artifact storage record artifact-metadata: write attestations: write - # Allows us to add artifacts to the release. - contents: write + # Allows read access to repository contents (e.g., for checkout). + contents: read # Allows the workflow to mint the OIDC token necessary to # request a Sigstore signing certificate. id-token: write From e78c3ca2f2d88585c599ebfac0cb9a6a6b1b444b Mon Sep 17 00:00:00 2001 From: Jeremy Frasier Date: Fri, 17 Apr 2026 13:01:02 -0400 Subject: [PATCH 15/15] Update subject path The subject path changed upstream, so it has to change here too. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e83e5d..5b56401 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -373,7 +373,7 @@ jobs: - name: Create provenance attestation for artifacts uses: actions/attest@v4 with: - subject-path: dist + subject-path: image.tar.gz - name: Setup tmate debug session uses: mxschmitt/action-tmate@v3 if: env.RUN_TMATE