lockfile

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package lockfile reads dependency lock files out of a source checkout.

A lock file is the source-mode analog of an installed-package database, and the analogy holds in the way that matters: both are the build's own record of what it resolved, not an inference drawn from it. package-lock.json names exactly the versions `npm ci` will install, the same way /var/lib/dpkg/status names exactly what is unpacked.

What a lock file cannot give is the thing image mode leans on hardest. There is no import graph here, because resolving a specifier needs an installed dependency tree, and materializing one means running the target's build -- arbitrary code from the thing being audited. So repo mode answers a narrower question than image mode and is built to say so rather than to guess.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DevOnly

func DevOnly(results []Result, name string) bool

DevOnly reports whether the lock files declare this package as reachable only through development dependencies.

Two things have to hold, and both are folded in here rather than left to the caller. Every result that names the package must mark it dev: a package that is dev-only in one lock file and a runtime dependency in another ships in production, so the runtime answer wins. And every such result must partition dev at all: a requirements.txt says nothing about the distinction, and "did not say" must never be read as "said no". A file with DevKnown false therefore forces the answer to false, which is why there is no second return value -- a true here already means the partition was declared.

func FilesFor

func FilesFor(results []Result, name string) []string

FilesFor returns the lock files that name this package, in the order they were read.

Evidence has to name these rather than every file the scan opened. A repo with four requirements files reads them all, but "requirements_test.txt declares certifi" is a claim about that file, and it is false unless the file says so.

Types

type Format

type Format string

Format identifies which reader produced a result.

const (
	FormatNPM  Format = "npm"
	FormatPyPI Format = "pypi"
)

type NPM

type NPM struct{}

NPM reads package-lock.json, in all three of its formats.

func (*NPM) Format

func (*NPM) Format() Format

func (*NPM) Read

func (n *NPM) Read(fsys target.RootFS, dir string) ([]Result, error)

type Package

type Package struct {
	// Name is the package name as OSV keys it: the PEP 503 normalized project
	// name for PyPI, the registry name verbatim for npm.
	Name string `json:"name"`

	// Version is the locked version, or "" when the file pins a range rather
	// than a point. An unpinned entry still proves the package is *present*,
	// which is the question repo mode is best at; it just cannot be asked
	// which advisories apply to it.
	Version string `json:"version,omitempty"`

	// Dev reports that the entry is reachable only through development
	// dependencies, and so is absent from a production install by
	// construction. This is a deterministic fact the lock file states, not a
	// heuristic: `npm ci --omit=dev` will not write it to disk.
	Dev bool `json:"dev,omitempty"`
}

Package is one locked dependency.

func Packages

func Packages(results []Result) []Package

Packages flattens several results, dropping duplicate coordinates.

Two lock files in one directory naming the same package at the same version is ordinary -- a Pipfile.lock beside a requirements.txt -- and reporting it twice would double every finding about it. Two files disagreeing about the *version* is not deduplicated, because that is a real thing to have found.

type PyPI

type PyPI struct{}

PyPI reads the three lock files Python actually ships with: requirements.txt, poetry.lock, and Pipfile.lock.

pyproject.toml is deliberately not among them. It declares constraints rather than resolutions, so it can say a package is *wanted* but not at which version -- and a version is what an advisory range is compared against.

func (*PyPI) Format

func (*PyPI) Format() Format

func (*PyPI) Read

func (p *PyPI) Read(fsys target.RootFS, dir string) ([]Result, error)

type Reader

type Reader interface {
	Format() Format

	// Read parses every lock file of this format directly under dir.
	//
	// A directory holding none of them is not an error and yields nothing. A
	// lock file that exists and will not parse *is* an error, for the reason
	// pkgdb.Read has the same rule: an empty inventory renders as "this repo
	// depends on nothing vulnerable", which is the worst way for this tool to
	// be wrong.
	Read(fsys target.RootFS, dir string) ([]Result, error)
}

Reader parses one family of lock file.

func Readers

func Readers() []Reader

Readers lists every lock file reader.

type Result

type Result struct {
	Format Format `json:"format"`

	// File is the tree-absolute path this was read from, for evidence.
	File string `json:"file"`

	// DevKnown reports whether this file partitions development dependencies
	// from runtime ones at all.
	//
	// It is false for requirements.txt, which carries no such partition. The
	// distinction has to travel with the data: "Dev is false" would otherwise
	// mean both "the file says this ships in production" and "the file does
	// not say", and only the first can support a not_in_execute_path.
	DevKnown bool `json:"dev_known"`

	Packages []Package `json:"packages,omitempty"`
}

Result is one lock file's contents.

func Read

func Read(fsys target.RootFS, dir string, format Format) ([]Result, error)

Read parses the lock files of one format under dir.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL