## Reusable workflow: OpenSSF Scorecard - weekly posture audit.
##
## Runs the Scorecard tool against the calling repository, uploads the
## SARIF result as an artifact (14-day retention) and to GitHub
## code-scanning under the caller's Security tab.
##
## ## Trust footprint
##
## OpenSSF (Linux Foundation). Same trust scope as
## github/codeql-action, which we already use across the org.
##
## ## Caller responsibilities
##
## - Define the trigger (branch_protection_rule + schedule). Schedule
##   cannot live in a reusable workflow per GitHub Actions; pick a
##   cron slot that does not collide with other repos in the org.
##   Current org-wide allocation (single source of truth - keep
##   consumer wrappers minimal, do not re-list this table elsewhere):
##
##     derivative-maker:  '0 4 * * 0'
##     helper-scripts:    '30 4 * * 0'
##     kloak:             '0 5 * * 0'
##     security-misc:     '30 5 * * 0'
##     tb-updater:        '0 6 * * 0'
##     msgcollector:      '30 6 * * 0'
##     whonix-firewall:   '0 7 * * 0'
##     Whonix-Installer:  '30 7 * * 0'
##     usability-misc:    '0 8 * * 0'
##     genmkfile:         '30 8 * * 0'
##     Whonix-Starter:    '0 9 * * 0'
## - Grant the job-level permissions block listed in the caller
##   example below (security-events: write, contents: read,
##   actions: read).
## - Hardcode the owner in 'jobs.<id>.uses:'. GitHub Actions does NOT
##   allow the github.* context there (only inputs/vars/needs/matrix);
##   ${{ github.repository_owner }}/... fails workflow load with
##   'Unrecognized named-value: github'. See
##   agents/github-actions.md G-A-001.
##
## ## Push trigger trade-off
##
## The 'push: branches: [master]' trigger is optional per consumer.
## In repos that fire other tag-triggered workflows on master push
## (Dry-run, Lint, builder), Scorecard piling on creates noise. In
## smaller repos the per-commit posture re-check is cheap. Each
## consumer picks.
##
## ## Publishing to OpenSSF transparency log
##
## Default: 'publish_results: false' below keeps results local.
## To opt in: caller adds 'id-token: write' to the permissions
## block AND patches the reusable to set publish_results: true.
## One-way commitment - see https://github.com/ossf/scorecard-action.
##
## ## Caller example
##
##   name: Scorecard
##   on:
##     branch_protection_rule:
##     schedule:
##       - cron: '0 4 * * 0'
##   permissions:
##     contents: read
##   jobs:
##     scorecard:
##       uses: Kicksecure/developer-meta-files/.github/workflows/scorecard.yml@master
##       permissions:
##         security-events: write
##         contents: read
##         actions: read

name: Scorecard (reusable)

on:
  workflow_call:

permissions:
  contents: read

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

jobs:
  analysis:
    name: Scorecard analysis
    runs-on: ubuntu-latest

    ## 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: 10

    permissions:
      security-events: write
      contents: read
      actions: read
      ## Intentionally NOT 'id-token: write'. That is only needed for
      ## publish_results: true; keep us off the OSSF public transparency
      ## log unless the project opts in (one-way commitment).

    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: Run analysis
        uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a  # v2.4.3
        with:
          results_file: results.sarif
          results_format: sarif
          publish_results: false

      - name: Upload SARIF artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a  # v7.0.1
        with:
          name: scorecard-sarif
          path: results.sarif
          retention-days: 14

      - name: Upload to GitHub code scanning
        uses: github/codeql-action/upload-sarif@7211b7c8077ea37d8641b6271f6a365a22a5fbfa  # v4.36.0
        with:
          sarif_file: results.sarif

      - name: Checkout developer-meta-files (step-summary helper)
        if: always() && (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: Emit step summary
        if: always()
        ## Route values through env and consume with shell-native
        ## expansion inside run: to avoid expression interpolation
        ## in shell arguments (CodeQL js/actions/command-injection).
        env:
          JOB_STATUS: ${{ job.status }}
          GITHUB_SERVER_URL: ${{ github.server_url }}
          GITHUB_REPOSITORY: ${{ github.repository }}
        run: |
          .github/dmf/ci/step-summary-emit.sh \
            --tool 'OpenSSF Scorecard' \
            --column-header field \
            --row "outcome=${JOB_STATUS}" \
            --details-url "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/security/code-scanning?tool_name=Scorecard"
