dennisdoomen / dennisdoomen/packageguard
[Feature]: Add a `packageguard explain <package>` command showing dependency paths and verdict rationale
- Dominant language
- C#
- Stars
- 73
- Forks
- 3
- Avg merge
- 3h
- Merged PRs (30d)
- 20
Description
### Background and motivation
When a build fails on a transitive package, the developer's first two questions are "what is this?" and "why is it in my project?" — and neither is answered by the current output. There is an existing roadmap item for displaying the reason a package was flagged; this proposes going further and making it explorable on demand.
The most frustrating case is a violation on a package the developer has never heard of, pulled in three levels down by something else. Without the dependency path, there is no way to know what to do about it.
**Proposal**
```bash
packageguard explain Newtonsoft.Json
```
```
Newtonsoft.Json 13.0.3
License: MIT (from package metadata)
Feed: nuget.org
Status: ALLOWED (matches allow list entry "MIT")
Required by:
MyApp.Web
-> Microsoft.AspNetCore.Mvc.NewtonsoftJson 8.0.0
-> Newtonsoft.Json 13.0.3
MyApp.Domain
-> Newtonsoft.Json 13.0.3 (direct)
Version resolution:
MyApp.Domain requested [12.0.0, ) -> resolved to 13.0.3
Microsoft.AspNetCore.Mvc.NewtonsoftJson requested [13.0.3, ) -> resolved to 13.0.3
Risk: 22.4 (low)
Legal 1.0 MIT, permissive, license URL valid
Security 2.1 No known vulnerabilities; signed by verified publisher
Operational 3.8 Actively maintained; 2 releases in the last 12 months
```
Design points:
- **The dependency path is the most valuable part.** It converts "some package I have never heard of is blocking my build" into "upgrade or replace this one direct dependency". The lock file already contains the graph, so the data is present.
- **Version resolution detail** explains why a version different from the one requested was selected — a recurring source of confusion in NuGet.
- **Risk factor breakdown** is already computed as `RiskFactorContribution` with rationale text; this simply surfaces it per package on demand rather than only in the HTML report.
- **Explain the verdict, not just the state.** Naming the specific policy rule that allowed or denied the package, and which configuration file it came from, is essential once hierarchical configs and presets are in play.
- **Fuzzy name matching.** Accepting a partial or case-insensitive name and suggesting candidates avoids forcing exact typing of long package identifiers.
- **Reuse the cache.** With `--use-caching` this should be near-instant, which is what makes it something people actually use interactively.
A companion `--why` on a violation in the normal output, showing an abbreviated path inline, would cover the common case without a second command.
### Alternative Concerns
- `dotnet nuget why` covers the dependency path for NuGet, but does not know about policy or risk, and does not cover the npm side.
- Putting all of this in the default output would make it unreadable; on-demand is the right shape.
### Are you willing help with a pull-request?
No
Contributor guide
Research direction
Start at the proposed `packageguard explain ` entry point and inspect how the lock file exposes dependency graphs, how `RiskFactorContribution` stores rationale, and how verdict and cache data are currently produced. Done means an on-demand explanation can show dependency paths, version resolution, risk factors, policy rationale, fuzzy matches, and cached results; the payload names no files or tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- cli, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100