Context
Stage: Pre-commit
Tool: semgrep
Scope: Application source code — frontend (JS/TS/React) and backend (Python, Go, Java, Ruby, etc.)
Parent: (see SAST parent issue)
IaC and Helm/Kustomize are out of scope for this step. IaC security scanning is covered by Step 17 (checkov, tflint) and the existing linting issues #10 and #11.
Why semgrep
At pre-commit time, the goal is instant developer feedback on code being committed. semgrep is the right tool:
- Pattern-based AST scanning — fast enough to run as a blocking hook (sub-second on typical file sets)
- Language-agnostic: a single hook covers Python, Go, Java, JavaScript, TypeScript, Ruby, PHP, Kotlin, Rust, and more — no stack-specific configuration needed in the workflow
semgrep/semgrep-rules registry ships 1000+ security-focused rules maintained by the Semgrep team
- Native
pre-commit hook available — zero custom wrapper code
snyk code (the alternative) requires a cloud API call on every commit — too slow and introduces a network dependency in the pre-commit path
Pre-commit local hook
Add to the consuming repo's .pre-commit-config.yaml:
repos:
- repo: https://github.com/returntocorp/semgrep
rev: v1.x.x
hooks:
- id: semgrep
args:
- --config=auto # uses semgrep registry, auto-selects rules for detected languages
- --error # non-zero exit on findings
- --severity=ERROR # block on ERROR; WARNING is surfaced but non-blocking
Reusable workflow — sast-precommit.yml
CI enforcement: runs semgrep directly in the workflow so PRs from contributors without the local hook are still gated.
name: SAST Pre-commit
on:
workflow_call:
inputs:
severity:
description: 'Minimum severity to fail: ERROR|WARNING|INFO'
default: 'ERROR'
type: string
config:
description: 'Semgrep config — registry alias or path to rules file'
default: 'auto'
type: string
Consuming repo usage
# .github/workflows/sast.yml
name: SAST
on: [pull_request]
jobs:
semgrep:
uses: sparkgeo/github-actions/.github/workflows/sast-precommit.yml@main
with:
severity: ERROR
Rule set strategy
--config=auto automatically selects rules from the Semgrep registry based on the languages detected in the repo. This is the language-agnostic default. For targeted rule sets:
| Stack |
Config value |
| Python |
p/python |
| JavaScript / TypeScript |
p/javascript + p/typescript |
| Go |
p/golang |
| Java |
p/java |
| Django / Flask |
p/django / p/flask |
| React |
p/react |
| OWASP Top 10 (any language) |
p/owasp-top-ten |
Add a .semgrepignore file to exclude generated code, vendored libraries, and test fixtures from scans.
Context
Stage: Pre-commit
Tool:
semgrepScope: Application source code — frontend (JS/TS/React) and backend (Python, Go, Java, Ruby, etc.)
Parent: (see SAST parent issue)
Why semgrep
At pre-commit time, the goal is instant developer feedback on code being committed.
semgrepis the right tool:semgrep/semgrep-rulesregistry ships 1000+ security-focused rules maintained by the Semgrep teampre-commithook available — zero custom wrapper codesnyk code(the alternative) requires a cloud API call on every commit — too slow and introduces a network dependency in the pre-commit pathPre-commit local hook
Add to the consuming repo's
.pre-commit-config.yaml:Reusable workflow —
sast-precommit.ymlCI enforcement: runs
semgrepdirectly in the workflow so PRs from contributors without the local hook are still gated.Consuming repo usage
Rule set strategy
--config=autoautomatically selects rules from the Semgrep registry based on the languages detected in the repo. This is the language-agnostic default. For targeted rule sets:p/pythonp/javascript+p/typescriptp/golangp/javap/django/p/flaskp/reactp/owasp-top-tenAdd a
.semgrepignorefile to exclude generated code, vendored libraries, and test fixtures from scans.