diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml new file mode 100644 index 0000000..b70e52d --- /dev/null +++ b/.github/workflows/security-scan.yml @@ -0,0 +1,44 @@ +# Security scanning via Radar CLI (EurekaDevSecOps/radarctl) — secrets (Gitleaks) +# and SCA (Grype). SAST is intentionally left to the existing CodeQL workflow: +# Radar's Opengrep SAST overlaps CodeQL and, on a CLI whose job is to spawn +# processes (`capy run`, deploy adapters shelling to aws/wrangler, clipboard), +# its command-injection rules fire on inherent, by-design behavior rather than +# real vulnerabilities. So Radar here adds the coverage CodeQL does not: +# secret scanning and dependency/SCA. +# +# Runs fully local: no EUREKA_AGENT_TOKEN is configured, so no findings leave +# the runner. The gate enforces the "no criticals/highs to main" policy: radar +# runs with `-t high`, so only high/critical findings fail the job — moderate +# and low findings still print to the log for triage but do not block. +# +# Runs on ubuntu-latest (not the self-hosted CI runner) because Radar's +# scanners run as Docker containers, which ubuntu-latest provides. +name: Security Scan + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + radar: + name: Radar (secrets + SCA) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + node-version: "22" + + - name: Install Radar CLI + run: npm i -g @eurekadevsecops/radar + + # Scans the repo. `-t high` fails the job only on high/critical findings + # (the "no criticals/highs to main" policy); moderate/low still print for + # triage. Gitleaks auto-loads the repo-root .gitleaks.toml allowlist. + - name: Run Radar scan (secrets + SCA) + run: radar scan -s "gitleaks,grype" -t high . diff --git a/.gitleaks.toml b/.gitleaks.toml new file mode 100644 index 0000000..ad700fd --- /dev/null +++ b/.gitleaks.toml @@ -0,0 +1,20 @@ +# Gitleaks configuration for capy-cli. +# +# Radar's secrets scanner (Gitleaks) runs `gitleaks dir ` in CI and +# auto-loads this file. The default ruleset is kept in full (useDefault = true) +# so real secrets in shipped code (src/, bin/, scripts/) still fail the gate. +# +# The test suite hardcodes intentional, obviously-fake credential-shaped +# fixtures — dummy Stripe/connector keys, a throwaway RSA test key, sample +# secret files — so tests can exercise parsing and encrypt/decrypt round-trips. +# None are real secrets, so they must not fail the security gate. Allowlist the +# tests/ tree only. + +[extend] +useDefault = true + +[allowlist] +description = "Test fixtures: intentional fake/example credentials used by the test suite (not real secrets)." +paths = [ + '''tests/.*''', +]