Sonatype’s 2026 supply-chain report describes a 2025 ecosystem that reused software at machine scale, while synthetic traffic and redundant downloads added strain to the registries everyone depends on. That changes the engineering problem: a team with 600 transitive packages does not become safer by producing a longer SBOM once per quarter.
The useful question is whether the team can explain, update, verify, and replace the code it did not write. Docker’s 2026 report frames third-party libraries, open source, and AI-generated code as expanding inputs to software delivery; Sonatype emphasizes registry-scale reuse and an attacker focus on open source as a delivery channel. Together, those observations point to an operational scorecard, not another annual compliance artifact.
1. Measure control over reuse, not the raw number of packages
A dependency count is an exposure indicator, not a performance metric. A Go service with 40 modules may be harder to maintain than a JavaScript application with 900 packages if the 40 modules include an unmaintained authentication library on its public request path. Conversely, a large frontend tree can be manageable when its lockfile is current, its artifacts are pinned, and updates are automated.
Start with four questions that can be answered for every production repository:
- Can we produce an inventory from the exact revision we are about to deploy?
- How long do security, compatibility, and routine updates wait before a human or automation reviews them?
- Can we trace each important artifact back to a known source and publisher?
- Which runtime dependencies would be difficult to replace because they appear abandoned or have no viable maintainer path?
Those questions intentionally measure control, not purity. Requiring zero dependencies would force teams to rewrite parsers, cryptography, HTTP stacks, and database clients. The better decision rule is: accept reuse when the package has an owner, an update path, and a replacement plan proportionate to its production impact.
2. Make dependency inventory coverage the first score
Your inventory score should answer whether the team knows what is actually shipped, including transitive packages. Do not score a repository as “covered” because someone uploaded a spreadsheet six months ago. Score it when the CI pipeline generates an SBOM or equivalent dependency graph from the same commit, lockfile, container image, or build artifact that is released.
For example, a team building a container can generate a CycloneDX-formatted inventory with Syft during CI:
syft packages oci-dir:./image -o cyclonedx-json > sbom.cdx.json
For application-level inspection, package-manager commands are useful cross-checks. A Node project can inspect its complete resolved tree with npm ls --all --json; a Python build can capture installation resolution using pip install --report report.json -r requirements.txt. Neither command alone proves that the deployed image contains the same components, which is why artifact-level generation is the stronger release control.
| Inventory check | What to measure | Evidence |
|---|---|---|
| Repository coverage | Production repositories with a generated inventory divided by all production repositories | CI job and stored SBOM artifact |
| Release coverage | Deployments linked to an inventory generated from the released artifact | Image digest, build ID, SBOM ID |
| Transitive visibility | Inventories containing resolved indirect dependencies, not only manifest entries | Lockfile or package-manager graph |
| Ownership | High-impact packages with a named internal owner | Repository metadata or service catalog |
3. Treat inventory freshness as a release property
An SBOM becomes stale the moment it is detached from the artifact it describes. This is the subtle failure behind many dependency dashboards: the dashboard reports a package version from a repository scan, while production runs a container assembled from a different branch, a cached layer, or an emergency patch.
Use an inventory freshness measure that is deliberately boring: the percentage of production releases for which the build stored an inventory and linked it to an immutable artifact identifier. For containers, that identifier is normally an image digest rather than a mutable tag such as latest or production. For a binary release, it can be a checksum plus the CI build number.
Set a release gate for services that handle credentials, payment flows, or public traffic: no artifact-to-inventory link, no deployment. Lower-risk internal tools can begin with reporting rather than a hard gate. This distinction avoids turning supply-chain work into a blanket release delay while still preventing the worst case: discovering a critical package issue and being unable to determine which deployed systems contain it.
Track the exceptions. A release bypass is not automatically a failure, but an exception without an expiry date is deferred work disguised as urgency. Record the service, approver, reason, and a review date in the same place that records deployment approvals.
4. Measure update cadence by review age, not just version age
“Outdated dependencies” is too vague to manage. A package can remain on a stable version for years without creating immediate work, while a newly disclosed issue in a direct runtime dependency may require review the same day. The more actionable metric is the age of the oldest unreviewed update, separated by severity and dependency role.
Use three queues: security updates, routine direct-dependency updates, and transitive updates that become actionable through a direct parent. The queues should have different targets because their costs differ. A patch update to a direct HTTP library may have a small regression surface; replacing a transitive serialization component may require upgrading an entire framework.
| Queue | Recommended measure | Useful review rule |
|---|---|---|
| Security | Hours or days from alert to documented decision | Patch, mitigate, accept temporarily, or prove not affected |
| Direct dependencies | Percentage reviewed within a chosen 90-day window | Review version notes, tests, and ownership |
| Transitive dependencies | Oldest unresolved actionable item | Identify the direct parent that controls the upgrade path |
| Major upgrades | Age of the planned migration ticket | Fund it explicitly or choose a replacement |
Do not reward teams merely for merging every automated update. Tools such as Dependabot and Renovate are valuable because they create repeatable pull requests, but a green lockfile update is not a risk assessment. The meaningful event is a recorded decision supported by CI, release notes where relevant, and an owner who will respond if the update breaks production.
5. Score provenance review at the artifact boundary
Inventory tells you what arrived. Provenance review asks whether you have sufficient evidence about where it came from and how it entered your build. This matters because the reports’ shared premise is not only more reuse; it is an ecosystem in which attackers can use open-source distribution as a delivery path.
A practical provenance review does not require every package to have identical metadata. Instead, create a tiered policy. For all production dependencies, retain the package name, version, registry, resolved hash or digest, license information where your organization requires it, and the direct dependency that introduced it. For high-impact components, add source repository location, publisher or maintainer review, release provenance when available, and a signed-artifact or attestation verification path where your tooling supports it.
High impact means the dependency can execute code during build or install, parse untrusted input, handle authentication, provide cryptography, run in a privileged CI job, or be exposed on a public request path. A development-only formatter does not deserve the same manual review as a package that runs post-install scripts in the build pipeline.
The tradeoff nobody mentions is reviewer fatigue. Asking security staff to manually inspect every transitive package creates a queue that will be ignored. Use automation for hashes, lockfiles, registry policy, and attestations; reserve human review for new direct dependencies and high-impact changes.
6. Find abandoned-package exposure before an urgent replacement
“No release in 18 months” is a useful triage signal, not proof that a package is abandoned. Mature libraries can be stable. A more reliable exposure score combines maintenance signals with your own dependency’s importance: time since meaningful activity, unresolved critical issues, a single maintainer, deprecated status, unavailable source, and whether the package is reachable in production.
For each candidate, classify it as monitored, constrained, or replace. A monitored package has a clear reason for low activity and can be pinned with an owner. A constrained package still works but cannot be updated without a wider ecosystem change. A replace item lacks confidence in maintenance, provenance, or future compatibility and needs a migration ticket.
Rank the work by blast radius. An abandoned test helper is usually lower priority than an abandoned URL parser used by every inbound API request. Likewise, a dependency used in one internal batch job is different from one embedded in a shared library consumed by 40 services. Add usage context to the inventory rather than asking maintainers to infer it from a package name.
Every replacement ticket needs an exit criterion: a new package and compatibility tests, an internal fork with a named owner, removal of the feature, or a framework upgrade that eliminates the dependency. “Evaluate alternatives” is not an exit criterion; it is a way to keep the item open forever.
7. Build a 100-point scorecard that drives planning
A score is useful only when it changes a decision. The following model is intentionally simple enough to calculate per service, per team, and across a portfolio. The weights favor basic visibility because no downstream control works if a team cannot identify the shipped dependency set.
| Category | Weight | Example scoring method | Planning consequence |
|---|---|---|---|
| Inventory coverage | 30 | 30 × releases with artifact-linked inventory ÷ total releases | Below 24: fix CI and release linkage first |
| Update cadence | 25 | Score security and direct-update review targets separately | Below 20: create a recurring dependency maintenance lane |
| Provenance review | 25 | High-impact dependencies meeting the tiered review policy | Below 20: review new direct additions before feature work expands the set |
| Abandoned-package exposure | 20 | Deduct for unowned, high-impact constrained or replace items | Below 15: fund migration, fork, or architectural removal |
Do not use this score to compare individual engineers or to reward the team with the fewest packages. Use it to allocate maintenance capacity. A service at 58 with public authentication traffic should receive engineering time ahead of an internal service at 72, even if the internal team has a larger dependency tree.
8. Work through one dependency decision end to end
Consider a checkout API that deploys a container weekly. Its generated SBOM lists 312 components, including a direct payment SDK, a transitive HTTP client, and an old parsing library brought in by a framework plugin. The team’s inventory score is strong because each image digest has a linked SBOM, but its update cadence reveals that the oldest direct-package review is 143 days old.
- The team assigns the payment SDK and HTTP client to the checkout service owner because both run on the public request path.
- Renovate opens a pull request for the HTTP client’s patch update. CI runs unit, integration, and checkout smoke tests; the owner records the result and merges it.
- The parsing library has no clear maintenance activity and is reachable through the framework plugin. The team marks it constrained rather than immediately replacing it, because changing it requires a plugin upgrade.
- The framework upgrade becomes a dated migration ticket with a compatibility test plan. Until then, the team documents the package version, its path in the graph, and the service owner.
- A new direct dependency proposal triggers provenance review before merge: source location, registry package, resolved digest, install behavior, owner, and replacement option.
The key decision is not “remove every old package.” It is to make the risk visible, assign it, and choose whether the next unit of effort belongs in a patch pull request, a funded migration, or a documented temporary acceptance.
9. Put the scorecard into use this week
Begin with one production service rather than launching a company-wide dashboard. Pick a service that deploys regularly and has a lockfile or container image. The goal for the first week is a baseline with evidence, not a perfect score.
- Generate an inventory from the deployed artifact and store it beside the build output.
- List direct runtime dependencies and name an internal owner for each one.
- Identify the oldest unreviewed security item and the oldest unreviewed direct update.
- Flag three packages using abandoned-package signals, then add runtime reachability and replacement difficulty.
- Apply the 100-point scorecard and write down the one category that should receive next sprint capacity.
Review the score monthly and after significant incidents, framework upgrades, or changes to the build system. The reports from Sonatype and Docker describe an environment where reused code is foundational infrastructure and an expanding attack surface. Your team’s advantage comes from making that reuse observable and maintainable at release speed, not from pretending it can be eliminated.