Know what a package update brings with it.
The Dependency Impact Gate traces every changed transitive package to its direct cause, measures blast radius, and enforces source-trust and reproducibility policy before a pull request merges.
From a flat diff to a causal review
A package update is rarely one line in the resolved graph. PackageMedic builds a deterministic shortest path from every changed transitive package to the direct dependency responsible for it, separately for each project, framework, and runtime.
Contoso.Web 4.0.0
-> Contoso.Transport 3.2.0
-> Contoso.Json 2.1.0When multiple direct packages reach the same transitive, one canonical path is selected and the other direct roots remain available in structured output. The maximum blast radius is the largest number of changed transitives attributed to one direct root.
Run the gate
package-medic diff origin/main .
package-medic diff origin/main . --format json --output artifacts/impact.json
package-medic diff origin/main . --audit --deprecated --include-transitiveThe gate is evaluated only after both graphs complete. Exit code 0 means the diagnostic threshold and Impact Gate passed; 1 means either gate failed; and2 means the comparison was operationally incomplete.
Define the repository boundary
{
"schemaVersion": 1,
"impact": {
"failOnDowngrade": true,
"failOnDirectToTransitive": true,
"maxAddedPackages": 40,
"maxAddedTransitivePackages": 25,
"failOnSourceChange": true,
"failOnContentChange": true,
"requirePackageSourceMapping": true,
"requireLockedMode": true,
"allowedSources": [
"https://api.nuget.org/v3/index.json",
"https://packages.example.com/v3/index.json"
]
}
}| Property | Default | Policy |
|---|---|---|
failOnDowngrade | true | Reject resolved package downgrades. |
failOnDirectToTransitive | true | Reject losing explicit control of a formerly direct dependency. |
maxAddedPackages | unset | Limit every package added by the comparison. |
maxAddedTransitivePackages | unset | Limit dependency growth outside direct declarations. |
failOnSourceChange | true | Reject a source change or loss/gain of source evidence for a persistent package. |
failOnContentChange | true | Reject a SHA-512 change or loss/gain of hash evidence for the same package ID/version. |
requirePackageSourceMapping | false | Require effective repository source mapping with a usable pattern for every resolved package. |
requireLockedMode | false | Require locked restore and a valid NuGet lock file inside the analysis root. |
allowedSources | empty | Allow only credential-free HTTPS sources or the explicit local value. |
Source trust fails closed when requested
PackageMedic reads bounded source, content-hash, and signature-presence evidence from metadata produced by NuGet restore. It does not contact a private provenance service or expose credentials. Query- or fragment-qualified sources and metadata reached through a symbolic link or junction remain unknown rather than inheriting trust from a base URL. A persistent package losing previously observed source or hash evidence is itself a gated change, even without an explicit source allowlist. If an allowlist is active and a changed package's source cannot be established, the gate reports unknown provenance instead of assuming it is trusted.
Impact policy codes
| Code | Condition |
|---|---|
PMI001 | Package downgrade. |
PMI002 | Direct dependency became transitive. |
PMI003 | Total added-package budget exceeded. |
PMI004 | Added-transitive budget exceeded. |
PMI005 | Package source changed. |
PMI006 | Source is unknown while an allowlist is active. |
PMI007 | Source is outside the allowlist. |
PMI008 | Multiple feeds lack effective repository Package Source Mapping. |
PMI009 | Locked restore is disabled or its in-repository NuGet lock file is missing or invalid. |
PMI010 | Same package ID/version has different SHA-512 content. |
Review it in GitHub
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: GonzMeza/package-medic@v0.6.1
with:
mode: auto
config: .packagemedic.json
audit: 'true'
deprecated: 'true'The job summary shows pass/fail status, dependency growth, source changes, maximum blast radius, and each failed policy with its causal path. Workflow outputs includeimpact-gate-passed, impact-violations,impact-added-direct, impact-added-transitive,impact-max-blast-radius, impact-source-changes, andimpact-content-changes.
Auto mode is for the unprivileged pull_request event. PackageMedic rejectspull_request_target because its default checkout would compare the trusted base against itself; do not execute an untrusted PR head with privileged secrets.