From 14678c5c654d38e1028d7f596fd1185e303d3d9f Mon Sep 17 00:00:00 2001 From: Ruben van der Linde Date: Fri, 1 May 2026 09:21:19 +0200 Subject: [PATCH] ci(sbom): open PR for SBOM updates on protected branches MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Commit SBOM step ran a direct `git push` on every push trigger. On protected branches (main / development / beta) the org ruleset rejects unbypassed pushes, so the workflow failed with `GH013: Repository rule violations` — visible as the red `SBOM Generation & Validation` check on every release PR. Split the post-build step in two: - Unprotected branches (feature/**, bugfix/**, hotfix/**) keep the fast direct-commit path — no protection, no friction. - Protected branches use peter-evans/create-pull-request to open (or update) `chore/sbom-update-` with the regenerated `sbom.cdx.json`, base'd on the same branch. A reviewer merges as with any other PR, so the org ruleset's "1 review" requirement is honoured. - pull_request events skip the commit step entirely. The SBOM is already validated by the preceding scan steps; once the PR merges, this same workflow re-runs against the target branch and goes down one of the two paths above. Adds explicit job-level `permissions: contents: write, pull-requests: write` so the bot can write commits / open PRs without relying on whatever the repo's default permissions happen to be. --- .github/workflows/sbom.yml | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 0d9c190c..e50ecce2 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -6,6 +6,10 @@ on: pull_request: branches: [main, development] +permissions: + contents: write + pull-requests: write + jobs: sbom: runs-on: ubuntu-latest @@ -79,7 +83,18 @@ jobs: - name: npm audit run: npm audit --audit-level=critical - - name: Commit SBOM + # Protected branches (main, development, beta) reject direct pushes per + # the org ruleset, so route SBOM updates through a PR instead. On any + # other branch (feature/**, bugfix/**, hotfix/**) commit + push direct + # since they aren't protected. Skip entirely on pull_request events — + # the SBOM is already validated by the steps above; merging the PR will + # re-trigger this workflow on the target branch. + - name: Commit SBOM (unprotected branches) + if: | + github.event_name == 'push' && + github.ref_name != 'main' && + github.ref_name != 'development' && + github.ref_name != 'beta' run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" @@ -91,6 +106,26 @@ jobs: git push fi + - name: Open PR with SBOM update (protected branches) + if: | + github.event_name == 'push' && + (github.ref_name == 'main' || github.ref_name == 'development' || github.ref_name == 'beta') + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: update SBOM" + title: "chore: update SBOM (auto-generated)" + body: | + Auto-generated SBOM regeneration after a push to `${{ github.ref_name }}`. + + Source run: [${{ github.workflow }} #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}). + + Merge to keep `sbom.cdx.json` in sync with the locked dependency tree on `${{ github.ref_name }}`. + branch: chore/sbom-update-${{ github.ref_name }} + base: ${{ github.ref_name }} + add-paths: sbom.cdx.json + delete-branch: true + - name: Upload SBOM artifact uses: actions/upload-artifact@v4 with: