diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml new file mode 100644 index 00000000000..b8e56f708d9 --- /dev/null +++ b/.github/codeql/codeql-config.yml @@ -0,0 +1,33 @@ +name: Sim CodeQL config + +# Trims the extraction surface. CodeQL parses every matching file into a +# database before a single query runs, and that phase dominates runtime on a +# ~12.7k-file JS/TS tree. Test and fixture code is not attacker-reachable, so +# excluding it costs no real coverage. +# +# paths-ignore applies to analysis. The workflow's `on.pull_request.paths` +# filter is separate and decides whether the run happens at all. +paths-ignore: + - '**/*.test.ts' + - '**/*.test.tsx' + - '**/*.test.js' + - '**/*.spec.ts' + - '**/*.spec.tsx' + - '**/__tests__/**' + - '**/__mocks__/**' + - '**/__fixtures__/**' + - '**/e2e/**' + # Deliberately no '**/test/**' or '**/tests/**'. A directory named `test` is a + # routable Next.js path segment, not necessarily test code: those globs + # excluded the real endpoint + # apps/sim/app/api/organizations/[id]/data-drains/[drainId]/test/route.ts, + # which authorizes, decrypts destination credentials, and makes an outbound + # request. CodeQL's paths-ignore has no `!` negation to carve it back out + # ("The filter pattern characters ?, +, [, ], and ! are not supported and will + # be matched literally"), and the globs only covered 76 of 12,716 files, so + # the naming convention above is the safer filter. + - '**/*.d.ts' + - '**/node_modules/**' + - '**/dist/**' + - '**/.next/**' + - 'apps/docs/content/**' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000000..51b709d5330 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,94 @@ +name: CodeQL + +# Advanced setup, replacing the repo-settings "default setup". +# +# Default setup pinned every scan to a 4-vCPU GitHub-hosted runner with no +# cancel-in-progress, which put PR scans at 30-125 min and re-ran them on every +# push (PR #6183 burned six overlapping runs). None of that is configurable from +# the settings UI, so the config moves into the repo. +# +# Before enabling this, disable default setup or the two will both run: +# gh api -X PATCH repos/:owner/:repo/code-scanning/default-setup -f state=not-configured +# +# The runs-on expression is the same CI_PROVIDER escape hatch as ci.yml and must +# change together with it. + +on: + # Pushes to main are infrequent (merges only), so a full scan per push is + # affordable and is what GitHub recommends pairing with the PR trigger: + # "Scanning code when someone pushes a change, and whenever a pull request is + # created, prevents developers from introducing new vulnerabilities." + push: + branches: [main] + pull_request: + branches: [main, staging] + # `ready_for_review` is not a default activity type, so it has to be listed + # alongside the defaults it replaces. Without it, a PR opened as a draft and + # then marked ready is skipped by the job-level draft guard and never + # rescanned until the next push. + types: [opened, synchronize, reopened, ready_for_review] + paths: + - '**/*.ts' + - '**/*.tsx' + - '**/*.js' + - '**/*.jsx' + - '**/*.mjs' + - '**/*.cjs' + - '.github/workflows/**' + - '.github/actions/**' + - '.github/codeql/**' + schedule: + # Safety net behind the push trigger, and the thing that keeps the + # default-branch alert view fresh when main is quiet. Only fires once this + # file is on the default branch — schedule events ignore other branches. + - cron: '17 8 * * *' + workflow_dispatch: + +# Scheduled main scans must run to completion — only PR pushes supersede. +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + +jobs: + analyze: + name: Analyze ${{ matrix.language }} + runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'ubuntu-latest' }} + timeout-minutes: 60 + if: github.event.pull_request.draft != true + permissions: + security-events: write + contents: read + actions: read + + strategy: + fail-fast: false + matrix: + # One entry covers both JS and TS — `javascript`, `typescript` and + # `javascript-typescript` all resolve to the same extractor + # (github/codeql-action src/languages/builtin.json), so the three + # entries default setup listed were one analysis, not three. + # `javascript-typescript` is the documented spelling. Python dropped: + # 7 files in the tree. + language: [javascript-typescript, actions] + + steps: + - name: Checkout repository + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2 + with: + languages: ${{ matrix.language }} + config-file: ./.github/codeql/codeql-config.yml + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@18420e3271f74589575af831a523c833acda327f # codeql-bundle-v2.26.2 + env: + NODE_OPTIONS: --max-old-space-size=8192 + with: + category: /language:${{ matrix.language }}