feat: add multi-path-same-vuln regression fixture (#528)#761
Conversation
|
Hey @Ayush7614 - this branch is a bit behind main. Could you rebase against main and force-push? Happy to review once it's up to date. |
bb98fe3 to
02ada3d
Compare
|
@sonukapoor Rebased onto latest |
|
Hey, this branch is behind main - could you rebase against the latest main and push? Happy to pick this up for review once it's up to date. |
|
@sonukapoor Rebased onto the latest |
02ada3d to
bfda0d0
Compare
sonukapoor
left a comment
There was a problem hiding this comment.
Clean regression fixture. The two-path scenario is correctly modelled, the mock packument setup is consistent with the existing pattern, and both remediations are explicitly asserted - update-parent-within-range for the body-parser path, upgrade-parent-to-version for the direct express path. Approving.
Craft a minimal express lockfile where qs@6.15.1 and qs@6.14.2 share the same advisory but need different fix commands — npm update qs for the body-parser within-range path and npm install express@4.22.2 for the direct express parent upgrade.
bfda0d0 to
6d394eb
Compare
|
cc: @sonukapoor |
sonukapoor
left a comment
There was a problem hiding this comment.
Thanks for adding this fixture - the scenario is exactly what #528 fixture 3 is meant to cover, and the test structure mirrors the exact-pinned-intermediate describe block cleanly. A few things need attention before this is ready to merge.
The negative assertions are missing
The most important regression guard here is not just "the right command was generated" - it's also "the wrong command was NOT generated". The exact-pinned-intermediate and wrong-parent tests both assert .not.toContain(...) to confirm the wrong remediation path wasn't taken. Right now if resolveNpmTransitiveRemediation returned "upgrade-parent-to-version" for the within-range path, the test would still pass. Please add:
expect(withinRangePlan?.command).not.toContain("npm install express");
expect(parentUpgradePlan?.command).not.toContain("npm update qs");The overrides field in package.json needs a note in the description
The description field doesn't mention that this lockfile is controlled by overrides. The other fixtures that pin specific versions via overrides call this out explicitly and warn against running npm install (since regenerating would produce a different lockfile and break the test). Worth adding the same note here.
readme.md description is slightly misleading
"direct express path" reads as if qs itself is a direct dependency. Both findings are transitive - I'd reword to "express > qs path expects npm install express@4.22.2" for clarity.
| scanInput, | ||
| ); | ||
|
|
||
| expect(withinRangePlan?.command).toBe("npm update qs"); |
There was a problem hiding this comment.
Missing a negative guard here. Add expect(withinRangePlan?.command).not.toContain("npm install express") after this line - otherwise a future change that generates the parent-upgrade command instead of npm update would still pass this test.
| ); | ||
|
|
||
| expect(withinRangePlan?.command).toBe("npm update qs"); | ||
| expect(parentUpgradePlan?.command).toBe("npm install express@4.22.2"); |
There was a problem hiding this comment.
Same here - add expect(parentUpgradePlan?.command).not.toContain("npm update qs") to guard against the remediation type flipping.
| "dependencies": { | ||
| "express": "4.22.1" | ||
| }, | ||
| "overrides": { |
There was a problem hiding this comment.
The description field above doesn't mention that this lockfile is controlled by overrides. The other fixtures that hand-craft their lockfiles (e.g. exact-pinned-intermediate) explicitly warn: "do not regenerate with npm install". Worth adding that here for the same reason - anyone who runs npm install will get a different lockfile and wonder why the test broke.
| | `direct-and-transitive` | npm | Mixed direct and transitive vulnerability output. | | ||
| | `deep-chain-no-fix` | npm | 3-level chain where the intermediate parent range does not cover the fix — expects a parent upgrade, not `npm update`. | | ||
| | `exact-pinned-intermediate` | npm | Same overrides as `deep-chain-no-fix`, but body-parser uses a bare `6.14.2` exact pin (not `~6.14.0`) — no in-range refresh is possible; expects a parent upgrade, not `npm update`. Lockfile is hand-crafted (qs range changed from `~6.14.0`; do not regenerate with `npm install`). | | ||
| | `multi-path-same-vuln` | npm | Same vulnerable package (`qs`) via two intermediate parents with different ranges — `body-parser` path expects `npm update qs`, direct `express` path expects `npm install express@4.22.2`. | |
There was a problem hiding this comment.
"direct express path" reads as if qs itself is a direct project dependency. Both findings are transitive. I'd reword to something like: "express > qs path expects npm install express@4.22.2".
Add negative regression guards, document overrides in the fixture description, and clarify readme wording for the express > qs path.
|
@sonukapoor Thanks for the detailed review — addressed all three points in
Regression test still passes locally. Ready for another look. |
sonukapoor
left a comment
There was a problem hiding this comment.
All three concerns addressed - negative assertions added, overrides documented in package.json description with the regeneration warning, and readme fixed to show the full path. Good to merge.
|
Merged - thank you @Ayush7614! |
Summary
examples/multi-path-same-vuln/for discussion Help wanted: edge case lockfile fixtures for regression testing #528 fixture 3qsadvisory via two paths with different parent ranges — each gets the correct fix commandtests/fixture-scan.test.tsScan output
Produces:
npm update qsfor qs@6.15.1 via body-parser (within-range)npm install express@4.22.2for qs@6.14.2 via express (parent upgrade)Test plan
npm test -- tests/fixture-scan.test.ts -t multi-path-same-vulnnode dist/index.js examples/multi-path-same-vuln --verboseCloses fixture 3 from #528