From 80859ac47ed6189ce8f31100c201b79461a0e009 Mon Sep 17 00:00:00 2001 From: Entlein Date: Mon, 4 May 2026 19:58:40 +0200 Subject: [PATCH 1/2] ci: add explicit top-level permissions to all workflows (least privilege) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scorecard flagged 9 'no topLevel permission defined' alerts (Token- Permissions, security_severity: high). GITHUB_TOKEN's default scope includes write access to most things; opting into 'permissions: read-all' at the workflow level scopes that down to read, then jobs that genuinely need write scopes override locally. Existing job-level permissions blocks (build / sign-object / pr-merged / pr-created / incluster-* / docker-build) are unchanged. Added job-level permissions to bypass.yaml's pr-merged caller — needed because that job invokes incluster-comp-pr-merged.yaml as a reusable workflow. Reusable workflows can't request scopes the caller hasn't granted, so top-level read-all + the implicit no-perms on the caller would starve the called workflow's docker-build / create-release jobs. Mirrors pr-merged.yaml's perms exactly. Closes 9 of 16 open Token-Permissions alerts. The remaining 7 are 'jobLevel X permission set to write' findings that flag legitimate write uses (image push, sigstore signing, security-events upload) — Scorecard wants those audit-acknowledged but they're not removable without breaking the workflow's purpose. --- .github/workflows/benchmark.yaml | 4 ++++ .github/workflows/build.yaml | 4 ++++ .github/workflows/bypass.yaml | 11 +++++++++++ .github/workflows/component-tests.yaml | 4 ++++ .github/workflows/go-basic-tests.yaml | 4 ++++ .github/workflows/incluster-comp-pr-created.yaml | 4 ++++ .github/workflows/incluster-comp-pr-merged.yaml | 4 ++++ .github/workflows/pr-created.yaml | 4 ++++ .github/workflows/pr-merged.yaml | 4 ++++ 9 files changed, 43 insertions(+) diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 12057cd17e..19352cbd01 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -24,6 +24,10 @@ on: required: false type: string +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + concurrency: group: benchmark-${{ github.ref }} cancel-in-progress: true diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index f647ab7ea1..14d9f0ac08 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -18,6 +18,10 @@ on: default: false description: "Build for both amd64 and arm64" +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/bypass.yaml b/.github/workflows/bypass.yaml index be81f0260b..e57856464f 100644 --- a/.github/workflows/bypass.yaml +++ b/.github/workflows/bypass.yaml @@ -2,6 +2,10 @@ name: build on: workflow_dispatch: +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: reset-run-number: runs-on: ubuntu-latest @@ -18,6 +22,13 @@ jobs: pr-merged: needs: reset-run-number + # Scopes the reusable workflow's docker-build / create-release jobs need. + # Mirrors pr-merged.yaml's pr-merged job — required because the top-level + # 'permissions: read-all' caps what the called workflow can request. + permissions: + id-token: write + packages: write + contents: write uses: ./.github/workflows/incluster-comp-pr-merged.yaml with: IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/node-agent diff --git a/.github/workflows/component-tests.yaml b/.github/workflows/component-tests.yaml index c01b09dd8b..ce1aa34375 100644 --- a/.github/workflows/component-tests.yaml +++ b/.github/workflows/component-tests.yaml @@ -60,6 +60,10 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: # ------------------------------------------------------------------- # Detect what changed to decide whether an image rebuild is needed. diff --git a/.github/workflows/go-basic-tests.yaml b/.github/workflows/go-basic-tests.yaml index 0962daa4ce..d0e3aaa5c1 100644 --- a/.github/workflows/go-basic-tests.yaml +++ b/.github/workflows/go-basic-tests.yaml @@ -36,6 +36,10 @@ on: GITGUARDIAN_API_KEY: required: false +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: Check-secret: name: check if secrets are set diff --git a/.github/workflows/incluster-comp-pr-created.yaml b/.github/workflows/incluster-comp-pr-created.yaml index 53c7c4f7e4..1226b0a62c 100644 --- a/.github/workflows/incluster-comp-pr-created.yaml +++ b/.github/workflows/incluster-comp-pr-created.yaml @@ -33,6 +33,10 @@ on: GITGUARDIAN_API_KEY: required: false +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: test: permissions: diff --git a/.github/workflows/incluster-comp-pr-merged.yaml b/.github/workflows/incluster-comp-pr-merged.yaml index 831858e430..5ef83da9b2 100644 --- a/.github/workflows/incluster-comp-pr-merged.yaml +++ b/.github/workflows/incluster-comp-pr-merged.yaml @@ -60,6 +60,10 @@ on: default: false type: boolean +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: docker-build: if: ${{ ((contains(github.event.pull_request.labels.*.name, 'release') || contains( github.event.pull_request.labels.*.name, 'trigger-integration-test')) && github.repository_owner == 'kubescape') || inputs.FORCE }} diff --git a/.github/workflows/pr-created.yaml b/.github/workflows/pr-created.yaml index 76ad4f3cbf..c9a5b5a5ee 100644 --- a/.github/workflows/pr-created.yaml +++ b/.github/workflows/pr-created.yaml @@ -11,6 +11,10 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: pr-created: permissions: diff --git a/.github/workflows/pr-merged.yaml b/.github/workflows/pr-merged.yaml index 1e98658f59..5ac255e7c7 100644 --- a/.github/workflows/pr-merged.yaml +++ b/.github/workflows/pr-merged.yaml @@ -10,6 +10,10 @@ on: workflow_dispatch: +# Default to read-only at the workflow level (least privilege per Scorecard). +# Jobs that need elevated scopes override below. +permissions: read-all + jobs: reset-run-number: runs-on: ubuntu-latest From 47b33c5a982459c04649753b9d9628a92ad46ee4 Mon Sep 17 00:00:00 2001 From: Entlein Date: Wed, 6 May 2026 17:02:43 +0200 Subject: [PATCH 2/2] ci: restore write scopes regressed by top-level read-all MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses CodeRabbit's two findings on PR #39: 1. benchmark.yaml:29 (Minor) — peter-evans/create-or-update-comment needs issues:write + pull-requests:write to post benchmark results to the PR thread. Failure was masked by continue-on-error on the step. Add job-level permissions on 'benchmark'. 2. go-basic-tests.yaml:41 (Major) — github/codeql-action/analyze needs security-events:write to upload SARIF results. Failure was masked by continue-on-error on the CodeQL steps. Add job-level permissions on 'Environment-Test'. Note for #2: this file is invoked as a reusable workflow (workflow_call) from pr-created.yaml's pr-created job, which already grants security-events:write — so the caller envelope is already correct, only the inner job's override was missing. YAML validated. --- .github/workflows/benchmark.yaml | 8 ++++++++ .github/workflows/go-basic-tests.yaml | 9 +++++++++ 2 files changed, 17 insertions(+) diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 19352cbd01..d0ed528394 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -35,6 +35,14 @@ concurrency: jobs: benchmark: runs-on: ubuntu-latest + # Override read-all to keep the 'Comment on PR' step working — the + # peter-evans/create-or-update-comment action requires both + # issues:write and pull-requests:write to post benchmark results. + # CodeRabbit PR #39 finding (benchmark.yaml:29). + permissions: + contents: read + issues: write + pull-requests: write steps: - name: Checkout uses: actions/checkout@v4 diff --git a/.github/workflows/go-basic-tests.yaml b/.github/workflows/go-basic-tests.yaml index d0e3aaa5c1..a3e7831085 100644 --- a/.github/workflows/go-basic-tests.yaml +++ b/.github/workflows/go-basic-tests.yaml @@ -76,6 +76,15 @@ jobs: name: Create cross-platform build # needs: [ Setup-Environment ] runs-on: ubuntu-latest + # Override read-all to let github/codeql-action/analyze upload its + # SARIF results — without security-events:write the upload silently + # fails (masked by continue-on-error on the CodeQL steps). + # NOTE: this is a workflow_call reusable, so the caller must ALSO + # grant security-events:write — pr-created.yaml's pr-created job + # already does. CodeRabbit PR #39 finding (go-basic-tests.yaml:41). + permissions: + contents: read + security-events: write env: GITHUB_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }} CGO_ENABLED: ${{ inputs.CGO_ENABLED }}