name: "CodeQL action"

on:
  push:
    branches: [main, releases/v*]
  pull_request:
    # Run checks on reopened draft PRs to support triggering PR checks on draft PRs that were opened
    # by other workflows.
    types: [opened, synchronize, reopened, ready_for_review]
  merge_group:
    types: [checks_requested]
  schedule:
    # Weekly on Sunday.
    - cron: '30 1 * * 0'
  workflow_dispatch:

defaults:
  run:
    shell: bash

env:
  CODEQL_ACTION_TESTING_ENVIRONMENT: codeql-action-pr-checks

jobs:
  # Identify the CodeQL tool versions to use in the analysis job.
  check-codeql-versions:
    if: github.triggering_actor != 'dependabot[bot]'
    runs-on: ubuntu-latest
    outputs:
      versions: ${{ steps.compare.outputs.versions }}

    permissions:
      contents: read
      # We currently need `security-events: read` to access feature flags.
      security-events: read

    steps:
    - uses: actions/checkout@v6
    - name: Set up default CodeQL bundle
      id: setup-default
      uses: ./setup-codeql
    - name: Set up linked CodeQL bundle
      id: setup-linked
      uses: ./setup-codeql
      with:
        tools: linked
    - name: Compare default and linked CodeQL bundle versions
      id: compare
      env:
        CODEQL_DEFAULT: ${{ steps.setup-default.outputs.codeql-path }}
        CODEQL_LINKED: ${{ steps.setup-linked.outputs.codeql-path }}
      run: |
        CODEQL_VERSION_DEFAULT="$("$CODEQL_DEFAULT" version --format terse)"
        CODEQL_VERSION_LINKED="$("$CODEQL_LINKED" version --format terse)"
        echo "Default CodeQL bundle version is $CODEQL_VERSION_DEFAULT"
        echo "Linked CodeQL bundle version is $CODEQL_VERSION_LINKED"

        # If we're running on a pull request, run with both bundles, even if `tools: linked` would
        # be the same as `tools: null`. This allows us to make the job for each of the bundles a
        # required status check.
        #
        # If we're running on push or schedule, then we can skip running with `tools: linked` when it would be
        # the same as running with `tools: null`.
        if [[ "$GITHUB_EVENT_NAME" != "pull_request" && "$GITHUB_EVENT_NAME" != "merge_group" && "$CODEQL_VERSION_DEFAULT" == "$CODEQL_VERSION_LINKED" ]]; then
          VERSIONS_JSON='[null]'
        else
          VERSIONS_JSON='[null, "linked"]'
        fi

        # Output a JSON-encoded list with the distinct versions to test against.
        echo "Suggested matrix config for analysis job: $VERSIONS_JSON"
        echo "versions=${VERSIONS_JSON}" >> $GITHUB_OUTPUT

  analyze-javascript:
    if: github.triggering_actor != 'dependabot[bot]'
    needs: [check-codeql-versions]
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-22.04,ubuntu-24.04,windows-2022,windows-2025,macos-14-xlarge,macos-15-xlarge]
        tools: ${{ fromJson(needs.check-codeql-versions.outputs.versions) }}
    runs-on: ${{ matrix.os }}

    permissions:
      contents: read
      security-events: write

    steps:
    - name: Checkout
      uses: actions/checkout@v6
    - name: Initialize CodeQL
      uses: ./init
      id: init
      with:
        languages: javascript
        config-file: ./.github/codeql/codeql-config-javascript.yml
        tools: ${{ matrix.tools }}
    # confirm steps.init.outputs.codeql-path points to the codeql binary
    - name: Print CodeQL Version
      run: >
        "$CODEQL" version --format=json
      env:
        CODEQL: ${{steps.init.outputs.codeql-path}}
    - name: Perform CodeQL Analysis
      uses: ./analyze
      with:
        category: "/language:javascript"
        upload: ${{ (matrix.os == 'ubuntu-24.04' && !matrix.tools && github.event_name != 'merge_group' && 'always' ) || 'never' }}

  analyze-other:
    if: github.triggering_actor != 'dependabot[bot]'
    runs-on: ubuntu-latest

    strategy:
      fail-fast: false
      matrix:
        include:
          - language: actions
          - language: python

    permissions:
      contents: read
      security-events: write

    steps:
    - name: Checkout
      uses: actions/checkout@v6
    - name: Initialize CodeQL
      uses: ./init
      with:
        languages: ${{ matrix.language }}
        build-mode: none
        config: >
          paths-ignore:
            - lib
            - tests
          queries:
            - uses: security-and-quality
    - name: Perform CodeQL Analysis
      uses: ./analyze
      with:
        category: "/language:${{ matrix.language }}"
        upload: ${{ (github.event_name != 'merge_group' && 'always') || 'never' }}
