Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions examples/multiple-versions-same-pkg/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions examples/multiple-versions-same-pkg/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "cve-lite-example-multiple-versions-same-pkg",
"version": "1.0.0",
"private": true,
"description": "npm regression fixture: lodash@3.10.1 (via karma) and lodash@4.17.20 (direct) — same package at two versions, each must be a separate finding.",
"license": "MIT",
"dependencies": {
"karma": "1.7.1",
"lodash": "4.17.20"
}
}
2 changes: 2 additions & 0 deletions examples/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Small curated projects committed to the repository. Clone the repo and scan imme
| `wrong-parent` | npm | 3-level transitive chain where the immediate parent's range already covers the fix — expects `npm update js-cookie`, not a parent bump. |
| `no-findings` | npm | Clean project with no known vulnerabilities — demonstrates success output. |
| `dev-only-finding` | npm | Vulnerable package that only appears in devDependencies — classified as a direct finding in full scans and excluded by `--prod-only`. |
| `multiple-versions-same-pkg` | npm | Same package at two installed versions (`lodash@3.10.1` via karma, `lodash@4.17.20` direct) — each version must appear as a separate finding. |
| `any fixture` + `.cve-lite/baseline.json` | any | Run `cve-lite . --ratchet` on any fixture to establish a baseline. Rescan without the flag to see only new findings. `.cve-lite/` directories should NOT be committed from example fixtures. |
| `mal-private-registry` | npm | `node-ipc@9.2.3` with `resolved` pointing to a private registry — demonstrates `Unverifiable (private source)` output for MAL- advisories where the artifact origin cannot be confirmed. |
| `pnpm-mal-private-registry` | pnpm v9 | `node-ipc@9.2.3` resolved from a private registry — demonstrates `Unverifiable (private source)` detection for pnpm v9 lockfiles. |
Expand Down Expand Up @@ -175,6 +176,7 @@ node dist/index.js examples/wrong-parent --verbose
node dist/index.js examples/no-findings
node dist/index.js examples/dev-only-finding --verbose
node dist/index.js examples/dev-only-finding --verbose --prod-only
node dist/index.js examples/multiple-versions-same-pkg --verbose
node dist/index.js examples/lima-site --verbose

# In-repo snapshot: Astro
Expand Down
45 changes: 42 additions & 3 deletions tests/fixture-scan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@ function itWithFixture(name: string, testName: string, testFn: () => void): void
fixtureTest(testName, testFn);
}

function requirePackage(scanInput: ScanInput, name: string): PackageRef {
const pkg = scanInput.packages.find(item => item.name === name);
function requirePackage(scanInput: ScanInput, name: string, version?: string): PackageRef {
const pkg = scanInput.packages.find(
item => item.name === name && (version === undefined || item.version === version),
);
if (!pkg) {
throw new Error(`Expected fixture to include ${name}`);
const versionSuffix = version ? `@${version}` : "";
throw new Error(`Expected fixture to include ${name}${versionSuffix}`);
}
return pkg;
}
Expand Down Expand Up @@ -183,6 +186,42 @@ describe("fixture remediation scans", () => {
);
});

itWithFixture(
"multiple-versions-same-pkg",
"reports lodash@3 and lodash@4 as separate installed packages with correct relationships",
() => {
const scanInput = loadFixture("multiple-versions-same-pkg");
const lodash3 = requirePackage(scanInput, "lodash", "3.10.1");
const lodash4 = requirePackage(scanInput, "lodash", "4.17.20");

expect(scanInput.packages.filter(item => item.name === "lodash")).toHaveLength(2);
expect(lodash3.paths?.every(path => path.length > 2)).toBe(true);
expect(lodash4.paths?.some(path => path.length <= 2)).toBe(true);

const directFinding = findingFor(scanInput, "lodash", {
relationship: "direct",
firstFixedVersion: "4.18.0",
validatedFirstFixedVersion: "4.18.0",
});
directFinding.pkg = lodash4;

const transitiveFinding = findingFor(scanInput, "lodash", {
relationship: "transitive",
firstFixedVersion: "4.18.0",
validatedFirstFixedVersion: "4.18.0",
dependencyPaths: lodash3.paths ?? [],
});
transitiveFinding.pkg = lodash3;

const directPlan = buildSuggestedFixCommandPlan([directFinding], scanInput);
const transitivePlan = buildSuggestedFixCommandPlan([transitiveFinding], scanInput);

expect(directPlan?.command).toBe("npm install lodash@4.18.0");
expect(directPlan?.targets.find(t => t.kind === "direct")?.package).toBe("lodash");
expect(transitivePlan?.targets.find(t => t.kind === "direct")).toBeUndefined();
},
);

it("mal-private-registry fixture - node-ipc resolvedUrl is from a private registry", () => {
const scanInput = loadFixture("mal-private-registry");
const nodeIpc = scanInput.packages.find(p => p.name === "node-ipc");
Expand Down