test: stabilize full-suite for CI (stale skill-guard assertions, env/… #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |