name: OpenGrep — PR Diff

# Runs the high-precision OpenGrep rule super-config against only first-party
# source paths changed by a pull request. Keeping PR scans diff-scoped makes
# findings attributable to the proposed change instead of surfacing unrelated
# repository-wide backlog.
#
# For a repository-wide scan, use the manual OpenGrep — Full workflow.

on:
  pull_request:
    types: [opened, synchronize, reopened, ready_for_review]
    paths:
      - ".github/actions/ensure-base-commit/**"
      - ".github/workflows/opengrep-precise.yml"
      - ".github/workflows/opengrep-precise-full.yml"
      - ".semgrepignore"
      - "apps/**"
      - "extensions/**"
      - "packages/**"
      - "scripts/**"
      - "security/opengrep/**"
      - "src/**"

concurrency:
  group: opengrep-pr-diff-${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
  cancel-in-progress: true

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"

permissions:
  contents: read
  security-events: write

jobs:
  scan:
    name: Scan changed paths (precise)
    if: ${{ !github.event.pull_request.draft }}
    runs-on: blacksmith-4vcpu-ubuntu-2404
    timeout-minutes: 30
    steps:
      - name: Checkout
        uses: actions/checkout@v6
        with:
          ref: ${{ github.sha }}
          fetch-depth: 1
          fetch-tags: false
          persist-credentials: false
          submodules: false

      - name: Ensure PR base commit
        uses: ./.github/actions/ensure-base-commit
        with:
          base-sha: ${{ github.event.pull_request.base.sha }}
          fetch-ref: ${{ github.event.pull_request.base.ref }}

      - name: Install opengrep
        env:
          # Pin both the install script (by commit SHA) and the binary version.
          # The script SHA must match the v1.22.0 release tag in opengrep/opengrep
          # so a compromised or force-pushed `main` cannot RCE in our CI runner.
          # Bump both together when upgrading.
          OPENGREP_VERSION: v1.22.0
          OPENGREP_INSTALL_SHA: f458d7f0d52cc58eae1ca3cf3d5caf101e637519
        run: |
          curl -fsSL "https://raw.githubusercontent.com/opengrep/opengrep/${OPENGREP_INSTALL_SHA}/install.sh" \
            | bash -s -- -v "$OPENGREP_VERSION"
          echo "$HOME/.opengrep/cli/latest" >> "$GITHUB_PATH"

      - name: Verify opengrep
        run: opengrep --version

      - name: Run opengrep on PR diff
        env:
          OPENCLAW_OPENGREP_BASE_REF: ${{ github.event.pull_request.base.sha }}...HEAD
        # Findings from precise rules block this workflow. Pull requests scan
        # changed first-party source paths only so findings stay attributable to
        # the PR diff. Test/fixture/QA path exclusions live in `.semgrepignore`
        # at the repo root and are picked up automatically.
        run: |
          mkdir -p .opengrep-out
          scripts/run-opengrep.sh --changed --sarif --error

      - name: Upload SARIF to GitHub Code Scanning
        uses: github/codeql-action/upload-sarif@v4
        # Only upload if the scan actually produced a SARIF file.
        if: always() && hashFiles('.opengrep-out/precise.sarif') != ''
        with:
          sarif_file: .opengrep-out/precise.sarif
          category: opengrep-pr-diff

      - name: Upload SARIF as workflow artifact
        if: always()
        uses: actions/upload-artifact@v7
        with:
          name: opengrep-pr-diff-sarif
          path: .opengrep-out/precise.sarif
          if-no-files-found: warn
          retention-days: 30
