From 931b65860304c0fdd162d5de85509022d0efb9e9 Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:52:33 +0200 Subject: [PATCH 1/9] Add security hardening and tool installations to workflow --- .github/workflows/shared-go-auto-release.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index f36dd78f..9e474365 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -104,6 +104,18 @@ jobs: run: |- sudo apt-get update && sudo apt-get install -y git gnupg2 + - name: Harden Runner + uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + with: + egress-policy: audit + + - name: "Install cosign" + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + + # syft binary that .goreleaser.yml's sboms: block shells out to. + - name: "Install syft" + uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: From 101da7418cad898cc70a3161f05a7ee2e812b796 Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Thu, 3 Sep 2026 18:05:15 +0200 Subject: [PATCH 2/9] Update shared-go-auto-release.yml --- .github/workflows/shared-go-auto-release.yml | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index 9e474365..65886b31 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -248,6 +248,7 @@ jobs: - name: Run GoReleaser uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 + id: releaser with: workdir: source version: latest @@ -258,6 +259,52 @@ jobs: GO_RELEASER_TARGET_COMMITISH: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref_name }} GO_RELEASER_DRAFT_MODE: ${{ inputs.draft }} + # Real Sigstore-backed provenance for every binary this job just built + # locally — no longer a re-fetch, so this is genuine build-time + # GitHub-native attestation stacked on top of cosign (a different + # verification mechanism/consumer than cosign, e.g. `gh attestation + # verify`), not a second re-fetch-and-sign layer. + - name: "Attest build provenance" + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-path: 'source/dist/*' + + - name: "Resolve checksums file" + id: checksums + run: | + file="$(find source/dist -maxdepth 1 -name '*_SHA256SUMS' -print -quit)" + if [ -z "$file" ]; then + echo "No *_SHA256SUMS file found in dist/" >&2 + exit 1 + fi + echo "file=$file" >> "$GITHUB_OUTPUT" + + # Bind a source-tree SBOM to the checksums file — it already commits to + # every binary's exact digest, so it's a well-defined single-artifact + # anchor for a release that ships multiple platform binaries. Separate + # from .goreleaser.yml's per-archive sboms: block (bound to individual + # archives, uploaded to the release directly by GoReleaser itself). + - name: "Generate and attest source-tree SBOM" + uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + with: + path: . + format: spdx-json + output-file: source/dist/atmos-sbom.spdx.json + + - name: "Attest SBOM" + uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + with: + subject-path: ${{ steps.checksums.outputs.file }} + sbom-path: source/dist/atmos-sbom.spdx.json + + - name: "Upload source-tree SBOM to the release" + env: + GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} + TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} + run: | + gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ + --repo "${{ github.repository }}" --clobber + - name: Check disk space after if: success() || failure() shell: bash From 026b3a636fd7d0fabdc367ea583f453290227eb1 Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Thu, 3 Sep 2026 20:15:38 +0200 Subject: [PATCH 3/9] Update shared-go-auto-release.yml --- .github/workflows/shared-go-auto-release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index 65886b31..28d34561 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -287,13 +287,15 @@ jobs: - name: "Generate and attest source-tree SBOM" uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 with: - path: . + github-token: ${{ steps.github-app.outputs.token }} + path: source/ format: spdx-json output-file: source/dist/atmos-sbom.spdx.json - name: "Attest SBOM" uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 with: + github-token: ${{ steps.github-app.outputs.token }} subject-path: ${{ steps.checksums.outputs.file }} sbom-path: source/dist/atmos-sbom.spdx.json From 9b12bc4c4bbb08ca99a095ad1b042683ea803855 Mon Sep 17 00:00:00 2001 From: Igor Rodionov Date: Thu, 3 Sep 2026 21:21:05 +0200 Subject: [PATCH 4/9] fix: pass App token to attest-build-provenance step --- .github/workflows/shared-go-auto-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index 28d34561..51b4ea83 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -267,6 +267,7 @@ jobs: - name: "Attest build provenance" uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 with: + github-token: ${{ steps.github-app.outputs.token }} subject-path: 'source/dist/*' - name: "Resolve checksums file" From b79c7ca56463fdcd80ac61c11bccb0e38a59a6c6 Mon Sep 17 00:00:00 2001 From: Igor Rodionov Date: Thu, 3 Sep 2026 21:56:23 +0200 Subject: [PATCH 5/9] fix: pass App token to attest-build-provenance step --- .github/workflows/shared-go-auto-release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index 51b4ea83..8ebf46cd 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -292,6 +292,11 @@ jobs: path: source/ format: spdx-json output-file: source/dist/atmos-sbom.spdx.json + # We upload the SBOM to the GitHub release ourselves in the next + # step, so skip the action's own GH Actions workflow-artifact + # upload — it depends on the runner's internal artifact-caching + # proxy, which has been unreliable on our self-hosted runners. + upload-artifact: false - name: "Attest SBOM" uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 From ba36c3cc0a8688d4ec317249d5a4690a99890c9e Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Thu, 3 Sep 2026 23:09:22 +0200 Subject: [PATCH 6/9] Update shared-go-auto-release.yml --- .github/workflows/shared-go-auto-release.yml | 53 +++++++++----------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index 8ebf46cd..ee6d9ba6 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -109,9 +109,6 @@ jobs: with: egress-policy: audit - - name: "Install cosign" - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 - # syft binary that .goreleaser.yml's sboms: block shells out to. - name: "Install syft" uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 @@ -285,33 +282,33 @@ jobs: # anchor for a release that ships multiple platform binaries. Separate # from .goreleaser.yml's per-archive sboms: block (bound to individual # archives, uploaded to the release directly by GoReleaser itself). - - name: "Generate and attest source-tree SBOM" - uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 - with: - github-token: ${{ steps.github-app.outputs.token }} - path: source/ - format: spdx-json - output-file: source/dist/atmos-sbom.spdx.json - # We upload the SBOM to the GitHub release ourselves in the next - # step, so skip the action's own GH Actions workflow-artifact - # upload — it depends on the runner's internal artifact-caching - # proxy, which has been unreliable on our self-hosted runners. - upload-artifact: false + # - name: "Generate and attest source-tree SBOM" + # uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + # with: + # github-token: ${{ steps.github-app.outputs.token }} + # path: source/ + # format: spdx-json + # output-file: source/dist/atmos-sbom.spdx.json + # # We upload the SBOM to the GitHub release ourselves in the next + # # step, so skip the action's own GH Actions workflow-artifact + # # upload — it depends on the runner's internal artifact-caching + # # proxy, which has been unreliable on our self-hosted runners. + # upload-artifact: false - - name: "Attest SBOM" - uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 - with: - github-token: ${{ steps.github-app.outputs.token }} - subject-path: ${{ steps.checksums.outputs.file }} - sbom-path: source/dist/atmos-sbom.spdx.json + # - name: "Attest SBOM" + # uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + # with: + # github-token: ${{ steps.github-app.outputs.token }} + # subject-path: ${{ steps.checksums.outputs.file }} + # sbom-path: source/dist/atmos-sbom.spdx.json - - name: "Upload source-tree SBOM to the release" - env: - GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} - TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} - run: | - gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ - --repo "${{ github.repository }}" --clobber + # - name: "Upload source-tree SBOM to the release" + # env: + # GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} + # TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} + # run: | + # gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ + # --repo "${{ github.repository }}" --clobber - name: Check disk space after if: success() || failure() From b5060cb05a8d8a42bc2fd621319e0e728d298884 Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Fri, 4 Sep 2026 19:24:14 +0200 Subject: [PATCH 7/9] Update shared-go-auto-release.yml --- .github/workflows/shared-go-auto-release.yml | 50 ++++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index ee6d9ba6..a16dca57 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -282,33 +282,33 @@ jobs: # anchor for a release that ships multiple platform binaries. Separate # from .goreleaser.yml's per-archive sboms: block (bound to individual # archives, uploaded to the release directly by GoReleaser itself). - # - name: "Generate and attest source-tree SBOM" - # uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 - # with: - # github-token: ${{ steps.github-app.outputs.token }} - # path: source/ - # format: spdx-json - # output-file: source/dist/atmos-sbom.spdx.json - # # We upload the SBOM to the GitHub release ourselves in the next - # # step, so skip the action's own GH Actions workflow-artifact - # # upload — it depends on the runner's internal artifact-caching - # # proxy, which has been unreliable on our self-hosted runners. - # upload-artifact: false + - name: "Generate and attest source-tree SBOM" + uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + with: + github-token: ${{ steps.github-app.outputs.token }} + path: source/ + format: spdx-json + output-file: source/dist/atmos-sbom.spdx.json + # We upload the SBOM to the GitHub release ourselves in the next + # step, so skip the action's own GH Actions workflow-artifact + # upload — it depends on the runner's internal artifact-caching + # proxy, which has been unreliable on our self-hosted runners. + upload-artifact: false - # - name: "Attest SBOM" - # uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 - # with: - # github-token: ${{ steps.github-app.outputs.token }} - # subject-path: ${{ steps.checksums.outputs.file }} - # sbom-path: source/dist/atmos-sbom.spdx.json + - name: "Attest SBOM" + uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + with: + github-token: ${{ steps.github-app.outputs.token }} + subject-path: ${{ steps.checksums.outputs.file }} + sbom-path: source/dist/atmos-sbom.spdx.json - # - name: "Upload source-tree SBOM to the release" - # env: - # GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} - # TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} - # run: | - # gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ - # --repo "${{ github.repository }}" --clobber + - name: "Upload source-tree SBOM to the release" + env: + GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} + TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} + run: | + gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ + --repo "${{ github.repository }}" --clobber - name: Check disk space after if: success() || failure() From 1a22a781bfb3f4806b1a7917de563de8585f69de Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Fri, 4 Sep 2026 19:49:48 +0200 Subject: [PATCH 8/9] Change SBOM subject path to 'source/' --- .github/workflows/shared-go-auto-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index a16dca57..dbc2b8a5 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -299,7 +299,7 @@ jobs: uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 with: github-token: ${{ steps.github-app.outputs.token }} - subject-path: ${{ steps.checksums.outputs.file }} + subject-path: source/ sbom-path: source/dist/atmos-sbom.spdx.json - name: "Upload source-tree SBOM to the release" From 11d48090c337156e721f8d7847c33ab71962603e Mon Sep 17 00:00:00 2001 From: Igor Rodionov <496956+goruha@users.noreply.github.com> Date: Fri, 4 Sep 2026 20:06:24 +0200 Subject: [PATCH 9/9] Update shared-go-auto-release.yml --- .github/workflows/shared-go-auto-release.yml | 50 ++++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/shared-go-auto-release.yml b/.github/workflows/shared-go-auto-release.yml index dbc2b8a5..78bc991e 100644 --- a/.github/workflows/shared-go-auto-release.yml +++ b/.github/workflows/shared-go-auto-release.yml @@ -282,33 +282,33 @@ jobs: # anchor for a release that ships multiple platform binaries. Separate # from .goreleaser.yml's per-archive sboms: block (bound to individual # archives, uploaded to the release directly by GoReleaser itself). - - name: "Generate and attest source-tree SBOM" - uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 - with: - github-token: ${{ steps.github-app.outputs.token }} - path: source/ - format: spdx-json - output-file: source/dist/atmos-sbom.spdx.json - # We upload the SBOM to the GitHub release ourselves in the next - # step, so skip the action's own GH Actions workflow-artifact - # upload — it depends on the runner's internal artifact-caching - # proxy, which has been unreliable on our self-hosted runners. - upload-artifact: false + # - name: "Generate and attest source-tree SBOM" + # uses: anchore/sbom-action@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + # with: + # github-token: ${{ steps.github-app.outputs.token }} + # path: source/ + # format: spdx-json + # output-file: source/dist/atmos-sbom.spdx.json + # # We upload the SBOM to the GitHub release ourselves in the next + # # step, so skip the action's own GH Actions workflow-artifact + # # upload — it depends on the runner's internal artifact-caching + # # proxy, which has been unreliable on our self-hosted runners. + # upload-artifact: false - - name: "Attest SBOM" - uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 - with: - github-token: ${{ steps.github-app.outputs.token }} - subject-path: source/ - sbom-path: source/dist/atmos-sbom.spdx.json + # - name: "Attest SBOM" + # uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2 + # with: + # github-token: ${{ steps.github-app.outputs.token }} + # subject-path: source/ + # sbom-path: source/dist/atmos-sbom.spdx.json - - name: "Upload source-tree SBOM to the release" - env: - GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} - TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} - run: | - gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ - --repo "${{ github.repository }}" --clobber + # - name: "Upload source-tree SBOM to the release" + # env: + # GITHUB_TOKEN: ${{ steps.github-app.outputs.token }} + # TAG: ${{ fromJSON(steps.releaser.outputs.metadata).tag }} + # run: | + # gh release upload "$TAG" source/dist/atmos-sbom.spdx.json \ + # --repo "${{ github.repository }}" --clobber - name: Check disk space after if: success() || failure()