Reference repo proving we can replace the GitHub Advanced Security features we use — secret scanning, code scanning, dependency alerts — with open-source tools: Gitleaks, Semgrep OSS, OSV-Scanner, and Trivy.
A minimal TypeScript/Express service carries intentionally planted vulnerabilities. Read SECURITY-DEMO.md for the full GHAS-feature mapping, the finding schema, and what we give up.
⚠️ This repo contains intentionally vulnerable code and fabricated credentials for testing. Keep it separate from production code. The secrets are not real (AWS docs example + pattern-valid fakes).
| Layer | When | Blocking? | What runs |
|---|---|---|---|
Agent / local gate (pnpm gate) |
before commit / patch handoff | yes (locally) | Gitleaks + focused Semgrep + OSV |
PR gate (security.yml) |
every PR + push to main | yes | secrets + focused SAST + deps (deps only when lockfiles change) |
Deep scan (deep-scan.yml) |
weekly + manual | no (reports only) | full Gitleaks/Semgrep/OSV/Trivy across main + development → findings artifact |
pnpm gate mirrors the PR gate, so green locally ⇒ green in CI. A coding
agent runs it before handing off a patch; the .husky/pre-commit hook runs the
fast secrets check on every commit.
| Tool | Version | Replaces (GHAS) | What it finds |
|---|---|---|---|
| Gitleaks | 8.30.1 | Secret Scanning | committed secrets / credentials |
| Semgrep OSS | 1.168.0 | Code Scanning (CodeQL) | SAST — injection, unsafe APIs, etc. |
| OSV-Scanner | 2.4.0 | Dependabot alerts | vulnerable dependencies (via osv.dev) |
| Trivy | 0.71.2 | (beyond GHAS) | deps + secrets + IaC/misconfig |
All scanner versions are pinned (binaries by version, semgrep via pipx install semgrep==1.168.0) so local and CI results match.
Gitleaks — secret scanning.
- Agent gate & PR gate:
gitleaks detect --source . --no-git --exit-code 1— scans the working tree; any leak fails. - Pre-commit hook:
gitleaks protect --staged— fast scan of staged changes only. - Deep scan:
gitleaks detectover full git history.
Semgrep OSS — static analysis (rules from the Semgrep Registry).
- Agent gate & PR gate (focused/fast):
--config p/security-audit --config p/owasp-top-ten --config p/expressjs --severity ERROR --error— only high-severity rules can fail the build. - Deep scan (broad): adds
p/default,p/javascript,p/nodejs— wider coverage, reported not enforced.
OSV-Scanner — dependency advisories from the open OSV database.
- Reads
pnpm-lock.yaml; output is piped through.github/scripts/osv_gate.py, which fails only on HIGH/CRITICAL. - PR gate runs it only when
package.json/pnpm-lock.yamlchange; always on push and in the deep scan.
Trivy — multi-scanner, deep scan only.
trivy fs . --scanners vuln,secret,misconfig— its unique value is misconfiguration / IaC scanning (e.g. theDockerfileroot-userDS-0002), which the other three don't cover.
| Tool | Link | How it's used |
|---|---|---|
| Dependabot | docs | weekly npm + github-actions update PRs (.github/dependabot.yml); bumps the SHA-pinned action refs |
| Husky | github | installs the .husky/pre-commit git hook (fast Gitleaks scan) |
| pnpm | pnpm.io | package manager; the committed pnpm-lock.yaml is OSV/Trivy's input |
| GitHub Actions | checkout · upload-artifact | CI runners; every uses: is pinned to a commit SHA, not a floating tag |
The deep scan normalizes all four scanners' output into the gate-agnostic finding schema via .github/scripts/normalize_findings.py and uploads findings-<branch>.ndjson for Company Brain ingestion.
src/
config.ts # PLANT 1+2: hardcoded AWS key + GitHub PAT (Gitleaks)
routes/diagnostics.ts # PLANT 3: command injection (Semgrep)
routes/users.ts # PLANT 4: SQL injection (Semgrep)
package.json # PLANT 5: minimist@1.2.5 (CVE-2021-44906) (OSV)
Dockerfile # PLANT 6: runs as root, no HEALTHCHECK (Trivy misconfig)
scripts/gate.sh # agent / local gate (pnpm gate)
.github/workflows/security.yml # Layer 2: blocking PR gate
.github/workflows/deep-scan.yml # Layer 3: weekly non-blocking deep scan
.github/scripts/osv_gate.py # fail-on-HIGH/CRITICAL gate for OSV
.github/scripts/normalize_findings.py # tool output -> finding schema (NDJSON)
.github/dependabot.yml # npm + github-actions update PRs
.husky/pre-commit # fast local gitleaks secret scan
schema/finding.schema.json # Siege Engine normalized finding schema
schema/sample-findings.ndjson # real findings, schema-validated
pnpm install
brew install gitleaks semgrep osv-scanner trivy
pnpm gate # gitleaks + semgrep + osv; non-zero exit on any findingpnpm install # husky installs the pre-commit hook
pnpm typecheck
pnpm build
pnpm start