## Copyright (C) 2026 - 2026 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

## AI-Assisted

## Reusable workflow: CodeQL static analysis.
##
## Runs CodeQL against the calling repository for a single (language,
## build-mode) tuple and uploads the SARIF result to GitHub
## code-scanning under the caller's Security tab.
##
## ## Trust footprint
##
## github/codeql-action - first-party. Same trust scope as
## actions/checkout, which we already use across the org.
##
## ## Per-repo configuration: .github/dm-consumer.yml (optional)
##
## When a caller passes `dm-consumer-section: <section>`, the
## reusable reads the named section from .github/dm-consumer.yml
## at workflow runtime. Schema per language:
##
##   codeql-python:
##     prepare-command: "<bash invocation>"   # optional
##
##   codeql-cpp:
##     prepare-command: "<bash invocation>"   # optional
##     build-command:   "<bash invocation>"   # required (build-mode=manual)
##
## When `dm-consumer-section` is empty (the universal case for
## consumer-codeql-actions.yml), the reusable does NOT read
## dm-consumer.yml and does not run the prepare / manual-build
## steps. Same applies when the file or named section is absent
## and build-mode is not 'manual' - the steps soft-skip. The
## reusable only HARD-FAILs when build-mode=manual and
## build-command is missing.
##
## ## Caller responsibilities
##
## - Define the trigger (push/pull_request/schedule/workflow_dispatch).
##   Schedule cannot live in a reusable workflow per G-A-002.
## - Hardcode the owner in 'jobs.<id>.uses:' (G-A-001).
## - For c-cpp consumers: author `.github/dm-consumer.yml` with the
##   `codeql-cpp.build-command` (required when build-mode=manual).
## - For python consumers needing pre-CodeQL source-tree prep (e.g.
##   symlinks for genmkfile-tagged '*.py#tag' files): author
##   `.github/dm-consumer.yml` with `codeql-python.prepare-command`.
##
## ## Inputs
##
## - language              (required)  CodeQL language id: actions,
##                                     c-cpp, python, ...
## - build-mode            (optional)  none | autobuild | manual.
##                                     Default 'none'. Use 'manual'
##                                     for c-cpp; pair with
##                                     codeql-cpp.build-command in
##                                     dm-consumer.yml.
## - queries               (optional)  CodeQL query suite. Default
##                                     'security-and-quality'.
## - dm-consumer-section   (optional)  Name of the section in
##                                     .github/dm-consumer.yml to
##                                     read per-repo prepare-command /
##                                     build-command from. Empty
##                                     disables the runtime read.
##                                     Hardcoded in each consumer
##                                     wrapper:
##                                       consumer-codeql-actions.yml: ''
##                                       consumer-codeql-python.yml: 'codeql-python'
##                                       consumer-codeql-cpp.yml:     'codeql-cpp'
##
## ## Caller examples - byte-identical consumer wrappers
##
## (1) consumer-codeql-actions.yml (universal):
##
##   jobs:
##     actions:
##       uses: org-ai-assisted/developer-meta-files/.github/workflows/reusable-codeql.yml@master
##       with:
##         language: actions
##       permissions:
##         security-events: write
##         contents: read
##
## (2) consumer-codeql-python.yml (optional prepare-command via
##     dm-consumer.yml.codeql-python.prepare-command):
##
##   jobs:
##     python:
##       uses: org-ai-assisted/developer-meta-files/.github/workflows/reusable-codeql.yml@master
##       with:
##         language: python
##         dm-consumer-section: codeql-python
##       permissions:
##         security-events: write
##         contents: read
##
## (3) consumer-codeql-cpp.yml (required build-command +
##     optional prepare-command via dm-consumer.yml.codeql-cpp.*):
##
##   jobs:
##     c-cpp:
##       uses: org-ai-assisted/developer-meta-files/.github/workflows/reusable-codeql.yml@master
##       with:
##         language: c-cpp
##         build-mode: manual
##         dm-consumer-section: codeql-cpp
##       permissions:
##         security-events: write
##         contents: read

name: CodeQL (reusable)

