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

## AI-Assisted

## Reusable workflow: cppcheck static analysis for C / C++.
##
## Free open-source local-runnable alternative to Coverity Scan -
## complements (does not replace) Coverity, with a different rule
## set and no third-party service dependency. Useful where Coverity
## is disabled (forks of upstream Coverity-registered projects), or
## as a faster pre-Coverity gate.
##
## ## Trust footprint
##
## cppcheck is in the Debian / Ubuntu archive; apt-installed by
## name. No GitHub Marketplace action used.
##
## ## Per-repo configuration: .github/dm-consumer.yml
##
## Per-repo values are read at workflow runtime from
## .github/dm-consumer.yml in the consumer repo. Schema:
##
##   cppcheck:
##     paths:           "<space-separated paths>"   # required
##     prepare-command: "<bash invocation>"         # optional
##
## Missing required keys hard-fail at workflow start. Missing
## optional keys treat as empty (no source-tree prep step).
##
## ## Caller responsibilities
##
## - Define the trigger schedule. Schedule cannot live in
##   workflow_call per G-A-002.
## - Hardcode the owner in 'jobs.<id>.uses:' (G-A-001).
## - Author .github/dm-consumer.yml in the consumer repo with the
##   required keys.
##
## ## Caller example - byte-identical consumer wrapper
##
##   name: cppcheck
##   on:
##     pull_request:
##       branches: [master]
##     push:
##       branches: [master]
##     workflow_dispatch:
##   permissions:
##     contents: read
##   jobs:
##     cppcheck:
##       uses: org-ai-assisted/developer-meta-files/.github/workflows/reusable-cppcheck.yml@master
##       permissions:
##         contents: read
##
## Note: no 'with:' block on the reusable call. Per-repo values
## live in the consumer's .github/dm-consumer.yml, read at runtime.

name: cppcheck (reusable)

on:
  workflow_call:

permissions:
  contents: read

## No 'concurrency:' block - see agents/github-actions.md G-A-006.

jobs:
  cppcheck:
    name: cppcheck
    ## 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
    timeout-minutes: 15

    if: github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request'

    permissions:
      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 cppcheck + yq
        ## Ubuntu 24.04 ships kislyuk's python-yq jq wrapper, which
        ## ci/dm-consumer-load.sh expects.
        uses: org-ai-assisted/developer-meta-files/.github/actions/apt-install-with-cache@master
        with:
          packages: 'cppcheck yq'
          cache-key: ${{ runner.os }}-apt-cppcheck-${{ hashFiles('.github/workflows/reusable-cppcheck.yml') }}

      - name: Load per-repo config from .github/dm-consumer.yml
        id: cfg
        ## See ci/dm-consumer-load.sh for schema rules.
        run: .github/dmf/ci/dm-consumer-load.sh
          cppcheck
          paths
          prepare-command

      - name: Prepare source tree
        if: steps.cfg.outputs.prepare_command != ''
        env:
          PREPARE_COMMAND: ${{ steps.cfg.outputs.prepare_command }}
        run: bash -c "${PREPARE_COMMAND}"

      - name: cppcheck
        ## 'style' deliberately omitted from --enable. cppcheck's
        ## --error-exitcode triggers on ANY finding at any enabled
        ## severity (NOT only the 'error' severity, despite the
        ## flag's name); style findings are typically noisy
        ## (variableScope, constVariablePointer, etc.) and would
        ## fail CI on every PR for repos that haven't been
        ## previously audited. The enable list is hardcoded here -
        ## per-repo override was removed per the consumer-template
        ## architecture (no extra-args, no per-repo enable). Repos
        ## that want broader scope contribute the default change
        ## here.
        ##
        ## --inline-suppr enables 'cppcheck-suppress' inline comments
        ## as the per-line escape hatch.
        ## --error-exitcode=2: any reported finding fails CI.
        ## --quiet drops per-file scan progress lines.
        ##
        ## NB: cppcheck does NOT support '--' as end-of-options
        ## separator (rejected with 'unrecognized command line
        ## option'). Per R-062, do not add it here.
        env:
          CPPCHECK_PATHS: ${{ steps.cfg.outputs.paths }}
        run: |
          # shellcheck disable=SC2086
          cppcheck \
            --enable=warning,performance,portability \
            --inline-suppr \
            --error-exitcode=2 \
            --quiet \
            ${CPPCHECK_PATHS}

      - name: Emit step summary
        if: always()
        ## Route steps.cfg.outputs.paths (sourced from the caller's
        ## .github/dm-consumer.yml) and job.status through env rather
        ## than inlining into the shell command. dm-consumer-load.sh
        ## rejects newlines, but env indirection adds a second layer
        ## that survives refactors and satisfies CodeQL
        ## js/actions/command-injection.
        env:
          CPPCHECK_PATHS: ${{ steps.cfg.outputs.paths }}
          JOB_STATUS: ${{ job.status }}
        run: |
          .github/dmf/ci/step-summary-emit.sh \
            --tool 'cppcheck' \
            --column-header field \
            --row "outcome=${JOB_STATUS}" \
            --row "paths=${CPPCHECK_PATHS}" \
            --row "enable=warning,performance,portability"
