feat(deps): verify requirements PATH can't see (package query + check) - #9
Merged
Conversation
A tool is normally detected by looking for its name as an executable on PATH. That cannot see a dependency which is not a program — a shared library, a font, a kernel module — so such a requirement could not be expressed at all. Add a `check:` field: when set, its shell command is run (via the OS shell, so pipes work) and a zero exit means the dependency is present, bypassing PATH lookup. MinVersion does not apply (there is no version string); pair `check:` with a package:/install: provider so `--install` can still install it. The Starlark `tool()` builtin gains a `check` argument. Motivating case: Electron's Chromium needs system libraries (libnspr4, libnss3, libasound2) that are not executables — `check: "ldconfig -p | grep -q ..."` lets an environment declare and auto-install them on a minimal Linux/WSL box. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
tarjan could install a system package (`package:` + `--install`) but had no way to verify one: presence was probed only with `exec.LookPath`, which finds an executable. A shared library is not an executable, so a package-only requirement was installed and then immediately reported unsatisfied — an install-but-never-verify asymmetry. When a tool is not found on PATH and declares a `package:`, ask the host package manager whether that package is installed (`dpkg -s`, `rpm -q`, `pacman -Q`, `apk info -e`, `brew list`) before deciding it is missing. The query is the manager's own tool (dpkg, not apt-get), needs no root, and is conservative — no query, no query tool on PATH, or a non-zero exit all read as "not present" — so a false positive never masks a genuinely missing dependency. Detection order is now: explicit `check:` → executable on PATH (the only path yielding a version for MinVersion) → installed `package:`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
tarjan verifies a
requirestool by looking for its name as an executable onPATH(exec.LookPath). That's correct for CLI tools (git, node, dotnet, psql) but can't express a prerequisite that isn't a program — a shared library, a font, a kernel module.Worse, it created an install-but-never-verify asymmetry: you could declare
package: {apt: libnspr4}and--installwould happilyapt-get install libnspr4, but the follow-up probe (LookPath("libnspr4")) always failed — a library is not onPATH— so tarjan reported it unsatisfied forever.Concretely, this is what blocks running an Electron app (edsger-studio) on a minimal Linux/WSL/CI box: Chromium needs
libnspr4/libnss3/libasound2, and tarjan had no way to declare or verify them.Change
Two ways to verify a requirement PATH can't see, most explicit first:
package:now doubles as verification. When a tool isn't onPATH, ask the host package manager whether the declared package is installed —dpkg -s,rpm -q,pacman -Q,apk info -e,brew list. This reuses the package identity already in the config, is portable across distros via the per-manager map, and closes the asymmetry directly. It's conservative: no query, no query tool on PATH, or a non-zero exit all read as "not present", so a false positive never masks a genuinely missing dependency.check:escape hatch. A shell command whose zero exit means "present", for anything the package managers can't express (a font, a kernel module, an OS-gated probe). The Starlarktool()builtin gains acheckargument.Detection order: explicit
check:→ executable onPATH(the only path that yields a version forMinVersion) → installedpackage:.Notes
MinVersionis not applied to a package-/check-verified tool (there's no version string to parse).Tests
TestPkgManagerQueryArgv— each manager's query is the right tool + argv, package name never shell-spliced; Windows has no query.TestPackageInstalledQueriesManager— reads dpkg's exit status via fakes on PATH; conservative when the query tool is absent.TestCheckSatisfiedByInstalledPackage— end-to-end: a non-executable requirement is satisfied by an installed package, unmet otherwise.TestCheckVerifiesWithoutPath— thecheck:path (present / absent / optional).Full suite +
go vetpass.🤖 Generated with Claude Code