feat: track direct vs transitive dependencies (v0.4.0)#4
Merged
Conversation
The npm parser already scanned every package in package-lock.json, but
treated them all as if they were direct deps — so a flagged CVE in a
5-level-deep transitive gave no clue which top-level package to update.
This change:
- Adds `isDirect` and `via` to Dependency / DependencyResult
- npm: marks direct deps from packages[""].dependencies; runs BFS over
the reverse-dep graph from package-lock.json to resolve `via`
- PyPI: adds Pipfile.lock parser (JSON, preferred over requirements.txt
when present); uses _meta.pipfile.packages to tag direct vs transitive
- New --direct-only CLI flag and direct-only action input
- Table output appends `via <name>` for flagged transitives
- Markdown output adds a Path column ("direct" / "via X" / "transitive")
- 8 new tests; bumps version to 0.4.0
Smoke-tested against a fresh `npm i express@4.18.2 lodash@4.17.21`
project: 69 deps detected, all transitives correctly attributed to
express via the BFS path.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The npm parser already scanned every package in
package-lock.json, but treated everything as if it were a direct dep — so a CVE in a 5-level-deep transitive gave no clue which top-level package to update. This PR makes direct/transitive a first-class concept.isDirect: booleanandvia?: stringtoDependencyandDependencyResultpackages[""].dependencies; runs BFS over the reverse-dep graph frompackage-lock.jsonto resolve theviadirect dep for each transitiverequirements.txtwhen present); uses_meta.pipfile.packagesto tag direct vs transitive--direct-onlyCLI flag and matchingdirect-onlyaction inputvia <name>for flagged transitives so users know which direct dep to updatePathcolumn (direct/via X/transitive)Smoke test
→ 69 deps detected (2 direct + 67 transitive). All transitives correctly attributed to
expressvia the BFS path. Flagged transitives showvia expressin the details column.ossrisk . --direct-only→ 2 deps (express, lodash).
Why
Without this, a transitive CVE was both undetectable (when only
package.jsonwas used) and unactionable (when the lockfile was used, but the user couldn't tell where the vulnerable package came from). Pulling inPipfile.lockdoes the same expansion for Python users.Test plan
npm test— 8 new tests, 91 total, all greennpm run build— cleannpm itree confirms direct/transitive split andviaaccuracy--direct-onlycorrectly filters to top-level deps🤖 Generated with Claude Code