Skip to content

ci(release): shard test gate into 5 isolated parallel processes to el… #13

ci(release): shard test gate into 5 isolated parallel processes to el…

ci(release): shard test gate into 5 isolated parallel processes to el… #13

Workflow file for this run

name: Security Scan
# Pre-launch verification layer. Two legs:
# secret-scan — HARD gate. A committed exchange/broker/LLM key is catastrophic
# for a money-handling agent, so any gitleaks finding fails the
# build. False positives are silenced in .gitleaks.toml, never by
# disabling the gate.
# sast — Semgrep. DIFF-AWARE HARD GATE on pull_request (`semgrep ci`
# fails only on findings introduced by the PR, so the existing
# baseline never blocks); INFORMATIONAL full scan on push.
# deps-osv — osv-scanner over the lockfile, informational (pairs with the
# `bun audit` job in ci.yml). Socket.dev is a GitHub App, not a
# workflow step — install github.com/apps/socket-security to get
# supply-chain PR review; nothing to wire here.
#
# gitleaks runs from its official image (ghcr.io/gitleaks/gitleaks) rather than
# the GitHub Action because this repo is org-owned (general-liquidity), and the
# Action requires a paid GITLEAKS_LICENSE for organizations. The binary/image is
# license-free regardless of owner.
on:
pull_request:
push:
branches:
- main
- v*
jobs:
secret-scan:
name: Secret Scan (gitleaks)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Full history so a secret committed in ANY past commit is caught,
# not just the PR tip.
fetch-depth: 0
- name: gitleaks (hard gate)
# The committed .gitleaks-baseline.json accepts the 67 known-benign
# historic findings (env-var NAMES, test fixtures, the npm-pack
# detector's own samples, the publishable Supabase anon key). Any NEW
# secret in a future commit has a different fingerprint and fails here.
# Regenerate the baseline only after manually confirming a new finding
# is benign: gitleaks git . --config .gitleaks.toml --redact \
# --report-path .gitleaks-baseline.json --report-format json
run: |
docker run --rm -v "${{ github.workspace }}:/repo" \
ghcr.io/gitleaks/gitleaks:latest \
git /repo --config /repo/.gitleaks.toml \
--baseline-path /repo/.gitleaks-baseline.json \
--redact --verbose --exit-code 1
sast:
name: SAST (semgrep)
runs-on: ubuntu-latest
env:
# Rulesets for a TypeScript money CLI: injection, secrets, the general
# audit packs, and Trail of Bits' AI-agent rules. Consumed by both
# `semgrep ci` (via SEMGREP_RULES) and the `semgrep scan` fallback.
SEMGREP_RULES: "p/typescript p/javascript p/secrets p/security-audit p/command-injection p/trailofbits"
SEMGREP_SEND_METRICS: "off"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Full history so `semgrep ci` can compute the merge-base for its
# diff-aware scan on pull requests.
fetch-depth: 0
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Semgrep
run: pip install --quiet semgrep
- name: Semgrep — diff-aware hard gate (pull requests)
# `semgrep ci` scans only what the PR changed against the merge-base, so
# it fails the build on a NEWLY introduced finding while the pre-existing
# baseline never blocks. No token needed — rules come from SEMGREP_RULES.
if: github.event_name == 'pull_request'
run: semgrep ci --sarif --output semgrep.sarif
- name: Semgrep — informational full scan (push)
# On push (post-merge), a full scan would trip on the existing baseline,
# so keep it informational until that baseline is triaged from the SARIF.
if: github.event_name != 'pull_request'
run: >
semgrep scan
--config p/typescript
--config p/javascript
--config p/secrets
--config p/security-audit
--config p/command-injection
--config p/trailofbits
--sarif --output semgrep.sarif
--metrics off || true
- name: Upload SARIF artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: semgrep-sarif
path: semgrep.sarif
if-no-files-found: warn
deps-osv:
name: Dependency Scan (osv-scanner)
runs-on: ubuntu-latest
# Informational: surfaces known-vuln advisories across the dependency tree
# via Google's OSV database, complementing the `bun audit` job in ci.yml.
# Tighten to a hard gate once the noise floor (long-tail crypto transitives)
# is triaged, the same path the bun-audit job documents.
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install & run osv-scanner
run: |
url="$(curl -sSL https://api.github.com/repos/google/osv-scanner/releases/latest \
| grep browser_download_url | grep linux_amd64 | grep -v -E 'sigstore|\.sig|\.pem' \
| head -1 | cut -d '"' -f4)"
curl -sSL "$url" -o osv-scanner && chmod +x osv-scanner
./osv-scanner --recursive --skip-git ./ || true