Skip to content

The Drift Log · Provenance, licensing and the paper trail

Linking SBOM Entries to Exact Source Commits

30 September 2026 · 4 min read · 846 words · established

A wax seal resting on a page of hash digests

Semver tags and mutable package identifiers leave audit trails broken. Pin SBOM entries directly to upstream commit hashes and tree digests.

Most Software Bill of Materials (SBOM) manifests are declarations of intent, not records of fact.

A standard build pipeline generates an SBOM by inspecting top-level manifest files. The resulting document asserts that your artifact contains upstream-auth at version 2.4.1 under an MIT license. If an auditor asks to see the exact upstream source to verify that an external contributor's header did not introduce a conflicting GPL requirement, the trail goes cold.

Semantic version tags are mutable. Upstream repositories rebase, force-push release tags, delete branches, or quietly replace release tarballs. If an internal engineer vendored a patch directly into the tree to fix an edge case, the version string 2.4.1 describes code that exists nowhere outside your own repository.

An SBOM without an immutable commit hash cannot verify provenance. When provenance cannot be verified, license compliance rests entirely on assumption. As we explore in our core note on why vendoring code without a paper trail is unsecured debt, unanchored third-party code behaves like an unhedged legal liability.

The Gap Between Version Strings and Source Trees

The primary failure mode in modern software supply chains is the assumption that a package identifier (PURL) is an immutable reference. It is not.

Consider what happens during standard dependency resolution:

  1. A build tool requests version 1.8.0 of a library.
  2. The package registry resolves this to an archive uploaded by a maintainer.
  3. The local build extracts the archive into the build tree.

If that dependency is instead vendored directly into your source control, the disconnect deepens. A developer copies files from an upstream repository, creates a local commit, and notes the version in a documentation file.

From that moment, the connection to the upstream origin is broken. If the upstream project later changes its license terms in a minor release, or if the local developer cherry-picked logic across multiple upstream branches, an auditor cannot determine which license obligations apply to which lines of code.

To establish defensible license compliance, every third-party component in your SBOM must resolve directly to a cryptographic commit hash from the upstream repository, alongside the exact hash of the local tree snapshot.

Capturing Provenance at the Build-Intent Gate

You cannot reconstruct exact provenance after the build completes. If you wait until artifacts are packaged, the metadata generator must infer origins from lockfiles that may already be stale or incomplete.

Provenance must be captured at the point of ingestion. When code enters your boundary—whether fetched by a package manager, pulled down by an automated workflow, or committed by an engineer—it must pass through an intake check. We detail this boundary enforcement in capturing license metadata at the build-intent gate.

At this gate, the intake process records three distinct values before allowing the source into the tree:

  1. The Origin URL: The canonical repository remote (e.g., https://github.com/org/repo.git).
  2. The Source Commit Hash: The full 40-character hex SHA-1 or 64-character SHA-256 identifying the exact upstream commit object.
  3. The Content Digest: The hash of the directory tree or archive payload as imported.
{
  "type": "library",
  "name": "crypto-primitives",
  "version": "1.4.2",
  "purl": "pkg:generic/crypto-primitives@1.4.2?vcs_url=git%2Bhttps://github.com/example/crypto-primitives.git@7f8a9d3e5b6c4a1b2c3d4e5f6a7b8c9d0e1f2a3b",
  "externalReferences": [
    {
      "type": "vcs",
      "url": "https://github.com/example/crypto-primitives.git"
    }
  ],
  "properties": [
    {
      "name": "shpbl:source:commit",
      "value": "7f8a9d3e5b6c4a1b2c3d4e5f6a7b8c9d0e1f2a3b"
    },
    {
      "name": "shpbl:source:tree_digest",
      "value": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    }
  ]
}

In a CycloneDX or SPDX output, this structure removes ambiguity. The purl references a version string for tooling compatibility, but the external reference and property fields bind the entry to a specific, immutable commit in the upstream version control system. For mission-critical dependencies, comparing this against a published root of trust ensures that local code matches the upstream record byte-for-byte.

What is Genuinely Difficult

Commit-level tracking introduces real operational friction that teams must design around:

  • Squashed and Rebased Upstreams: If an upstream maintainer rewrites history, an older commit hash may disappear from the default branch. Your gate must either mirror upstream repositories internally or preserve the imported commit object in a local archive.
  • Sub-directory Vendoring: Projects rarely vendor an entire multi-gigabyte monorepo. When importing a single sub-directory, recording the parent commit hash is necessary, but you must also record the path within the tree where that code lived at that commit.
  • Locally Patched Sources: The moment an internal patch touches vendored code, the local file hash diverges from the upstream commit hash. Your SBOM must distinguish between the upstream base commit and the patch series applied on top of it.

Treating these edge cases as separate metadata fields prevents the SBOM from becoming an unreadable set of conflicting claims.

What to Check on Monday

Inspect your current build pipeline's SBOM output.

Take three random third-party components listed in your generated manifest:

  1. Locate the package identifier in the SBOM.
  2. Attempt to resolve that identifier to an exact upstream Git commit without checking your current lockfile or searching a commit history manually.
  3. If the SBOM only provides a version string like ^2.1.0 or a tag like v2.1, your compliance paper trail is broken.

Update your build configuration to require package URLs to serialize the VCS commit hash parameter (?vcs_url=git+https://...@[commit-hash]). If your dependency tooling cannot resolve the upstream commit automatically, record the commit hash and archive digest at the boundary gate before the source enters your tree.

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.