diff --git a/.github/workflows/self-scan.yml b/.github/workflows/self-scan.yml index 28990542..576b8793 100644 --- a/.github/workflows/self-scan.yml +++ b/.github/workflows/self-scan.yml @@ -26,4 +26,4 @@ jobs: run: npm run build - name: Run CVE Lite CLI against this repo - run: node dist/index.js . --fail-on high + run: node dist/index.js . --verbose --fail-on high diff --git a/README-updated.md b/README-updated.md new file mode 100644 index 00000000..e8ba1fb1 --- /dev/null +++ b/README-updated.md @@ -0,0 +1,460 @@ +
+ CVE Lite CLI + +

CVE Lite CLI

+

Fast, developer-friendly vulnerability scanning for JavaScript and TypeScript projects.

+ + Scan. Prioritize. Fix. + +

+ Quick Start • + Features • + Usage • + Contributing +

+ +
+ +--- + +

+ CVE Lite CLI workflow +

+ +--- + +## What is CVE Lite CLI + +**CVE Lite CLI** helps developers scan their projects for known package vulnerabilities without signing up for an expensive platform. It is built for the moment right before release, when you want a clear answer, a practical fix plan, and a tool you can actually afford to use. + +## Quick start + +Install globally: + +```bash +npm install -g cve-lite-cli +``` + +Then run: + +```bash +cve-lite /path/to/project +``` + +Or run it one-off with `npx`: + +```bash +npx cve-lite-cli /path/to/project +``` + +## Usage + +```bash +# Basic scan +cve-lite /path/to/project + +# Show all findings +cve-lite /path/to/project --all + +# Focus only on urgent findings +cve-lite /path/to/project --min-severity high + +# Show full detailed output, fix plan, paths, and full table +# Recommended for CI logs when you want full context +cve-lite /path/to/project --verbose + +# Fail a build on high severity and above +cve-lite /path/to/project --fail-on high + +# JSON output +cve-lite /path/to/project --json + +# SARIF output +cve-lite /path/to/project --sarif --output reports/scan.sarif +``` + +## What it looks like + +By default, CVE Lite CLI shows a cleaner, calmer, summary-first console view designed for fast local triage. For CI and deeper investigation, run with `--verbose` to include the full detailed output, dependency paths, fix plan, and table view. + + +

+ CVE Lite CLI default output screenshot placeholder +

+ +Verbose examples: + +

+ CVE Lite CLI verbose output screenshot placeholder + CVE Lite CLI verbose output screenshot placeholder + CVE Lite CLI verbose output screenshot placeholder + CVE Lite CLI verbose output screenshot placeholder +

+ +That is the core idea: install it, point it at your project, and immediately get a practical fix plan instead of a wall of raw advisories. + +The final status line also gives the scan a clear ending, which makes terminal use and screenshots easier to read. + +## Why this tool exists + +A lot of developers want a practical dependency scan right before release, but they do not want the cost, complexity, or friction of a larger platform just to answer a simple question: + +**Do we have known vulnerable packages in this project, and what should we fix first?** + +CVE Lite CLI is built for that workflow. + +It focuses on being: + +- fast +- local-first +- easy to understand +- useful in CI +- honest about what it does and does not do + +## Project scope and differentiation + +CVE Lite CLI is intentionally focused. + +It is built for JavaScript and TypeScript dependency scanning, especially in the workflows where developers want a fast local check before release or a simple CI gate during dependency review. + +The project emphasizes: + +- npm, pnpm, and Yarn lockfile support +- direct vs transitive visibility +- top-priority fixes and a suggested remediation plan +- JSON and SARIF output for automation +- a small, reviewable runtime footprint + +That narrow scope is deliberate. CVE Lite CLI is not trying to be a full application security platform or a broad multi-surface scanner. It is trying to be a lightweight, understandable, developer-first tool for teams that want practical vulnerability scanning without extra cost or complexity. + +## Relationship to similar OWASP projects + +CVE Lite CLI is not trying to replace broader OWASP security tooling. + +Its role is narrower and workflow-focused: + +- focused on JavaScript and TypeScript dependency scanning +- designed for fast local checks and simple CI release gates +- centered on direct vs transitive visibility +- built to highlight top-priority fixes and a suggested remediation plan +- intentionally lightweight in runtime footprint and setup + +This section is here to make the scope clear. CVE Lite CLI aims to complement the broader security ecosystem by being a practical, low-friction option for JS/TS dependency checks close to release time. + +## How it works + +CVE Lite CLI follows a simple workflow: + +1. Read a supported lockfile from your project. +2. Resolve package names and versions locally. +3. Match those packages against OSV advisory data. +4. Classify findings as direct or transitive where possible. +5. Highlight the most important fixes first. +6. Produce terminal, JSON, or SARIF output. + +The goal is to keep vulnerability scanning practical, understandable, and easy to act on. + +## What makes it stand out + +- **fast, low-friction workflow** + Run it locally against a project without adopting a large security platform. + +- **practical remediation guidance** + It does not stop at raw advisory output. It highlights top-priority fixes and suggests a fix plan. + +- **direct vs transitive visibility** + The output makes it easier to see whether the risk comes from something you installed directly or from a nested package. + +- **developer-first** + It is optimized for developers working with npm, pnpm, and Yarn lockfiles. + +- **budget-friendly** + It is intended for developers and teams who want useful security checks without paying for a large commercial product. + +- **local-first** + It reads your project locally and uses package/version matching against OSV advisories. + +- **release-focused** + It is especially useful before a release, in CI, or during final dependency cleanup. + +## Features + +### 1. Lockfile-based scanning + +CVE Lite CLI scans resolved dependency versions from: + +- `package-lock.json` +- `pnpm-lock.yaml` +- `yarn.lock` + +It also supports a limited `package.json` fallback for exact pinned direct dependencies. + +### 2. Clear vulnerability output + +Instead of only showing advisory IDs, the CLI reports: + +- package name and version +- severity +- direct vs transitive relationship +- fixed-version hint when available +- advisory IDs +- dependency path hints + +By default, the CLI now presents a cleaner summary-first view, with `--verbose` available for the full detailed output. + +### 3. Top priority fixes + +The CLI highlights the most important issues first, so developers can focus on the findings most likely to matter immediately. + +### 4. Suggested fix plan + +CVE Lite CLI organizes likely remediation work into a practical sequence, such as: + +- direct critical and high issues first +- urgent transitive issues next +- medium direct cleanup after that +- duplicated vulnerable packages to consolidate + +### 5. Parent package hints for transitive issues + +For transitive vulnerabilities, the tool can point to the likely parent dependency to review. That makes the output more actionable than simply saying a nested package is vulnerable. + +### 6. JSON output + +Structured JSON output makes it easier to integrate with scripts, logs, or pipeline artifacts. + +### 7. SARIF output + +CVE Lite CLI supports SARIF (Static Analysis Results Interchange Format) output for security tooling and code-scanning workflows. SARIF is a standardized JSON-based format for security and code analysis results, which means CI systems, scanners, and code analysis platforms can all understand the same output without custom adapters. This is important because it makes CVE Lite CLI more than just a terminal tool: you can export findings into a format that fits modern DevSecOps workflows, archive results as build artifacts, and integrate vulnerability scans into automated release pipelines. For developers and teams, SARIF support helps security results travel cleanly from a local scan into CI/CD and other tooling, instead of being trapped in plain console output. + +Example: + +```bash +cve-lite /path/to/project --sarif --output reports/scan.sarif +``` + +### 8. CI-friendly behavior + +The CLI can be used in CI/CD pipelines and can fail builds based on severity thresholds. + +### 9. Local cache + +It caches advisory detail results locally so repeated scans are faster and make fewer repeated requests. + +### 10. Clear final scan status + +At the end of each run, CVE Lite CLI prints a short final status line so users immediately know whether the scan was clean or whether they should start with the priority fixes above. + +### 11. Small runtime footprint + +This project intentionally keeps runtime dependencies minimal to reduce attack surface and keep the tool easier to review. + +## Dependency footprint + +CVE Lite CLI is intentionally designed with a very small dependency surface. + +**Runtime dependencies** +- `yaml` +- `yarn-lockfile` + +**Development dependencies** +- `@types/node` +- `tsx` +- `typescript` + +This is a deliberate design choice. Because CVE Lite CLI is itself a security-oriented tool, we want to minimize unnecessary third-party packages and keep the runtime as small and reviewable as possible. + +## Example use cases + +CVE Lite CLI is a good fit for: + +- independent developers shipping side projects +- startups watching every tool budget +- consultants doing release checks for client projects +- teams that want a lightweight dependency scan in CI +- developers who want a second opinion alongside other tools +- OSS maintainers who need a practical scan before publishing + +## Supported workflows + +### Local development + +Run it before a release, during dependency cleanup, or after a major package upgrade. + +### CI/CD + +This repository also uses CVE Lite CLI in its own GitHub Actions workflow to scan itself as part of CI. See [`self-scan.yml`](./.github/workflows/self-scan.yml). + +For CI, we recommend using `--verbose` so build logs include the full fix plan, dependency paths, and detailed table output when a scan fails. + +Use it as a release gate in CI: + +```bash +cve-lite . --verbose --fail-on high +``` + +Export SARIF in CI: + +```bash +cve-lite . --verbose --sarif --output reports/scan.sarif +``` + +### Scripted automation + +Use JSON output for custom reporting: + +```bash +cve-lite . --json > cve-lite-report.json +``` + +## Comparison with other tools + +CVE Lite CLI is not trying to be everything for everyone. It is designed to be one of the easiest and most actionable vulnerability scanners for JavaScript and TypeScript developers who want fast release-time checks without the cost and complexity of a full security platform. + +### Where CVE Lite CLI stands out + +Compared with other tools in this space, CVE Lite CLI focuses on: + +- **free to use** +- **fast to run** +- **easy to understand** +- **practical remediation guidance** instead of just raw advisory dumps +- **clear direct vs transitive visibility** +- **top priority fixes** and a suggested fix plan +- support for **npm**, **pnpm**, and **Yarn** lockfiles +- **SARIF** and **JSON** output for CI and automation +- a **lightweight**, **security-conscious** dependency footprint +- a **developer-friendly** option for teams that want useful **CVE scanning without paying for a larger commercial product** + +### At a glance + +| Tool | Best at | Ecosystem scope | Lockfile support | Guided remediation | JSON/SARIF | Best fit | +|---|---|---|---|---|---|---| +| **CVE Lite CLI** | Fast, developer-friendly pre-release CVE scanning | Focused on JS/TS | npm, pnpm, Yarn | **Yes** | **Yes** | Developers and small teams who want a free, practical release-time check | +| `npm audit` | Built-in npm auditing | npm-centric | npm | Basic remediation info | Limited compared to dedicated scanner workflows | Teams already living fully inside npm | +| OSV-Scanner | Broad multi-ecosystem scanning | Broad | Many ecosystems and lockfiles | More general-purpose | Strong machine-readable workflows | Teams needing wider ecosystem coverage | +| Snyk CLI | Broader enterprise security workflows | Broad | Strong ecosystem coverage | Strong commercial guidance | Strong | Teams adopting a larger security platform | +| Socket CLI | Broader package and supply-chain risk visibility | Broad | Multi-ecosystem/package-risk focus | Strong for package risk workflows | Strong | Teams that want more than CVE scanning alone | + +### CVE Lite CLI vs npm audit + +`npm audit` is the built-in default for npm users, which makes it convenient when your workflow is entirely npm-based. + +CVE Lite CLI stands out when you want: + +- support across npm, pnpm, and Yarn lockfiles +- cleaner, more guided console output +- priority fixes and a suggested remediation plan +- a more focused pre-release scanning experience for JS/TS teams + +### CVE Lite CLI vs OSV-Scanner + +OSV-Scanner supports many ecosystems and lockfile types, which makes it broader overall. + +CVE Lite CLI stands out when you want: + +- a narrower, easier-to-understand tool built specifically around JS/TS dependency workflows +- remediation-first output instead of a more general multi-ecosystem scanner experience +- a more approachable local workflow for everyday developers + +### CVE Lite CLI vs Snyk CLI + +Snyk CLI is part of a much broader commercial platform with wider enterprise coverage. + +CVE Lite CLI stands out when you want: + +- a simpler and lighter dependency CVE workflow +- an affordable option for small teams, startups, consultants, and independent developers +- a focused tool for lockfile-based release checks without adopting a larger platform + +### CVE Lite CLI vs Socket CLI + +Socket CLI goes beyond CVEs into broader package and supply-chain risk signals. + +CVE Lite CLI stands out when you want: + +- a focused dependency vulnerability scanner +- a straightforward answer to “what should I fix before release?” +- readable output centered on known vulnerability findings and practical next steps + +### Best fit + +CVE Lite CLI is best for: + +- developers shipping JavaScript or TypeScript applications +- teams that want a lightweight release gate +- maintainers who want actionable vulnerability output without heavy platform overhead +- users who care about simplicity, readability, and fast adoption + +If your goal is a practical developer-first CVE scan right before release, CVE Lite CLI is designed to be one of the most approachable options in that workflow. + +## Philosophy + +CVE Lite CLI is not trying to be everything. + +It is trying to be **one of the easiest and most useful tools for developers who need a practical CVE scan right now**. + +That means: + +- fast setup +- understandable output +- useful remediation guidance +- low friction +- realistic adoption for developers without enterprise budgets + +## Current limitations + +To keep the project honest, here is what it does **not** do in the current version: + +- it does not prove exploitability +- it does not verify runtime reachability +- it does not scan container images, binaries, secrets, or IaC +- it does not replace a full application security program +- it is currently focused on JS/TS dependency scanning + +## Positioning + +CVE Lite CLI is best described as: + +**A fast, developer-friendly dependency vulnerability scanner for JavaScript and TypeScript projects, built for teams that want actionable results without the cost and complexity of a full security platform.** + +## Roadmap ideas + +Planned or possible future improvements include: + +- richer remediation guidance +- stronger CI examples +- broader export improvements +- improved caching options +- better package grouping and deduplication insights +- publishable npm release polish +- GitHub Action or container workflow support + +## Contributing + +This project is being shaped around real-world developer usability. Feedback on output clarity, remediation guidance, ecosystem coverage, and CI usage is especially valuable. + +To get started, see [CONTRIBUTING.md](./CONTRIBUTING.md). + +## Community and support + +CVE Lite CLI is being shaped in public and feedback is welcome. + +If you run into a bug, want to suggest an improvement, or have a lockfile edge case that the tool should handle better, please open an issue in the repository. + +Helpful feedback includes: + +- reproducible bug reports +- real-world lockfile edge cases +- ideas for clearer output and remediation guidance +- CI usage examples +- JSON and SARIF workflow feedback +- comparison feedback based on real usage + +As the project grows, contribution and security guidance will be expanded further in dedicated project docs. + +For bug reports and feature requests, please use [GitHub Issues](https://github.com/sonukapoor/cve-lite-cli/issues). For contribution guidance, see [CONTRIBUTING.md](./CONTRIBUTING.md). For security-related reporting, see [SECURITY.md](./SECURITY.md). + +## License + +MIT diff --git a/assets/default-output.png b/assets/default-output.png new file mode 100644 index 00000000..f6563de9 Binary files /dev/null and b/assets/default-output.png differ diff --git a/assets/verbose-output-1.png b/assets/verbose-output-1.png new file mode 100644 index 00000000..0f27a58b Binary files /dev/null and b/assets/verbose-output-1.png differ diff --git a/assets/verbose-output-2.png b/assets/verbose-output-2.png new file mode 100644 index 00000000..20e8291c Binary files /dev/null and b/assets/verbose-output-2.png differ diff --git a/assets/verbose-output-3.png b/assets/verbose-output-3.png new file mode 100644 index 00000000..912139a7 Binary files /dev/null and b/assets/verbose-output-3.png differ diff --git a/assets/verbose-output-4.png b/assets/verbose-output-4.png new file mode 100644 index 00000000..fec74a8f Binary files /dev/null and b/assets/verbose-output-4.png differ diff --git a/src/cli/args.ts b/src/cli/args.ts index 90b988e5..73f1af09 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -13,6 +13,7 @@ export function parseArgs(argv: string[]): { options: ParsedOptions; projectArg? const arg = argv[i]; if (arg === "-h" || arg === "--help") { options.help = true; continue; } if (arg === "--json") { options.json = true; continue; } + if (arg === "--verbose") { options.verbose = true; continue; } if (arg === "--prod-only") { options.prodOnly = true; continue; } if (arg === "--offline") { options.offline = true; continue; } if (arg === "--all") { options.all = true; continue; } diff --git a/src/cli/help.ts b/src/cli/help.ts index 55b24991..f9b86342 100644 --- a/src/cli/help.ts +++ b/src/cli/help.ts @@ -29,6 +29,7 @@ export function printHelp(): void { "", "Options:", " --json Print JSON output", + " --verbose Show detailed output with fix plan, paths, and full table", " --prod-only Exclude dev dependencies where available", " --fail-on Exit non-zero at or above severity (default: critical)", " --batch-size OSV batch size (default: 100)", diff --git a/src/index.ts b/src/index.ts index c9791276..814c6bf6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,7 +24,8 @@ import { printGroupSummary, printTable, printPathHints, - printFinalStatus + printFinalStatus, + printCompactOutput } from "./output/printers.js"; const { options, projectArg } = parseArgs(process.argv.slice(2)); @@ -84,7 +85,8 @@ async function main() { skippedDependencies: scanInput.skippedDependencies, findings: sorted.map(serializeFinding) }, null, 2)); - } else { + } else if (options.verbose) { + // Verbose output - show all details printSummary(sorted, packages.length, scanInput); printActionSummary(sorted); printPriorityFixes(sorted); @@ -103,6 +105,9 @@ async function main() { } } printFinalStatus(sorted); + } else { + // Simplified output - cleaner, focused view + printCompactOutput(sorted); } const failLevel = normalizeSeverity(options.failOn); diff --git a/src/output/printers.ts b/src/output/printers.ts index b668b60c..e87328a0 100644 --- a/src/output/printers.ts +++ b/src/output/printers.ts @@ -276,3 +276,118 @@ function truncate(value: string, width: number) { if (plain.length <= width) return value; return plain.slice(0, Math.max(0, width - 1)) + "…"; } + +export function printCompactOutput(findings: Finding[]) { + console.log(""); + + if (findings.length === 0) { + console.log(chalk.greenBright("✔ Scan complete. No known vulnerabilities found.")); + console.log(""); + return; + } + + // Vulnerabilities found section + console.log("────────────────────────────────"); + console.log(chalk.bold("📦 Vulnerabilities found")); + console.log("────────────────────────────────\n"); + + // Get top 3 critical/high issues + const urgentFindings = findings + .filter(f => f.severity === "critical" || f.severity === "high") + .slice(0, 3); + + for (const finding of urgentFindings) { + const sevLabel = finding.severity.toUpperCase().padEnd(8); + const typeLabel = finding.relationship === "direct" ? "Direct dependency" : + finding.relationship === "transitive" ? "Transitive dependency" : "Unknown dependency"; + + console.log(`${formatSeverityLabel(sevLabel)} ${chalk.whiteBright(finding.pkg.name)}@${finding.pkg.version}`); + console.log(` ${typeLabel}`); + + if (finding.firstFixedVersion) { + const action = finding.relationship === "direct" + ? `upgrade to ${finding.firstFixedVersion}` + : `upgrade parent chain to resolve ${finding.firstFixedVersion}+`; + console.log(` ${chalk.gray(`Fix: ${action}`)}`); + } else { + const action = finding.relationship === "direct" + ? "review and upgrade directly" + : "upgrade parent chain to resolve"; + console.log(` ${chalk.gray(`Fix: ${action}`)}`); + } + console.log(""); + } + + // Top Priority Fix section + if (urgentFindings.length > 0) { + const topFinding = urgentFindings[0]; + console.log("────────────────────────────────"); + console.log(chalk.bold("🚀 Top Priority Fix")); + console.log("────────────────────────────────\n"); + + if (topFinding.relationship === "direct" && topFinding.firstFixedVersion) { + console.log(`Upgrade ${chalk.whiteBright(topFinding.pkg.name)} → ${topFinding.firstFixedVersion}`); + } else if (topFinding.relationship === "direct") { + console.log(`Upgrade ${chalk.whiteBright(topFinding.pkg.name)} to latest safe version`); + } else { + const parent = getPrimaryParent(topFinding); + if (parent) { + console.log(`Upgrade ${chalk.whiteBright(parent)} to resolve ${topFinding.pkg.name}`); + } else { + console.log(`Upgrade parent chain to resolve ${chalk.whiteBright(topFinding.pkg.name)}`); + } + } + console.log(""); + } + + // Summary + console.log("────────────────────────────────"); + console.log("Summary"); + console.log("────────────────────────────────\n"); + + const counts = { + critical: findings.filter(f => f.severity === "critical").length, + high: findings.filter(f => f.severity === "high").length, + medium: findings.filter(f => f.severity === "medium").length, + low: findings.filter(f => f.severity === "low").length, + unknown: findings.filter(f => f.severity === "unknown").length + }; + + const direct = findings.filter(f => f.relationship === "direct").length; + const transitive = findings.filter(f => f.relationship === "transitive").length; + +const parts: string[] = []; +if (counts.critical > 0) parts.push(chalk.redBright(`${counts.critical} critical`)); +if (counts.high > 0) parts.push(chalk.magenta(`${counts.high} high`)); +if (counts.medium > 0) parts.push(chalk.yellow(`${counts.medium} medium`)); +if (counts.low > 0) parts.push(chalk.green(`${counts.low} low`)); +if (counts.unknown > 0) parts.push(chalk.gray(`${counts.unknown} unknown`)); + +console.log(`${chalk.whiteBright(String(findings.length))} vulnerable packages`); +console.log(parts.join(chalk.gray(" · "))); +console.log( + `${chalk.cyan(String(direct))} ${chalk.white("direct")}` + + `${chalk.gray(" · ")}` + + `${chalk.cyan(String(transitive))} ${chalk.white("transitive")}` +); +console.log(""); + +// Footer +const urgentCount = counts.critical + counts.high; +if (urgentCount > 0) { + console.log( + chalk.redBright( + `✖ Scan complete. ${urgentCount} urgent issue${urgentCount === 1 ? "" : "s"} found.` + ) + ); +} else { + console.log( + chalk.yellow( + `▲ Scan complete. ${findings.length} issue${findings.length === 1 ? "" : "s"} found.` + ) + ); +} +console.log(chalk.gray(`Run with ${chalk.whiteBright("--verbose")} for fix plan, paths, and full table.`)); +console.log(""); +} + diff --git a/src/types.ts b/src/types.ts index a47e38bd..0c74265a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -75,6 +75,7 @@ export type Spinner = { export type ParsedOptions = { json?: boolean; + verbose?: boolean; prodOnly?: boolean; failOn: string; batchSize: string;