From 6341fe9217cf4c8d42aa5dd48f4979bc3ba56a5b Mon Sep 17 00:00:00 2001 From: Goetch Stone Date: Tue, 16 Jun 2026 06:11:55 -0400 Subject: [PATCH 1/3] fix(ci): grant scanner jobs the token scopes they need Both scanner jobs were under-declaring GITHUB_TOKEN permissions, so with the repo default token now read-only they 403'd with 'Resource not accessible by integration': - gitleaks (secret-scan): gitleaks-action v3 lists PR commits via the API on pull_request events -> needs pull-requests: read. - semgrep (Scan): upload-sarif reads the workflow run for context -> needs actions: read (mirrors the working codeql.yml). Least-privilege per-job scopes; repo default stays read-only. --- .github/workflows/ci.yml | 2 ++ .github/workflows/semgrep.yml | 3 +++ 2 files changed, 5 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 280fd5a..3a79109 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,8 @@ jobs: timeout-minutes: 5 permissions: contents: read + # gitleaks-action v3 lists PR commits via the API on pull_request events. + pull-requests: read steps: - uses: actions/checkout@v6 diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index b891a51..af6e694 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -25,6 +25,9 @@ jobs: permissions: contents: read security-events: write + # upload-sarif reads the workflow run for context; without this the SARIF + # upload 403s with "Resource not accessible by integration". + actions: read steps: - uses: actions/checkout@v6 From 6cf6e13b1e09f2c48db51de461c0bb4bdf494fcd Mon Sep 17 00:00:00 2001 From: Goetch Stone Date: Tue, 16 Jun 2026 06:24:26 -0400 Subject: [PATCH 2/3] ci: drop GHAS-only code scanning for the now-private repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Repo is private on a free plan, so GitHub code scanning (CodeQL + SARIF upload) is unavailable. Reconfigure so CI works and still gates, at zero cost: - semgrep.yml: remove the SARIF upload; 'semgrep ci' still exits non-zero on findings, so the Scan job remains a real merge gate. Reduce its token scopes to contents:read. - codeql.yml: deleted — CodeQL can't run on a private repo without GitHub Advanced Security. - (gitleaks pull-requests:read fix from this branch is retained.) Security gates remaining: gitleaks (secrets), semgrep (SAST, exit-code), npm audit (deps), tsc + vitest. Lost: CodeQL dataflow + Security-tab dashboards (require paid GHAS on private). --- .github/workflows/codeql.yml | 44 ------------------------------------ 1 file changed, 44 deletions(-) delete mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml deleted file mode 100644 index 78640c4..0000000 --- a/.github/workflows/codeql.yml +++ /dev/null @@ -1,44 +0,0 @@ -# .github/workflows/codeql.yml -# CodeQL — dataflow / taint analysis. Free for public repos. -# Complementary to Semgrep (pattern-based). Together: comprehensive SAST coverage. -name: CodeQL - -on: - push: - branches: [main] - pull_request: - branches: [main] - schedule: - - cron: "0 9 * * 1" # Mondays 09:00 UTC - -concurrency: - group: codeql-${{ github.ref }} - cancel-in-progress: true - -jobs: - analyze: - name: Analyze (javascript-typescript) - runs-on: ubuntu-latest - timeout-minutes: 360 - permissions: - actions: read - contents: read - security-events: write - - steps: - - uses: actions/checkout@v6 - - - name: Initialize CodeQL - uses: github/codeql-action/init@v4 - with: - languages: javascript-typescript - # Default queries only — security-extended adds noise. - queries: security-and-quality - - - name: Autobuild - uses: github/codeql-action/autobuild@v4 - - - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v4 - with: - category: "/language:javascript-typescript" From 9b3be81491859ac1eb5ee77f890d942af56b7d79 Mon Sep 17 00:00:00 2001 From: Goetch Stone Date: Tue, 16 Jun 2026 06:24:40 -0400 Subject: [PATCH 3/3] ci: semgrep gates via exit code, drop SARIF upload (private repo) Code scanning needs GHAS on private repos. Remove the SARIF upload step; 'semgrep ci' still exits non-zero on findings so the Scan job stays a real merge gate. Token scopes reduced to contents:read. --- .github/workflows/semgrep.yml | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index af6e694..e75f4ac 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -1,6 +1,10 @@ # .github/workflows/semgrep.yml -# Semgrep — pattern-based SAST. Free community ruleset. -# Complementary to CodeQL: catches framework misuse, OWASP patterns, dangerous APIs. +# Semgrep — pattern-based SAST on the free community ruleset. +# `semgrep ci` exits non-zero on findings, so this job GATES merges on its own. +# We don't upload SARIF to the GitHub Security tab: code scanning requires +# GitHub Advanced Security on private repos, which this repo doesn't have. +# The exit-code gate is the security control; the Security-tab UI is just a +# (paid) dashboard we forgo. name: Semgrep on: @@ -24,10 +28,6 @@ jobs: image: semgrep/semgrep permissions: contents: read - security-events: write - # upload-sarif reads the workflow run for context; without this the SARIF - # upload 403s with "Resource not accessible by integration". - actions: read steps: - uses: actions/checkout@v6 @@ -40,12 +40,10 @@ jobs: --config p/nextjs \ --config p/react \ --config p/owasp-top-ten \ - --config p/secrets \ - --sarif \ - --output=semgrep.sarif + --config p/secrets env: - # No SEMGREP_APP_TOKEN — runs on free community rulesets only. - # Findings appear in Security tab via SARIF upload below. + # No SEMGREP_APP_TOKEN — free community rulesets only. Findings fail + # the job (and print in the log); no Security-tab upload. SEMGREP_RULES: >- p/javascript p/typescript @@ -53,9 +51,3 @@ jobs: p/react p/owasp-top-ten p/secrets - - - name: Upload SARIF to GitHub Security - if: always() - uses: github/codeql-action/upload-sarif@v4 - with: - sarif_file: semgrep.sarif