diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml new file mode 100644 index 0000000000..92473ce95b --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,53 @@ +name: SBOM + +# Publishes an accurate SBOM to GitHub's dependency graph. +# +# GitHub does NOT natively parse `bun.lock`, so out of the box its dependency +# graph, exported SBOM, and Dependabot are blind to the bun dependency tree +# (they only see declared package.json ranges + the npm package-lock.json in +# apps/mcp-server). Syft DOES parse bun.lock with fully resolved versions +# (overrides applied), so this workflow scans the repo with Syft and submits +# the resolved tree via GitHub's Dependency Submission API. After this runs on +# `main`, GitHub's own "Export SBOM" and Dependabot reflect the real bun tree. + +on: + push: + branches: [main] + paths: + - 'bun.lock' + - 'apps/mcp-server/package-lock.json' + - '**/package.json' + - '.github/workflows/sbom.yml' + schedule: + - cron: '0 6 * * 1' # weekly, Monday 06:00 UTC — refresh against new advisories + workflow_dispatch: + +permissions: + contents: write # required by the Dependency Submission API + +concurrency: + group: sbom-${{ github.ref }} + cancel-in-progress: true + +jobs: + sbom: + name: Generate & submit SBOM + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + # Scans the whole repo: Syft reads bun.lock (resolved) and + # apps/mcp-server/package-lock.json. `dependency-snapshot: true` submits + # the result to the dependency graph; the SBOM is also uploaded as a + # workflow artifact for anyone who wants the file directly. + - name: Generate SBOM & submit to dependency graph + # Pinned to a full commit SHA (not the mutable @v0 tag): this action + # runs with contents:write, so a retag/compromise must not be able to + # swap in altered code. Bump the SHA + comment together to upgrade. + uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 + with: + path: . + format: spdx-json + artifact-name: sbom.spdx.json + dependency-snapshot: true