Documentation
¶
Overview ¶
Package lock parses dependency lockfiles into a common representation.
Index ¶
Constants ¶
const SniffBudget = 20
SniffBudget is the default cap PathFilter puts on content-sniff candidates per remote fetch.
Variables ¶
This section is empty.
Functions ¶
func HostOf ¶ added in v0.4.6
HostOf extracts the lowercase host from a URL string; "" when it can't.
func ImageHost ¶ added in v0.5.12
ImageHost returns the registry host an image name resolves from and the repository path on that registry, following the daemon's rules: no host part means Docker Hub, and single-component Hub names live under library/.
func KnownBasenames ¶
func KnownBasenames() []string
KnownBasenames lists every lockfile filename lockvet understands.
func PathFilter ¶ added in v0.5.19
PathFilter returns a fresh predicate for remote diff fetches: every known lockfile path always passes, and up to sniffBudget other YAML files (SniffableYAML) pass for content sniffing — the cap keeps a big refactor PR from ballooning the number of file downloads. The closure is stateful; make one per fetch and do not share across goroutines.
func Sanitize ¶
Sanitize makes untrusted strings (lockfile- or registry-derived) safe to render: it enforces valid UTF-8 and strips control characters (so hostile input cannot smuggle ANSI escape sequences into terminal output).
func SniffableYAML ¶ added in v0.5.19
SniffableYAML reports whether a changed file that no basename or path convention claims is still worth a content sniff as a Kubernetes manifest. GitOps repos keep workload manifests under arbitrary layouts (default/nzbget/nzbget.yaml); the strict top-level apiVersion: + kind: gate inside the parser makes over-matching free, so in diff modes — where the changed-file list is small — every other YAML file qualifies. Helm chart templates stay excluded: their image references are {{ interpolated }}. Directory walks (audit) keep convention-based discovery instead: sniffing every YAML in a large tree would read far more than it finds.
Types ¶
type Ecosystem ¶
type Ecosystem string
Ecosystem is an OSV.dev ecosystem identifier.
const ( NPM Ecosystem = "npm" CratesIO Ecosystem = "crates.io" PyPI Ecosystem = "PyPI" Go Ecosystem = "Go" Packagist Ecosystem = "Packagist" RubyGems Ecosystem = "RubyGems" Hex Ecosystem = "Hex" Pub Ecosystem = "Pub" Maven Ecosystem = "Maven" NuGet Ecosystem = "NuGet" SwiftURL Ecosystem = "SwiftURL" CocoaPods Ecosystem = "CocoaPods" // CRAN and Bioconductor cover R packages from renv.lock. A single // renv.lock mixes both; Bioconductor packages are marked per-package // via File.PkgEco. CRAN Ecosystem = "CRAN" Bioconductor Ecosystem = "Bioconductor" // Nix has no OSV.dev ecosystem and no semver: flake inputs pin git // revisions. lockvet still explains what moved and by how much time. Nix Ecosystem = "Nix" // Conda covers pixi.lock and conda-lock.yml. Conda channels have no // OSV.dev ecosystem or deps.dev coverage, so conda packages get diff, // graph and version-jump treatment only; pip/pypi packages inside the // same lockfile are marked PyPI per-package (File.PkgEco) and get // full vulnerability, age and deprecation data. Conda Ecosystem = "conda" // Terraform providers (.terraform.lock.hcl, Terraform & OpenTofu) // and Helm charts (Chart.lock) have no OSV.dev ecosystem or deps.dev // coverage: changes are diffed, classified and explained without // vulnerability or age claims. Terraform Ecosystem = "Terraform" Helm Ecosystem = "Helm" // Julia covers Manifest.toml (General registry packages and stdlibs; // OSV ecosystem "Julia"). Hackage covers stack.yaml.lock and // cabal.project.freeze/cabal.config (OSV ecosystem "Hackage"). Julia Ecosystem = "Julia" Hackage Ecosystem = "Hackage" // GitHubActions covers pkg:github purls in SBOMs (OSV ecosystem // "GitHub Actions"). GitHubActions Ecosystem = "GitHub Actions" // Conan covers conan.lock (C/C++). "ConanCenter" is a valid OSV // ecosystem (currently near-empty — advisories will surface here // automatically if it fills in); deps.dev has no Conan system, so // internal/conanreg is the metadata layer for these lockfiles. Conan Ecosystem = "ConanCenter" // Bazel covers MODULE.bazel.lock (bzlmod). There is no OSV.dev // ecosystem and no deps.dev system for Bazel modules; internal/bzlreg // reads the Bazel Central Registry directly (yanked versions with // reasons, version lists, source repositories). Bazel Ecosystem = "Bazel" // Zig covers build.zig.zon: Zig has no lockfile beyond it, no central // registry, and no OSV.dev ecosystem. Dependencies pin source archive // URLs plus content hashes, so lockvet explains bumps and checks the // pins themselves (integrity, resolution source) without registry or // vulnerability claims. Zig Ecosystem = "Zig" // Docker covers container base-image pins: Dockerfile / Containerfile // FROM lines and Compose file image: values. There is no OSV.dev // ecosystem for whole images; internal/ocireg verifies tags and // digest pins against the image registries themselves (Docker Hub // ages included). Docker Ecosystem = "Docker" // PreCommit covers .pre-commit-config.yaml `rev:` pins: each entry // names a hook repository (on any git forge — names keep their host) // at an exact tag or commit that pre-commit clones and runs. No // OSV.dev ecosystem; internal/actreg verifies revs against the hook // repositories' real tags. PreCommit Ecosystem = "pre-commit" // Ansible covers Galaxy requirements.yml files: collections // (namespace.name) and classic roles (owner.name), which OSV.dev and // deps.dev both lack entirely. internal/ansreg reads galaxy.ansible.com // itself (the v3 collection index and v1 role index): release ages, // collection deprecation, registry-verified unlisted versions, source // repositories. Roles are marked per-package via File.PkgEco. Ansible Ecosystem = "Ansible Galaxy" AnsibleRole Ecosystem = "Ansible Galaxy role" // SBOMEco is the file-level ecosystem of an SBOM: a single CycloneDX // or SPDX document mixes ecosystems, so each package carries its own // (File.PkgEco) and this value is only a label / fallback. SBOMEco Ecosystem = "SBOM" )
func (Ecosystem) HasOSV ¶
HasOSV reports whether the ecosystem can be queried on OSV.dev. This is a whitelist: SBOMs introduce open-ended ecosystem strings (Linux distro packages, unknown purl types) and OSV rejects a whole batch when one query names an invalid ecosystem.
func (Ecosystem) HasSemver ¶
HasSemver reports whether version-jump levels (major/minor/patch) are meaningful for the ecosystem. Nix pins git revisions; Debian/Ubuntu/RPM version strings carry epochs and distro revisions where semver labels would be noise.
func (Ecosystem) PublicRegistryHost ¶ added in v0.4.6
PublicRegistryHost reports whether the host is the ecosystem's canonical public registry (or its official CDN). Used to tell "resolution moved to the public registry" — the dependency-confusion direction — apart from ordinary mirror hops.
type File ¶
type File struct {
Path string
Kind string // e.g. "package-lock.json"
Ecosystem Ecosystem
Packages map[string][]string
// Dependency-graph info, filled in only when the lockfile format
// records it. Deps maps package name -> names it depends on.
// Roots are the project's *direct* dependencies when the lockfile
// itself says so (npm root entry, pnpm importers, Gemfile.lock
// DEPENDENCIES, go.mod without "// indirect", ...).
// RootsKnown distinguishes "no roots recorded" from "empty roots".
Deps map[string][]string
Roots []string
RootsKnown bool
// PkgEco overrides the file-level Ecosystem per package. Only SBOMs
// use it: one CycloneDX/SPDX document mixes npm, PyPI, distro
// packages and more. nil for ordinary lockfiles.
PkgEco map[string]Ecosystem
// NonRegistry marks packages the lockfile itself says do NOT come
// from the format's public registry: workspace members, path and
// git dependencies, alternate indexes. Registry-metadata checks
// (like the unlisted-version flag) skip them.
NonRegistry map[string]bool
// PkgChannel records the registry "channel" a package resolves
// from, when the lockfile names one: the conda channel
// (conda.anaconda.org/<channel>/… artifact URLs) for the conda
// formats, or the chart repository URL for Helm charts. The
// condareg/helmreg layers key their lookups on it. nil elsewhere.
PkgChannel map[string]string
// PkgRepo records the source repository URL the lockfile itself
// resolves a package from, when the format pins repositories rather
// than registry releases (Nix flake inputs). diffx copies it onto
// Change.SourceRepo so compare links work without any registry
// lookup. nil elsewhere.
PkgRepo map[string]string
// PkgYanked records versions the lockfile ITSELF admits are yanked
// from their registry, keyed "name@version" → reason. Only Bazel's
// MODULE.bazel.lock fills it (selectedYankedVersions, written when
// the build passes --allow_yanked_versions): a fully-offline
// deprecation signal. nil elsewhere.
PkgYanked map[string]string
// Pins records what the lockfile itself pins for a (package, version)
// beyond the version string: the content hash it expects and the
// registry host it resolves from. Filled only by formats that write
// integrity hashes or resolution URLs (npm, pnpm, yarn, Cargo, uv,
// poetry, Pipfile, requirements --hash, Gemfile.lock remotes).
// name → version → meta.
Pins map[string]map[string]PinMeta
}
File is a parsed lockfile: package name -> set of pinned versions. A lockfile may legitimately contain multiple versions of one package (npm nesting, cargo duplicate majors), hence the set.
type Parser ¶
type Parser struct {
Kind string
Ecosystem Ecosystem
Parse func(p string, data []byte) (*File, error)
}
Parser turns lockfile bytes into a File.
func ByBasename ¶
ByBasename returns the parser responsible for a given file path, or nil. Both forward and backward slashes separate: forge and git paths always use "/", but file mode (`lockvet diff`, MCP vet_files) gets OS paths, and no supported lockfile basename contains a backslash.
func FallbackParser ¶ added in v0.5.0
FallbackParser guesses a parser for a file whose name is not a known lockfile basename (explicit two-file diffs, playground drops): YAML files are tried as CI workflows — strict: at least one `uses:` pin — then as Kubernetes manifests (top-level apiVersion: and kind: required), so a mis-named real lockfile still gets a helpful error — and everything else goes to SBOM content sniffing.
func SBOMParser ¶ added in v0.1.16
func SBOMParser() *Parser
SBOMParser returns the format-sniffing SBOM parser. `lockvet diff` uses it for files whose names aren't recognizable lockfile names.
func SniffParser ¶ added in v0.5.19
func SniffParser() *Parser
SniffParser parses files admitted by SniffableYAML: Kubernetes YAML gets the manifest treatment, anything else parses to an empty file.
type PinMeta ¶ added in v0.4.6
type PinMeta struct {
// Integrity is a space-joined set of content hashes in whatever
// notation the format uses ("sha512-…", "sha256:…", bare hex,
// yarn-berry "10c0/…"). A set because Python lockfiles record one
// hash per artifact (sdist + wheels) for the same version.
Integrity string
// Host is the registry/CDN host the package resolves from, e.g.
// "registry.npmjs.org". Empty when the format doesn't record it.
Host string
}
PinMeta is the integrity/resolution metadata a lockfile records for one pinned (package, version).