Skip to content

The Drift Log · Provenance, licensing and the paper trail

Verifying License Compatibility for Transitive Dependencies

23 September 2026 · 4 min read · 857 words · established

A wax seal resting on a page of hash digests

Directly vendoring code severs the package graph, hiding transitive copyleft obligations. Here is how to gate imports against license term collisions.

A developer copies a neat, self-contained HTTP routing utility into pkg/vendor/router. The top-level repository had an MIT license file at its root. The developer files a pull request, CI passes, and the code merges.

Six months later, an audit for an enterprise customer or an acquisition diligence process discovers that the router vendors an unbundled radix tree implementation under pkg/vendor/router/internal/radix. That sub-tree carries a GPL-2.0-only header.

By copying the source directly into the internal tree, the dependency graph vanished from your package manager's manifest. The top-level license was a veneer. The transitive dependency carried obligations that your distribution model cannot satisfy.

When you copy third-party code into your repository, software provenance becomes an internal responsibility. If you do not resolve license invariants across the entire transitive tree at import, your licensing posture is not compliance—it is an unverified assumption.

The Transitive Blindspot in Vendored Code

Modern package managers build a graph. When you run a resolver against a declared dependency, modern tooling can inspect declared metadata across the entire tree. But when you vendor source code directly, you sever that graph.

Vendored source files frequently contain:

  • Unattributed utility functions copied from older projects.
  • Sub-modules or directory-level dependencies carrying differing copyleft or notice-heavy terms.
  • Dual-licensed files where specific usage modes trigger restrictive clauses.

Assuming a repository’s root LICENSE applies uniformly to every source file inside it is one of the most common oversights in code maintenance. As we explored in our discussion on why vendoring code without a paper trail is unsecured debt, imported code brings all of its historical legal constraints with it, whether you documented them or not.

When transitive terms conflict—such as combining Apache-2.0 code with GPL-2.0-only code, or linking proprietary application code against an unisolated reciprocal license—the resulting binary cannot be legally distributed under the terms of either license alone.

Invariant Resolution as an Import Gate

Retrospective scanning is the wrong posture for license compliance. Running a scheduled vulnerability or license scanner against your main branch once a week means incompatible code has already landed, developers have built features on top of it, and remediation requires an expensive rewrite or an urgent legal review.

License compatibility should be evaluated as an invariant check before the vendor commit is written:

[Import Request] 
      │
      ▼
[Recursive File Scanner] ──► Parse SPDX-License-Identifier headers
      │                  ──► Hash file contents against known package archives
      ▼
[Compatibility Matrix]   ──► Evaluate (Permitted Root ∧ Transitive Terms)
      │
   ┌──┴───────────────┐
   ▼                  ▼
[PASS: Invariants]  [FAIL: Term Collision]
   │                  │
   ▼                  ▼
[Commit to Tree]    [Block Import & Emit Error]

To resolve license invariants automatically, an ingestion tool must do three things:

  1. Extract file-level declarations: Scan every imported file for SPDX-License-Identifier expressions and embedded copyright headers rather than relying on top-level license files.
  2. Handle multi-level nesting: When vendored code itself vendors other code, traverse the sub-directories recursively. You can read more about tracking nested trees in our note on resolving transitive license obligations in multi-level vendoring.
  3. Execute a deterministic compatibility rule set: A binary truth table must decide if the combination of all discovered terms is compatible with your project's distribution license. For example:
  • Proprietary distribution + MIT: Valid
  • Proprietary distribution + Apache-2.0: Valid (with NOTICE preservation)
  • Proprietary distribution + LGPL-3.0 (static compilation): Invalid
  • Apache-2.0 + GPL-2.0-only: Invalid (patent clause incompatibility)

If the solver encounters a single term that contradicts the parent distribution model, the import must fail immediately at the gate. Capturing this metadata upfront is the only reliable way to guarantee clean history, a concept covered in depth in capturing license metadata at the build-intent gate.

Constructing an Accurate SBOM

A Software Bill of Materials (SBOM) constructed only from your package manager's lockfile is incomplete the moment you vendor code directly. If an auditor asks for a complete accounting of your runtime artifacts, an SBOM that omits vendored code sub-dependencies represents a compliance failure.

For vendored code, each file or directory slice imported must generate an SBOM record containing:

  • The exact upstream commit SHA and repository origin.
  • The cryptographic hash of the imported files.
  • The resolved SPDX expression covering all included files.
  • Any mandatory attribution notices extracted from upstream NOTICE files.

If you cannot mechanically generate these records from your source tree during your build pipeline, you do not have software provenance. You have a folder of source code with an unknown legal surface.

What to Put in Place on Monday

You do not need to rewrite your entire build system to start catching transitive license conflicts. Begin with three concrete checks in your local workflow:

  1. Audit your current vendored directories: Run an open-source scanner (like scancode-toolkit or license-detector) specifically against your vendor/, third_party/, or internal/ folders. Do not scan the root; scan the individual directories to find buried copyleft headers.
  2. Write an explicit compatibility allowlist: Document the exact set of SPDX identifiers permitted in your codebase based on how you ship (e.g., hosted SaaS versus distributed on-premises binaries). Anything outside this list (e.g., GPL-3.0-or-later, AGPL-3.0-only, SSPL-1.0) must require explicit, documented architectural isolation.
  3. Fail vendoring scripts on missing metadata: If your team uses scripts to pull upstream source into the repo, modify them to require an origin commit hash and a scan step before the files are written to disk. If a transitive file introduces an incompatible license, abort the write.

This post supports the longer argument in Vendoring Code Without a Paper Trail Is Unsecured Debt.

Keep reading

Next in the log

The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.