diff --git a/.github/workflows/semgrep.yaml b/.github/workflows/semgrep.yaml new file mode 100644 index 0000000..54c85f3 --- /dev/null +++ b/.github/workflows/semgrep.yaml @@ -0,0 +1,62 @@ +name: SAST (Semgrep) + +# Security-grade static analysis beyond CodeQL (#117). +# +# Semgrep runs a different engine and ruleset from CodeQL (pattern/dataflow +# rules for C#, a general security-audit pack, and a secrets pack), so it +# surfaces issues CodeQL's queries don't. Findings upload to Code Scanning +# (Security tab) as an additional signal; report-only for now (`|| true`) so a +# noisy new ruleset can't block merges — promote to a gate once the baseline is +# clean. +# +# Uses the public Semgrep registry packs, which need no account/login (the free +# Semgrep OSS tier — the "try the free tool first" path the issue calls for). + +on: + pull_request: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: semgrep-${{ github.ref }} + cancel-in-progress: true + +jobs: + semgrep: + name: Semgrep + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + security-events: write + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 + with: + persist-credentials: false + + - name: Setup Python + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: '3.x' + + - name: Install Semgrep + run: pip install semgrep + + - name: Run Semgrep + run: | + semgrep scan \ + --config p/csharp \ + --config p/security-audit \ + --config p/secrets \ + --sarif --output semgrep.sarif \ + --error || true + + - name: Upload Semgrep SARIF + uses: github/codeql-action/upload-sarif@e0647621c2984b5ed2f768cb892365bf2a616ad1 # v4 + with: + sarif_file: semgrep.sarif