diff --git a/.github/aw/actions-lock.json b/.github/aw/actions-lock.json index c184eee006..ccc5e58047 100644 --- a/.github/aw/actions-lock.json +++ b/.github/aw/actions-lock.json @@ -65,6 +65,11 @@ "version": "v5", "sha": "330a01c490aca151604b8cf639adc76d48f6c5d4" }, + "anchore/sbom-action@v0.20.10": { + "repo": "anchore/sbom-action", + "version": "v0.20.10", + "sha": "fbfd9c6c189226748411491745178e0c2017392d" + }, "astral-sh/setup-uv@v5": { "repo": "astral-sh/setup-uv", "version": "v5", diff --git a/.github/workflows/release.lock.yml b/.github/workflows/release.lock.yml index 2d268b7a7a..cdbb51626f 100644 --- a/.github/workflows/release.lock.yml +++ b/.github/workflows/release.lock.yml @@ -60,6 +60,7 @@ # attestations: write # outputs: # release_id: ${{ steps.get_release.outputs.release_id }} +# release_tag: ${{ steps.get_release.outputs.release_tag }} # steps: # - name: Checkout # uses: actions/checkout@v5 @@ -82,7 +83,58 @@ # echo "Getting release ID for tag: $RELEASE_TAG" # RELEASE_ID=$(gh release view "$RELEASE_TAG" --json databaseId --jq '.databaseId') # echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" +# echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT" # echo "✓ Release ID: $RELEASE_ID" +# echo "✓ Release Tag: $RELEASE_TAG" +# generate-sbom: +# needs: ["release"] +# runs-on: ubuntu-latest +# permissions: +# contents: write +# steps: +# - name: Checkout repository +# uses: actions/checkout@v5 +# +# - name: Set up Go +# uses: actions/setup-go@v5 +# with: +# go-version-file: go.mod +# cache: true +# +# - name: Download Go modules +# run: go mod download +# +# - name: Generate SBOM (SPDX format) +# uses: anchore/sbom-action@v0 +# with: +# artifact-name: sbom.spdx.json +# output-file: sbom.spdx.json +# format: spdx-json +# +# - name: Generate SBOM (CycloneDX format) +# uses: anchore/sbom-action@v0 +# with: +# artifact-name: sbom.cdx.json +# output-file: sbom.cdx.json +# format: cyclonedx-json +# +# - name: Upload SBOM artifacts +# uses: actions/upload-artifact@v4 +# with: +# name: sbom-artifacts +# path: | +# sbom.spdx.json +# sbom.cdx.json +# retention-days: 90 +# +# - name: Attach SBOM to release +# env: +# GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# RELEASE_TAG: ${{ needs.release.outputs.release_tag }} +# run: | +# echo "Attaching SBOM files to release: $RELEASE_TAG" +# gh release upload "$RELEASE_TAG" sbom.spdx.json sbom.cdx.json --clobber +# echo "✓ SBOM files attached to release" # steps: # - name: Setup environment and fetch release data # env: @@ -159,16 +211,19 @@ # agent["agent"] # conclusion["conclusion"] # detection["detection"] +# generate-sbom["generate-sbom"] # pre_activation["pre_activation"] # release["release"] # update_release["update_release"] # pre_activation --> activation # activation --> agent # release --> agent +# generate-sbom --> agent # agent --> conclusion # activation --> conclusion # update_release --> conclusion # agent --> detection +# release --> generate-sbom # activation --> release # agent --> update_release # detection --> update_release @@ -311,10 +366,14 @@ # https://github.com/actions/download-artifact/commit/018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # - actions/github-script@v8 (ed597411d8f924073f98dfc5c65a23a2325f34cd) # https://github.com/actions/github-script/commit/ed597411d8f924073f98dfc5c65a23a2325f34cd +# - actions/setup-go@v5 (d35c59abb061a4a6fb18e82ac0862c26744d6ab5) +# https://github.com/actions/setup-go/commit/d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # - actions/setup-node@v6 (395ad3262231945c25e8478fd5baf05154b1d79f) # https://github.com/actions/setup-node/commit/395ad3262231945c25e8478fd5baf05154b1d79f # - actions/upload-artifact@v5 (330a01c490aca151604b8cf639adc76d48f6c5d4) # https://github.com/actions/upload-artifact/commit/330a01c490aca151604b8cf639adc76d48f6c5d4 +# - anchore/sbom-action@v0.20.10 (fbfd9c6c189226748411491745178e0c2017392d) +# https://github.com/anchore/sbom-action/commit/fbfd9c6c189226748411491745178e0c2017392d # - cli/gh-extension-precompile@v2 (9e2237c30f869ad3bcaed6a4be2cd43564dd421b) # https://github.com/cli/gh-extension-precompile/commit/9e2237c30f869ad3bcaed6a4be2cd43564dd421b @@ -438,6 +497,7 @@ jobs: needs: - activation - release + - generate-sbom runs-on: ubuntu-latest permissions: actions: read @@ -5892,6 +5952,51 @@ jobs: path: /tmp/gh-aw/threat-detection/detection.log if-no-files-found: ignore + generate-sbom: + needs: release + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout repository + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5 + with: + cache: true + go-version-file: go.mod + - name: Download Go modules + run: go mod download + - name: Generate SBOM (SPDX format) + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + with: + artifact-name: sbom.spdx.json + format: spdx-json + output-file: sbom.spdx.json + - name: Generate SBOM (CycloneDX format) + uses: anchore/sbom-action@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 + with: + artifact-name: sbom.cdx.json + format: cyclonedx-json + output-file: sbom.cdx.json + - name: Upload SBOM artifacts + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: sbom-artifacts + path: | + sbom.spdx.json + sbom.cdx.json + retention-days: 90 + - name: Attach SBOM to release + run: | + echo "Attaching SBOM files to release: $RELEASE_TAG" + gh release upload "$RELEASE_TAG" sbom.spdx.json sbom.cdx.json --clobber + echo "✓ SBOM files attached to release" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ needs.release.outputs.release_tag }} + pre_activation: runs-on: ubuntu-slim outputs: @@ -5996,6 +6101,7 @@ jobs: outputs: release_id: ${{ steps.get_release.outputs.release_id }} + release_tag: ${{ steps.get_release.outputs.release_tag }} steps: - name: Checkout uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 @@ -6014,7 +6120,9 @@ jobs: echo "Getting release ID for tag: $RELEASE_TAG" RELEASE_ID=$(gh release view "$RELEASE_TAG" --json databaseId --jq '.databaseId') echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" + echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT" echo "✓ Release ID: $RELEASE_ID" + echo "✓ Release Tag: $RELEASE_TAG" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.md b/.github/workflows/release.md index 0717d8283c..520342671f 100644 --- a/.github/workflows/release.md +++ b/.github/workflows/release.md @@ -37,6 +37,7 @@ jobs: attestations: write outputs: release_id: ${{ steps.get_release.outputs.release_id }} + release_tag: ${{ steps.get_release.outputs.release_tag }} steps: - name: Checkout uses: actions/checkout@v5 @@ -59,7 +60,58 @@ jobs: echo "Getting release ID for tag: $RELEASE_TAG" RELEASE_ID=$(gh release view "$RELEASE_TAG" --json databaseId --jq '.databaseId') echo "release_id=$RELEASE_ID" >> "$GITHUB_OUTPUT" + echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT" echo "✓ Release ID: $RELEASE_ID" + echo "✓ Release Tag: $RELEASE_TAG" + generate-sbom: + needs: ["release"] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Download Go modules + run: go mod download + + - name: Generate SBOM (SPDX format) + uses: anchore/sbom-action@v0 + with: + artifact-name: sbom.spdx.json + output-file: sbom.spdx.json + format: spdx-json + + - name: Generate SBOM (CycloneDX format) + uses: anchore/sbom-action@v0 + with: + artifact-name: sbom.cdx.json + output-file: sbom.cdx.json + format: cyclonedx-json + + - name: Upload SBOM artifacts + uses: actions/upload-artifact@v4 + with: + name: sbom-artifacts + path: | + sbom.spdx.json + sbom.cdx.json + retention-days: 90 + + - name: Attach SBOM to release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ needs.release.outputs.release_tag }} + run: | + echo "Attaching SBOM files to release: $RELEASE_TAG" + gh release upload "$RELEASE_TAG" sbom.spdx.json sbom.cdx.json --clobber + echo "✓ SBOM files attached to release" steps: - name: Setup environment and fetch release data env: diff --git a/.gitignore b/.gitignore index 196952b6ca..2e4cf4a3b4 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,10 @@ logs/ # Benchmark results bench_results.txt +# SBOM files (generated by make sbom) +sbom.spdx.json +sbom.cdx.json + node_modules/ gh-aw-test/ diff --git a/Makefile b/Makefile index 1bce63e7ad..34a2fe0ce1 100644 --- a/Makefile +++ b/Makefile @@ -341,6 +341,24 @@ pull-main: release: pull-main build @node scripts/changeset.js release +# Generate Software Bill of Materials (SBOM) +.PHONY: sbom +sbom: + @if ! command -v syft >/dev/null 2>&1; then \ + echo "Error: syft is not installed."; \ + echo ""; \ + echo "Install syft to generate SBOMs:"; \ + echo " curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin"; \ + echo ""; \ + echo "Or visit: https://github.com/anchore/syft#installation"; \ + exit 1; \ + fi + @echo "Generating SBOM in SPDX format..." + syft packages . -o spdx-json=sbom.spdx.json + @echo "Generating SBOM in CycloneDX format..." + syft packages . -o cyclonedx-json=sbom.cdx.json + @echo "✓ SBOM files generated: sbom.spdx.json, sbom.cdx.json" + # Agent should run this task before finishing its turns .PHONY: agent-finish agent-finish: deps-dev fmt lint build test-all recompile dependabot generate-schema-docs generate-labs @@ -387,4 +405,5 @@ help: @echo " agent-finish - Complete validation sequence (build, test, recompile, fmt, lint)" @echo " version - Preview next version from changesets" @echo " release - Create release using changesets (depends on test)" + @echo " sbom - Generate SBOM in SPDX and CycloneDX formats (requires syft)" @echo " help - Show this help message" \ No newline at end of file diff --git a/SECURITY.md b/SECURITY.md index 77d7986f73..f5cf4bfea6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -29,3 +29,37 @@ This information will help us triage your report more quickly. ## Policy See [GitHub's Safe Harbor Policy](https://docs.github.com/en/github/site-policy/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) + +## Software Bill of Materials (SBOM) + +We generate Software Bill of Materials (SBOM) for this project to provide complete visibility into the dependency tree, enabling compliance reporting, vulnerability tracking, and supply chain risk assessment. + +### SBOM Generation + +SBOMs are automatically generated on every release and attached to GitHub releases as downloadable assets. + +Both SPDX and CycloneDX formats are generated to ensure compatibility with different compliance and security tools. + +### Local SBOM Generation + +To generate an SBOM locally, first install [syft](https://github.com/anchore/syft): + +```bash +# Install syft +curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin + +# Generate SBOM +make sbom +``` + +This produces two files: +- `sbom.spdx.json` - SBOM in SPDX JSON format +- `sbom.cdx.json` - SBOM in CycloneDX JSON format + +### SBOM Contents + +The generated SBOMs include: +- All direct and transitive Go dependencies +- Package versions and licenses +- Package hashes for integrity verification +- Dependency relationships diff --git a/pkg/workflow/data/action_pins.json b/pkg/workflow/data/action_pins.json index c184eee006..ccc5e58047 100644 --- a/pkg/workflow/data/action_pins.json +++ b/pkg/workflow/data/action_pins.json @@ -65,6 +65,11 @@ "version": "v5", "sha": "330a01c490aca151604b8cf639adc76d48f6c5d4" }, + "anchore/sbom-action@v0.20.10": { + "repo": "anchore/sbom-action", + "version": "v0.20.10", + "sha": "fbfd9c6c189226748411491745178e0c2017392d" + }, "astral-sh/setup-uv@v5": { "repo": "astral-sh/setup-uv", "version": "v5",