From 3a1edbffca8f35ecc719bc64ed07329a8cb44b52 Mon Sep 17 00:00:00 2001 From: Rico Gu Date: Sat, 23 May 2026 21:58:48 +0200 Subject: [PATCH 1/4] ci: add CodeQL advanced workflow with JS/TS and fork PR scanning - Replaces default setup to also analyze javascript-typescript sources (currently only `actions` is scanned). - Uses pull_request_target with explicit PR head checkout and persist-credentials: false so fork PRs are scanned safely without exposing the base-repo token to fork code. - build-mode: none for both languages, so no fork code is executed. - Adds .github/codeql/codeql-config.yml to skip generated bundles (dist/), node_modules, lockfiles, and test fixtures to keep alerts signal-heavy. Default CodeQL setup must be disabled before this can upload SARIF; see PR description for the API call. --- .github/codeql/codeql-config.yml | 26 ++++++++++++ .github/workflows/codeql.yml | 73 ++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 .github/codeql/codeql-config.yml create mode 100644 .github/workflows/codeql.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 0000000..66dffd7 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,26 @@ +name: "SAP/pull-request-semver-bumper CodeQL config" + +# Apply these path filters to every language analyzed. +paths-ignore: + # Generated bundles produced by ncc/webpack — analyzing them duplicates + # alerts already covered by the TS sources and produces noise. + - "**/dist/**" + + # Vendored dependencies. + - "**/node_modules/**" + + # Build artefacts and TypeScript output directories, if any. + - "**/build/**" + - "**/out/**" + - "**/coverage/**" + + # Test fixtures and snapshots — usually not interesting for security scans + # and frequently contain intentionally malformed inputs that trip rules. + - "**/__fixtures__/**" + - "**/__snapshots__/**" + - "**/*.snap" + + # Lockfiles and generated package manifests. + - "**/package-lock.json" + - "**/yarn.lock" + - "**/pnpm-lock.yaml" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..9e4c7cd --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,73 @@ +# CodeQL Advanced setup for SAP/pull-request-semver-bumper +# +# Scans: +# - GitHub Actions workflows and action definitions (language: actions) +# - TypeScript / JavaScript sources (language: javascript-typescript) +# +# Triggers: +# - push to main (baseline analysis of merged code) +# - pull_request_target on main (PR head analysis, including fork PRs) +# - weekly schedule (catches new queries / advisories) +# +# Security model for fork PRs: +# - pull_request_target runs in the BASE repo context using the workflow +# file from main; the fork cannot modify what runs here. +# - We explicitly check out the PR head with persist-credentials: false so +# the base-repo token is never exposed to fork code. +# - build-mode: none for both languages — CodeQL extracts directly from +# source. No `npm install`, no `run:` step executes fork code. + +name: "CodeQL Advanced" + +on: + push: + branches: [main] + pull_request_target: + branches: [main] + schedule: + - cron: '26 1 * * 3' + +permissions: + contents: read + security-events: write + pull-requests: read + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: javascript-typescript + build-mode: none + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + # On pull_request_target, check out the PR head (incl. forks). + # On push/schedule, fall back to the workflow ref. + ref: ${{ github.event.pull_request.head.sha || github.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} + # Do NOT expose the base-repo token to fork code. + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + config-file: ./.github/codeql/codeql-config.yml + # Use the security-and-quality suite to also report quality alerts, + # which the repo ruleset's `code_quality` rule consumes. + queries: security-and-quality + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:${{ matrix.language }}" From 7d74e6d87b0d9e9b81491a3b532339a2ab31ba2b Mon Sep 17 00:00:00 2001 From: Rico Gu Date: Sat, 23 May 2026 22:01:35 +0200 Subject: [PATCH 2/4] ci(codeql): handle same-repo and fork PRs in one workflow - Add `pull_request` trigger so PRs from branches within SAP/pull-request-semver-bumper are analyzed using their own workflow version (lets us iterate on the workflow inside a PR). - Keep `pull_request_target` trigger for fork PRs so SARIF can be uploaded under the base repo for the fork's head SHA. - Add a job-level `if` so each PR is analyzed exactly once: same-repo via pull_request, forks via pull_request_target. - Push and schedule triggers are unchanged. --- .github/workflows/codeql.yml | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 9e4c7cd..b5c25f7 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -6,22 +6,28 @@ # # Triggers: # - push to main (baseline analysis of merged code) -# - pull_request_target on main (PR head analysis, including fork PRs) +# - pull_request on main (PRs from branches within this repo) +# - pull_request_target on main (PRs from forks) # - weekly schedule (catches new queries / advisories) # -# Security model for fork PRs: -# - pull_request_target runs in the BASE repo context using the workflow -# file from main; the fork cannot modify what runs here. -# - We explicitly check out the PR head with persist-credentials: false so -# the base-repo token is never exposed to fork code. +# The job-level `if` ensures each PR is analyzed exactly once: +# - same-repo PRs → pull_request only +# - fork PRs → pull_request_target only +# +# Security model for fork PRs (pull_request_target): +# - Workflow file is read from main; the fork cannot modify what runs. +# - actions/checkout uses persist-credentials: false so the base-repo +# token is never exposed to fork code. # - build-mode: none for both languages — CodeQL extracts directly from -# source. No `npm install`, no `run:` step executes fork code. +# source, no `npm install`, no `run:` step executes fork code. name: "CodeQL Advanced" on: push: branches: [main] + pull_request: + branches: [main] pull_request_target: branches: [main] schedule: @@ -35,6 +41,16 @@ permissions: jobs: analyze: name: Analyze (${{ matrix.language }}) + # Run on push and schedule unconditionally. + # On pull_request: only same-repo PRs (forks handled by pull_request_target). + # On pull_request_target: only fork PRs (same-repo handled by pull_request). + if: >- + github.event_name == 'push' || + github.event_name == 'schedule' || + (github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == github.repository) || + (github.event_name == 'pull_request_target' && + github.event.pull_request.head.repo.full_name != github.repository) runs-on: ubuntu-latest strategy: @@ -50,11 +66,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 with: - # On pull_request_target, check out the PR head (incl. forks). + # On any pull_request[_target], check out the PR head (incl. forks). # On push/schedule, fall back to the workflow ref. ref: ${{ github.event.pull_request.head.sha || github.ref }} repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} - # Do NOT expose the base-repo token to fork code. + # Do NOT expose the base-repo token to checked-out code. persist-credentials: false - name: Initialize CodeQL From 7ff1c478ca4094c8cd13649b4ef9f63dabe03adf Mon Sep 17 00:00:00 2001 From: Rico Gu Date: Sat, 23 May 2026 22:07:23 +0200 Subject: [PATCH 3/4] ci(codeql): inline config to prevent fork tampering with the gate Previously the workflow used `config-file: ./.github/codeql/codeql-config.yml` which, on `pull_request_target` for fork PRs, resolved to the fork's version of that file because actions/checkout had already overlaid the fork's source onto the working directory. A malicious fork could submit a PR carrying a config like: disable-default-queries: true paths-ignore: - "**/*" This would make CodeQL upload an empty SARIF, satisfy the `code_scanning` ruleset rule, and let the fork merge unscanned code. Switch to the `config:` (inline YAML) input on codeql-action/init, which takes precedence over `config-file` and is read from the workflow file itself \u2014 always the trusted version on main when triggered by pull_request_target. --- .github/workflows/codeql.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index b5c25f7..10f20d3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -20,6 +20,10 @@ # token is never exposed to fork code. # - build-mode: none for both languages — CodeQL extracts directly from # source, no `npm install`, no `run:` step executes fork code. +# - The CodeQL configuration (paths-ignore, queries) is provided INLINE +# via the `config:` input rather than read from a file in the working +# directory. This prevents a malicious fork from disabling queries or +# adding broad paths-ignore in their PR to neuter the security gate. name: "CodeQL Advanced" @@ -78,10 +82,30 @@ jobs: with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} - config-file: ./.github/codeql/codeql-config.yml # Use the security-and-quality suite to also report quality alerts, # which the repo ruleset's `code_quality` rule consumes. queries: security-and-quality + # Inline config (NOT config-file) so the fork's working-directory + # version cannot override paths-ignore or disable queries. + config: | + paths-ignore: + # Generated bundles produced by ncc/webpack — analyzing them + # duplicates alerts already covered by the TS sources. + - "**/dist/**" + # Vendored dependencies. + - "**/node_modules/**" + # Build artefacts and TypeScript output directories. + - "**/build/**" + - "**/out/**" + - "**/coverage/**" + # Test fixtures and snapshots. + - "**/__fixtures__/**" + - "**/__snapshots__/**" + - "**/*.snap" + # Lockfiles. + - "**/package-lock.json" + - "**/yarn.lock" + - "**/pnpm-lock.yaml" - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 From 3c7af2e6e70958fa0a8e4983c553703f099681d0 Mon Sep 17 00:00:00 2001 From: Rico Gu Date: Sat, 23 May 2026 22:07:48 +0200 Subject: [PATCH 4/4] ci(codeql): drop now-redundant codeql-config.yml The CodeQL configuration is now provided inline in the workflow's `config:` input (see prior commit). Keeping the file would create two sources of truth and \u2014 worse \u2014 leave a fork-controlled file on disk that future contributors might wire up via `config-file:` again, reintroducing the gate-bypass vulnerability. --- .github/codeql/codeql-config.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .github/codeql/codeql-config.yml diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml deleted file mode 100644 index 66dffd7..0000000 --- a/.github/codeql/codeql-config.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: "SAP/pull-request-semver-bumper CodeQL config" - -# Apply these path filters to every language analyzed. -paths-ignore: - # Generated bundles produced by ncc/webpack — analyzing them duplicates - # alerts already covered by the TS sources and produces noise. - - "**/dist/**" - - # Vendored dependencies. - - "**/node_modules/**" - - # Build artefacts and TypeScript output directories, if any. - - "**/build/**" - - "**/out/**" - - "**/coverage/**" - - # Test fixtures and snapshots — usually not interesting for security scans - # and frequently contain intentionally malformed inputs that trip rules. - - "**/__fixtures__/**" - - "**/__snapshots__/**" - - "**/*.snap" - - # Lockfiles and generated package manifests. - - "**/package-lock.json" - - "**/yarn.lock" - - "**/pnpm-lock.yaml"