Skip to main content

vulkro respond

Incident-response mode for the 3am advisory-drop workflow: given a package + version, or an advisory ID, in under a second, answer "is this in my project?" Walks every lockfile and per-file import once, builds a reverse index, and reports every place the named package shows up (direct or transitive).

The pipeline is deliberately scoped: it does not run the full security scan, it does not validate signatures, it does not call any remote service. It exists for the moment between "a new advisory just dropped" and "do we patch tonight or in the morning."

Usage

vulkro respond --package <NAME@VER> [PATH]
vulkro respond --advisory <ID> [PATH]

Exactly one of --package or --advisory must be passed.

Arguments

ArgumentDescriptionDefault
PATHPath to the project root..

Flags

FlagDescriptionDefault
--advisory <ID>Curated advisory ID. Accepts SUP-COMPROMISE-001..005 (the stable rule-id family for the compromised-release catalog) and specific incident IDs (e.g. INCIDENT-2018-event-stream).(none)
--package <PKG@VER>Explicit package spec. Accepts name@version for npm and Cargo, name==version for PyPI, @scope/pkg@version for scoped npm.(none)
--format, -f <FMT>table (default, human-readable), json, ndjson.table
--no-cacheBypass both the read and the write of the on-disk reverse-index cache. Forces a fresh walk. Useful for timing a cold start or when the cache is suspected stale. Equivalent to VULKRO_DISABLE_CACHE=1.false

Exit codes

CodeMeaning
0Target NOT found in the project: you are not exposed.
1Target found in at least one place.
2Error: bad argument, IO failure, or an unsupported advisory ID.

Note the inversion vs. vulkro scan: here exit 1 means "you are exposed", exit 0 means "you are clean". CI gates that should block on exposure can pipe vulkro respond directly.

How it works

The reverse index is built once per project and consulted on every subsequent call:

  1. Lockfile walkers parse every supported lockfile in the project tree:
    • npm: package-lock.json, npm-shrinkwrap.json
    • Poetry: poetry.lock
    • pip: Pipfile.lock
    • Cargo: Cargo.lock
    • Go: go.sum
  2. Per-file import extraction runs over JavaScript, TypeScript, Python, Go, and Rust source files to catch direct import / require / use mentions of the target package.
  3. The merged (package, version) -> [places] map is written to the on-disk cache.

The cache lives at:

~/.vulkro/cache/<short-blake3-of-root>/reverse-index-v1.json

The short BLAKE3 hash of the project's canonical root path scopes the cache per-project so two repos cannot collide.

Cache invalidation: the index is considered stale and rebuilt whenever any lockfile under the project tree changes (mtime, length, new file, or removed file). Source-file edits do not invalidate the index by themselves: the package-membership question only changes when lockfiles change. Pass --no-cache to bypass the cache entirely.

Cold-start wall-clock is well under one second on a typical project.

CVE IDs

--advisory CVE-2024-... returns an actionable error:

error: CVE-* IDs are not supported by `vulkro respond`. CVE matching
uses version-range membership against the local CVE bundle; this
command only does exact-string `name@version` lookups. Try:
vulkro respond --package <name>@<version> .
or run a full scan:
vulkro scan .

vulkro respond answers an exact-version question. CVE-* advisories have a version-range shape that vulkro scan + vulkro match-cve already resolve.

Examples

# Specific package + version.
vulkro respond --package [email protected] .

# Scoped npm.
vulkro respond --package @solana/[email protected] .

# PyPI uses `==` instead of `@`.
vulkro respond --package requests==2.31.0 .

# Stable advisory family ID covers every catalog incident of that kind.
vulkro respond --advisory SUP-COMPROMISE-001 .

# Specific historical incident.
vulkro respond --advisory INCIDENT-2018-event-stream .

# JSON for tooling pipelines.
vulkro respond --package [email protected] . --format json | jq '.matches[]'

# Skip the cache (fresh walk, no write).
vulkro respond --package ctx==0.2.2 . --no-cache