Problem Statement
A security advisory drops (a CVE against a package, or a vulnerable code pattern) and a security engineer has to answer one question fast: where does this touch our code? Interactive search answers it for one repo at a time and only for direct imports. The hard cases — transitive dependencies pinned in lockfiles, vendored copies, and code copied wholesale from the vulnerable project — hide across hundreds of repos, and nobody has a tool that sweeps all of them exhaustively and produces a defensible blast-radius report.
Solution
A security-advisory-scanner recipe: a CLI that takes a CVE ID or a package name (with optional version range), expands it into a set of exhaustive Search Job queries covering direct usage, lockfile pins, vendored paths, and copied-code signatures, runs those jobs in parallel over the Search Jobs API, and aggregates the JSONL results into one report. The report groups findings by repository and classifies each match as direct, transitive, vendored, or copied, so the engineer can hand it to an incident channel as-is.
User Stories
- As a security engineer, I want to pass a CVE ID and get affected repositories back, so that I can size an incident within minutes of an advisory publishing
- As a security engineer, I want to pass a bare package name and ecosystem when no CVE exists yet, so that I can scan ahead of an official advisory
- As a security engineer, I want the CVE resolved to affected package names and version ranges automatically, so that I do not have to read the advisory and translate it into queries myself
- As a security engineer, I want matches in dependency manifests (package.json, go.mod, requirements.txt, pom.xml, Gemfile, Cargo.toml) classified as direct usage, so that I know which teams import the package deliberately
- As a security engineer, I want matches in lockfiles (package-lock.json, yarn.lock, pnpm-lock.yaml, go.sum, poetry.lock, Cargo.lock) classified as transitive, so that I catch repos that never mention the package in a manifest
- As a security engineer, I want matches under vendor directories (vendor/, third_party/, node_modules checked into git) classified as vendored, so that I find copies that dependency scanners miss
- As a security engineer, I want distinctive code signatures from the vulnerable package (function names, unique string literals) searched as content queries, so that I find code copied out of the project entirely
- As a security engineer, I want version-range checking against the pinned versions found in manifests and lockfiles, so that repos already on a fixed version are marked safe instead of flagged
- As a security engineer, I want all queries to run as parallel Search Jobs with live progress, so that a slow job never blocks the sweep
- As a security engineer, I want a single aggregated report grouped by repository with per-match classification and file paths, so that I can assign remediation per team
- As a security engineer, I want the report written as both human-readable markdown and machine-readable JSONL, so that I can paste it into an incident doc and feed it into tooling
- As a security engineer, I want a repo-level severity roll-up (direct beats transitive beats vendored beats copied), so that the report leads with the worst exposure
- As an engineering manager, I want a summary line with total repos affected and counts per classification, so that I can report blast radius upward without reading the detail
- As a platform engineer, I want raw per-job JSONL kept on disk, so that I can re-run aggregation without re-running the jobs
- As a developer running the recipe, I want it to work with only SRC_ENDPOINT and SRC_ACCESS_TOKEN set, so that setup matches every other recipe in the cookbook
- As a developer running the recipe, I want clear errors when my token lacks externalapi scopes, so that I fix auth instead of debugging false empties
- As a viewer of the video, I want a README that stands alone, so that I can run the scan without watching the video
- As a cautious operator, I want a --dry-run flag that prints the generated queries without creating jobs, so that I can review query cost before running an org-wide sweep
Implementation Decisions
- New recipe directory following the cookbook rule: one directory, standalone README, runnable end to end.
- TypeScript under bare node, matching the search-jobs-api recipe's zero-dependency shape. The recipe is about the Search Jobs API, not about a dependency, so no packages.
- CVE resolution uses the OSV.dev public API (no auth, no client library — one fetch call) to map CVE ID to affected packages and version ranges. Offline or air-gapped users can skip resolution by passing package and version range directly.
- Query generation is a pure function: advisory metadata in, list of {query, classification} pairs out. Manifest, lockfile, and vendor-path queries are templated per ecosystem; ecosystems covered at launch: npm, Go, Python, Java/Maven, Ruby, Rust.
- Copied-code signature queries are optional and user-supplied (a --signature flag accepting a literal or regex), since deriving signatures automatically from a CVE is unreliable.
- Jobs are created in parallel and polled independently, reusing the polling shape established by the existing recipes; each job's JSONL streams to disk before aggregation.
- Aggregation is a pure function: JSONL lines plus classification map in, report structure out. Version-range comparison uses a small hand-rolled semver-range check rather than a library.
- Report emitted as markdown to stdout and JSONL to a file; exit code is nonzero when any repo is affected, so the tool composes with CI.
Testing Decisions
- Tests exercise external behavior only: query generation (advisory in, expected query strings out), classification (file path in, classification out), version-range checks (pinned version plus range in, affected verdict out), and aggregation (fixture JSONL in, report out).
- No test touches the network or needs a token. Fixture JSONL files checked into the recipe, following the prior art of the TUI recipe's layout tests and its checked-in JSONL fixtures.
- OSV resolution is tested against a recorded fixture response, not the live API.
Out of Scope
- Automated remediation (opening PRs to bump versions).
- Binary or container-image scanning; this scans source as indexed by Sourcegraph.
- Full SCA-grade transitive resolution (walking dependency graphs); lockfile matching is the transitive signal.
- Continuous monitoring or scheduling; the recipe is a one-shot scan.
- SBOM ingestion or export.
Further Notes
This is recipe three in the Search Jobs API video series. The demo arc for the video: paste a fresh CVE ID, watch four job classes fan out in parallel, end on the markdown report showing a vendored copy that a dependency scanner would have missed — the moment that lands with senior engineers.
Problem Statement
A security advisory drops (a CVE against a package, or a vulnerable code pattern) and a security engineer has to answer one question fast: where does this touch our code? Interactive search answers it for one repo at a time and only for direct imports. The hard cases — transitive dependencies pinned in lockfiles, vendored copies, and code copied wholesale from the vulnerable project — hide across hundreds of repos, and nobody has a tool that sweeps all of them exhaustively and produces a defensible blast-radius report.
Solution
A
security-advisory-scannerrecipe: a CLI that takes a CVE ID or a package name (with optional version range), expands it into a set of exhaustive Search Job queries covering direct usage, lockfile pins, vendored paths, and copied-code signatures, runs those jobs in parallel over the Search Jobs API, and aggregates the JSONL results into one report. The report groups findings by repository and classifies each match as direct, transitive, vendored, or copied, so the engineer can hand it to an incident channel as-is.User Stories
Implementation Decisions
Testing Decisions
Out of Scope
Further Notes
This is recipe three in the Search Jobs API video series. The demo arc for the video: paste a fresh CVE ID, watch four job classes fan out in parallel, end on the markdown report showing a vendored copy that a dependency scanner would have missed — the moment that lands with senior engineers.