Skip to content

feat(deps): verify requirements PATH can't see (package query + check) - #9

Merged
stevenzg merged 2 commits into
mainfrom
feat/verify-non-path-requirements
Jul 18, 2026
Merged

feat(deps): verify requirements PATH can't see (package query + check)#9
stevenzg merged 2 commits into
mainfrom
feat/verify-non-path-requirements

Conversation

@stevenzg

Copy link
Copy Markdown
Owner

Problem

tarjan verifies a requires tool by looking for its name as an executable on PATH (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 --install would happily apt-get install libnspr4, but the follow-up probe (LookPath("libnspr4")) always failed — a library is not on PATH — 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:

  1. package: now doubles as verification. When a tool isn't on PATH, 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.

  2. 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 Starlark tool() builtin gains a check argument.

Detection order: explicit check: → executable on PATH (the only path that yields a version for MinVersion) → installed package:.

Notes

  • No behavior change for existing configs: PATH is still tried first, and package-query only runs as a fallback when a tool is off PATH — where the old behavior was an unconditional "missing" anyway.
  • Windows managers (winget/choco/scoop) declare no presence query; the library-verification case doesn't arise there (Windows binaries ship self-contained).
  • MinVersion is 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 — the check: path (present / absent / optional).

Full suite + go vet pass.

🤖 Generated with Claude Code

stevenzg and others added 2 commits July 18, 2026 17:40
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>
@stevenzg
stevenzg merged commit c4d7d83 into main Jul 18, 2026
5 checks passed
@stevenzg
stevenzg deleted the feat/verify-non-path-requirements branch July 18, 2026 06:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant