Every package manager has its own lockfile format. Gemfile.lock, package-lock.json, yarn.lock, Cargo.lock, poetry.lock, composer.lock, go.sum. They all record roughly the same information: which packages were installed, at what versions, with what checksums, from where.
Lockfiles are SBOMs.
Meanwhile, the security world has been pushing CycloneDX and SPDX as standardized formats for describing software components. Lockfiles do the same job, just in bespoke formats. Adoption in open source projects remains low, but that’s changing: the EU’s Cyber Resilience Act will push vendors toward providing SBOMs, and that pressure will flow upstream. The typical workflow involves generating an SBOM from a lockfile, which means running a tool like Syft or Trivy to convert one format to another. This conversion is sometimes lossy.
What if we cut out the middle step? What if package managers wrote SBOMs directly as their lockfile format? The short answer is: yes, mostly, with some sharp edges. I wanted to map out exactly where the gaps are.
What lockfiles record
Looking across the major package managers, lockfiles generally contain:
Package identity: Name, version, and where it came from. npm records a resolved URL. Bundler records the registry and gem source. Cargo uses a source field. Go uses module paths.
Integrity: Some form of checksum. npm uses SHA-512 integrity hashes. Cargo stores checksums. Go puts SHA-256 hashes in go.sum. Bundler historically didn’t include checksums in Gemfile.lock, though newer versions do.
Dependencies: The relationship between packages. Most lockfiles record which packages depend on which, either inline (Bundler lists dependencies under each gem) or as a separate structure (npm’s packages object, Cargo’s dependencies array).
Scope: Whether something is a dev dependency or a production one. npm marks this with dev/optional flags. Bundler separates groups in the Gemfile but flattens them in the lockfile. Poetry distinguishes packages from packages-dev.
... continue reading