Dependency Tree Static Analysis¶
Static dependency analysis — instantiates Substrate Lineage Risk Audit
Resolves the full transitive dependency graph of an inherited codebase from its manifests — without running it — to expose the layers of borrowed code the project rests on but never wrote.
A project declares a handful of dependencies; it ships hundreds. Dependency Tree Static Analysis reads the manifests and lockfiles and resolves the complete direct-to-transitive graph, recovering the whole substrate of borrowed code a codebase stands on — and it does this statically, from the build specification, without executing anything. Its purpose here is specifically the audit lens: not merely to list what's declared, but to trace each transitive package back to what pulled it in and where it came from, and thereby pull code that no one on the team wrote or reviewed inside the audit boundary. The distinctive move is deriving the substrate from the build spec, so it maps components that never run in a single test yet still ride along in production.
Example¶
A Java service declares eight direct dependencies. Static analysis of its build file resolves the full tree and reports that those eight drag in around 240 transitive packages — including two different versions of the same serialization library and one package resolved from an unexpected repository rather than the canonical registry. The team wrote none of these and had reviewed none of these; until the tree was resolved, none were inside the audit boundary at all. The map's real value is the lineage: it shows which declared dependency is responsible for each risky transitive one, so ownership of a buried package attaches to a direct choice someone actually made.
How it works¶
- Parse the build spec. Read manifests and lockfiles for the declared dependencies and version constraints.
- Resolve like the build. Compute the transitive closure the way the build system would, ideally from the lockfile so it matches what actually installs.
- Record lineage per edge. For each transitive node, capture the path that pulled it in and, where possible, its source registry or repository.
- Flag structural hazards. Surface version conflicts, duplicate incompatible copies, unpinned ranges, and packages from unexpected sources — all without running the code.
Tuning parameters¶
- Resolution fidelity — declared ranges versus locked/actually-installed versions; lockfile resolution matches reality, manifest-only shows intent.
- Depth cutoff — how many transitive levels to walk; deeper is complete, shallower is legible.
- Source attribution — whether each node records its origin registry; turning it on catches substitution and unexpected-source risk at extra resolution cost.
- Conflict sensitivity — how aggressively to flag duplicate versions, incompatibilities, and unpinned ranges.
- Dev-versus-runtime scope — include build and test dependencies or only shipped ones; a wider net finds more but adds noise.
When it helps, and when it misleads¶
Its strength is turning an eight-line manifest into an honest map of the hundreds of borrowed components actually present, each traced to the direct dependency that brought it in — the assignment of responsibility that inherited code usually lacks.
Its limits are the limits of static resolution. What the build declares can diverge from what actually loads at runtime — dynamic loading, plugins, platform-pinned versions — so the map can be both incomplete and over-complete. More importantly, it maps presence and lineage, not danger: a fully-resolved tree is not a safe tree, and reading it as one is the misuse. Static coordinates can also be made to lie.[1] The discipline is to pair the map with a runtime and vulnerability read, and to verify sources rather than trusting names.
How it implements the components¶
Dependency Tree Static Analysis fills the mapping-and-scoping slice of the archetype — recovering the inherited-code substrate and bringing it into scope:
substrate_lineage_map— it builds the direct-to-transitive graph: the map of borrowed code the project rests on.transitive_dependency_trace— it traces each transitive package back to the declared dependency and source that introduced it.audit_boundary_extension— by enumerating the tree, it pulls previously-invisible transitive code inside the reviewed boundary.
It maps the substrate but does not judge it: known-vulnerability findings are Transitive Vulnerability Scan's job, maintenance and end-of-life state are End-of-Life and Maintainer Activity Check's, and the signed origin of any given artifact is Base Image Provenance Attestation's.
Related¶
- Instantiates: Substrate Lineage Risk Audit — it produces the borrowed-code map the narrower detectors then run over.
- Sibling mechanisms: Transitive Vulnerability Scan · End-of-Life and Maintainer Activity Check · Software Bill of Materials with Lineage · Base Image Provenance Attestation
Notes¶
This map is the substrate the other detectors operate on — a vulnerability scan or an end-of-life check can only be as complete as the tree traced here. A gap in resolution (a dynamically-loaded plugin, a dependency the analysis can't reach) silently caps everything downstream, so the fidelity dials on this tool bound the coverage of the whole audit.
References¶
[1] Dependency confusion is a documented supply-chain attack in which a package sharing only the name of an internal component is pulled from a public registry instead of the intended private one. It is the standard reminder that static tree analysis reads declared coordinates, and coordinates can be made to lie — which is why source attribution, not just names, belongs in the trace. ↩