on:
  workflow_call:
    inputs:
      language:
        required: true
        type: string
      build-mode:
        required: false
        type: string
        default: none
      queries:
        required: false
        type: string
        default: security-and-quality
      dm-consumer-section:
        required: false
        type: string
        default: ""

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ inputs.language }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  analyze:
    name: Analyze (${{ inputs.language }})
    ## Pinned to ubuntu-24.04 so the apt-packaged yq (kislyuk's
    ## python-yq jq wrapper) remains stable across runner-image
    ## transitions; the config-load step's syntax depends on that
    ## implementation.
    runs-on: ubuntu-24.04

    ## Fork-PR guard: a no-op unless the caller routes pull_request
    ## events into us, in which case it blocks PRs from forks (those
    ## need maintainer review and a manual re-run from a trusted ref).
    if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request'

    timeout-minutes: 30

    permissions:
      ## Required so the CodeQL action can upload SARIF results.
      security-events: write
      ## Checkout / source read.
      contents: read

    env:
      ## Dogfood ref: caller's commit when developer-meta-files is its
      ## own caller (so a PR that modifies the script under test gets
      ## exercised); 'master' for every other caller. Routed through
      ## env for the org-wide env-routing convention (same shape as
      ## JOB_STATUS). The job-level fork-PR guard above is the actual
      ## mitigation for actions/untrusted-checkout.
      DMF_REF: ${{ github.repository == 'org-ai-assisted/developer-meta-files' && github.sha || 'master' }}

    steps:
      - name: Checkout repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
        with:
          persist-credentials: false

      - name: Checkout developer-meta-files (ci/ helpers + step-summary)
        if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
        with:
          repository: org-ai-assisted/developer-meta-files
          ref: ${{ env.DMF_REF }}
          path: .github/dmf
          persist-credentials: false

      - name: Install yq
        if: inputs.dm-consumer-section != ''
        ## Ubuntu 24.04 ships kislyuk's python-yq jq wrapper, which
        ## ci/dm-consumer-load.sh (via codeql-load-config.sh)
        ## expects.
        run: |
          sudo --non-interactive apt-get update --error-on=any
          sudo --non-interactive apt-get install --yes --no-install-recommends yq

      - name: Load per-repo config from .github/dm-consumer.yml
        id: cfg
        if: inputs.dm-consumer-section != ''
        env:
          DM_SECTION: ${{ inputs.dm-consumer-section }}
          BUILD_MODE: ${{ inputs.build-mode }}
        ## See ci/codeql-load-config.sh (build-mode=manual makes
        ## build-command required; otherwise optional).
        run: .github/dmf/ci/codeql-load-config.sh

      ## Pre-init hook - source-tree prep that the extractor must
      ## see. Skipped when dm-consumer.yml.<section>.prepare-command
      ## is absent or empty (the universal case).
      - name: Prepare source tree
        if: steps.cfg.outputs.prepare_command != ''
        env:
          PREPARE_COMMAND: ${{ steps.cfg.outputs.prepare_command }}
        run: bash -c "${PREPARE_COMMAND}"

      - name: Initialize CodeQL
        uses: github/codeql-action/init@7211b7c8077ea37d8641b6271f6a365a22a5fbfa  # v4.36.0
        with:
          languages: ${{ inputs.language }}
          build-mode: ${{ inputs.build-mode }}
          queries: ${{ inputs.queries }}

      ## Manual build path - dm-consumer.yml.<section>.build-command.
      ## Only runs when build-mode=manual.
      - name: Manual build
        if: inputs.build-mode == 'manual'
        env:
          BUILD_COMMAND: ${{ steps.cfg.outputs.build_command }}
        run: bash -c "${BUILD_COMMAND}"

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@7211b7c8077ea37d8641b6271f6a365a22a5fbfa  # v4.36.0
        with:
          category: "/language:${{ inputs.language }}"

      - name: Emit step summary
        if: always()
        ## Route values through env and consume with shell-native
        ## expansion inside run: to avoid expression interpolation
        ## in shell arguments.
        env:
          CODEQL_LANGUAGE: ${{ inputs.language }}
          CODEQL_BUILD_MODE: ${{ inputs.build-mode }}
          CODEQL_QUERIES: ${{ inputs.queries }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_REPOSITORY: ${{ github.repository }}
          JOB_STATUS: ${{ job.status }}
        run: |
          .github/dmf/ci/step-summary-emit.sh \
            --tool "CodeQL (${CODEQL_LANGUAGE})" \
            --column-header field \
            --row "outcome=${JOB_STATUS}" \
            --row "language=${CODEQL_LANGUAGE}" \
            --row "build-mode=${CODEQL_BUILD_MODE}" \
            --row "queries=${CODEQL_QUERIES}" \
            --details-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/security/code-scanning?tool_name=CodeQL"
