Skip to content

ci: add ThreatCrush PR scanner - #894

Merged
ralyodio merged 1 commit into
masterfrom
feat/threatcrush-pr-scanner
Aug 1, 2026
Merged

ci: add ThreatCrush PR scanner#894
ralyodio merged 1 commit into
masterfrom
feat/threatcrush-pr-scanner

Conversation

@ralyodio

@ralyodio ralyodio commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Adds threatcrush-scan.yml, a PR scanner running the ThreatCrush CLI. Companion to vu1nz-scan.yml — that one is AI-backed and reviews the diff, this is a local static/secrets scan.

CLI runs in the container, nothing hits the web

The CLI is installed with npm i -g @profullstack/threatcrush and executed inside the runner. No scanning API is called and no code leaves the container — matching what packages/scanners/threatcrush already documents: "scans run locally against the host; no account is required." No secrets or API keys needed.

Design notes

  • Node 22 matches mise.toml, and is required for a second reason: the CLI depends on better-sqlite3 ^11.7.0, which ships prebuilds for ABI 127 (Node 22) but not ABI 137 (Node 24). On Node 24 the install falls through to a node-gyp source build and fails.
  • Scans from the repo root so reported paths are repository-relative, then filters to the files the PR changed. Pre-existing findings elsewhere are counted but not attributed, so the gate reflects the PR rather than the repo history.
  • Dependencies are not installed, keeping node_modules out of the scan.
  • Fails on critical/high in changed files. Follows vu1nz-scan.yml throughout: job summary always written, PR comment upserted best-effort, skipped for forks and Dependabot.

Heads-up: packages/scanners/threatcrush is broken

The adapter calls threatcrush scan <path> --json, and its own comment flags --json as assumed. It does not exist. Verified against the published bundle:

.command("scan").description("Scan codebase for vulnerabilities and secrets")
  .argument("[path]", "Path to scan", ".")

scan takes a path and nothing else — only harden accepts --json. So scanArgs() produces a command that errors with unknown option --json, and parseJson() never sees JSON. This workflow parses the CLI's text output instead, so it works today. Fixing the adapter is a separate change (it has tests) — happy to do it if you want.

Verified

Parser exercised against real captured CLI output across four cases: PR touching files with critical findings (fails), medium-only (correctly still fails — that file also has a CRITICAL), unrelated file (passes, 0 findings), and a clean scan (passes). YAML validated.

🤖 Generated with Claude Code

Runs the ThreatCrush CLI against pull requests, alongside vu1nz-scan.yml.
The two are complementary: vu1nz is AI-backed and reviews the diff, this is a
local static/secrets scan.

The CLI runs inside the runner container — installed with npm and executed
locally. No scanning API is called and no code leaves the container, which
matches packages/scanners/threatcrush ('scans run locally against the host;
no account is required').

Node 22 matches mise.toml, and is required for a second reason: the CLI
depends on better-sqlite3 ^11.7.0, which ships prebuilds for ABI 127 (Node 22)
but not ABI 137 (Node 24). On Node 24 the install falls back to a node-gyp
source build and fails.

Scanning happens from the repository root so reported paths are already
repository-relative. Findings are then filtered to the files the PR actually
changed; pre-existing findings elsewhere are counted but not attributed, so
the gate reflects the PR rather than the repository's history. Dependencies
are deliberately not installed, keeping node_modules out of the scan.

Output is parsed from the CLI's text blocks because 'threatcrush scan' has no
machine-readable mode — only 'threatcrush harden' accepts --json, verified
against the published bundle where scan is declared as:

    .command("scan").argument("[path]", "Path to scan", ".")

Follows vu1nz-scan.yml throughout: job summary always written, PR comment
upserted best-effort and skipped for forks and Dependabot, and the pass/fail
decision owned by the report step. Fails on critical or high findings in
changed files.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

ThreatCrush security scan

0 finding(s) in files changed by this PR (scanned 1 changed file(s); 88 further finding(s) elsewhere in the repository are not attributed to this PR).

No new findings in the files this PR changes.

ThreatCrush CLI ran locally in the runner (npm i -g @profullstack/threatcrush); no code left the container.

@ralyodio
ralyodio merged commit 7b29e57 into master Aug 1, 2026
7 checks passed
@ralyodio
ralyodio deleted the feat/threatcrush-pr-scanner branch August 1, 2026 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants