Skip to content

pm view, pm diff: report an unknown dist-tag instead of resolving it to latest - #41992

Closed
robobun wants to merge 1 commit into
mainfrom
robobun/3d7283a0/pm-view-unknown-dist-tag
Closed

robobun wants to merge 1 commit into
mainfrom
robobun/3d7283a0/pm-view-unknown-dist-tag

Conversation

@robobun

@robobun robobun commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • With a dist-tag the registry does not have, bun info pkg@<tag> and bun pm diff pkg@<tag> <v> print the data for latest and exit 0: bun info is-number@nonexistenttag version prints 7.0.0. npm exits 1 with E404 No match found for version.
  • Cause: both commands try the spec as a dist-tag, then as a semver range (pm_view_command.rs:200, pm_diff_command.rs:765). Semver::query::parse skips words it cannot read, so the tag parses to an empty Group. An empty Group satisfies every version, and find_best_version returns latest.

Fix

  • Add PackageManifest::find_by_spec: the dist-tag if there is one, else the range, but only when the parser found a comparator. Both commands call it and take their existing not-found exit, plain and --json.
  • The "Recent versions" hint on that exit sliced the tail of PackageManifest::versions, which ends with the dist-tag targets, so it repeated versions. It now lists the newest five releases (prereleases if there is no release).
  • Verified: test/cli/install/bun-info.test.ts (new block, 5 of 6 fail on 1.4.3) and bun-pm-diff.test.ts (new case, fails on 1.4.3). Both files pass.
  • Self-reviewed: 3 concerns, 1 addressed (the github:/file: test no longer pins the error wording), 2 answered under Notes.

Background

  • A packument's dist-tags maps names like latest or next to versions. npm's view swaps a known tag for its version, then filters with semver.satisfies, false for an invalid range.
  • The range parser is lenient on purpose: 1.0.0 || boop ignores boop. Group::is_empty() reports a parse that found no comparator.
  • PackageManifest::versions holds releases, then prereleases, then the dist-tag targets.
Notes
  • A typo'd tag (bun info react@nxt) was the motivating case: it showed latest with no hint that the tag does not exist.
  • Group::is_empty() is the same check add_catalog.rs and audit_fix.rs use to reject an unparseable range.
  • bun install is not affected: it classifies a spec with Tag::infer before it parses a range, and find_best_version itself is unchanged. find_best_version had two callers outside npm.rs, the two fixed here.
  • Behavior change on one edge: bun info pkg against a packument whose latest tag is missing, or points at a version that is not in versions, now reports No version of "pkg" satisfying "latest" found with the recent versions. Before, it printed the highest release through the same accidental path. bun install pkg@latest already fails in that case (DistTagNotFound). install: fall back to highest version when dist-tags.latest does not resolve #36671 proposes a fallback for install and leaves pm view out on purpose. If that fallback lands and a maintainer wants pm view to follow, find_by_spec is the one place to add it.
  • Specs such as github:user/repo, file:./x and npm:other@1 also went down the latest path. They now exit 1 through the same not-found message. pm view never supported them, and the test only asserts the exit code and an error: line, so a later dedicated "unsupported spec" message does not break it.
  • Review concern, not changed: the is-number@999.0.0 snapshot in the pre-existing real-registry block now reads 3.0.0 .. 7.0.0, ... and 10 more instead of 7.0.0 twice and 11 more. That test already depended on registry.npmjs.org data (as do its neighbours, e.g. versions: 15). is-number last published in 2018.
  • Review concern, not changed: pm view: match the requested range against the buffer it was parsed from #38671 rewrites the same lines in pm_view_command.rs for a different bug (range buffer). Whichever lands second needs a small rebase. With this PR the range is parsed and matched inside find_by_spec against spec, which is also what pm view: match the requested range against the buffer it was parsed from #38671 wants.
  • The other npm-parity gaps in pm view (several property arguments, array-pluck paths, the two --json error shapes, the package.json requirement in bun info / pm view requires a package.json #20673 / install: allow bun info and pm view without a package.json #38151) are separate and not touched here.
  • redacted-config-logs.test.ts (which runs pm view) also passes.
  • Repro on 1.4.3, in any directory with a package.json:
    $ bun info is-number@nonexistenttag version; echo $?
    7.0.0
    0
    $ bun pm diff is-number@nonexistenttag is-number@7.0.0
    is-number@7.0.0 → is-number@7.0.0
    No differences (4 files)
    

no test proof · iteration 0 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/cli/install/bun-pm-diff.test.ts

…to latest

`bun info pkg@<spec>` and `bun pm diff pkg@<spec>` looked the spec up as a
dist-tag and then, when that missed, as a semver range. The range parser
skips words it cannot read, so an unknown dist-tag parsed to an empty group,
and an empty group satisfies every version. Both commands printed the data
for `latest` and exited 0. npm exits 1 with E404.

Add PackageManifest::find_by_spec, which does the dist-tag lookup and only
treats the spec as a range when the parser found a comparator in it, and
use it in both commands so they take their existing not-found path.

The "Recent versions" hint on that path listed the tail of the manifest's
raw versions buffer, which ends with the dist-tag targets, so it repeated
versions. List the newest release versions instead (prereleases when the
package has no release).
@github-actions github-actions Bot added the claude label Sep 8, 2026
@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

On-demand reviews are free for the next 12 days. After that, they cost $0.25 per reviewed file.

Or wait 19 seconds for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 33022243-82ae-421d-8ebf-f557edaa2a92

📥 Commits

Reviewing files that changed from the base of the PR and between d745f03 and 21a08b8.

📒 Files selected for processing (5)
  • src/install/npm.rs
  • src/runtime/cli/pm_diff_command.rs
  • src/runtime/cli/pm_view_command.rs
  • test/cli/install/bun-info.test.ts
  • test/cli/install/bun-pm-diff.test.ts

Comment @coderabbitai help to get the list of available commands.

@robobun

robobun commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator Author

Status: ready for review.

Reproduced on bun 1.4.3 against the public registry, in a directory with a package.json:

$ bun info is-number@nonexistenttag version; echo $?
7.0.0
0
$ bun pm diff is-number@nonexistenttag is-number@7.0.0
is-number@7.0.0 → is-number@7.0.0
No differences (4 files)

npm exits 1 with E404 No match found for version nonexistenttag for the same spec.

The new tests use a local Bun.serve registry. On 1.4.3, 5 of the 6 new cases in test/cli/install/bun-info.test.ts and the new case in test/cli/install/bun-pm-diff.test.ts fail. With this branch both files pass in full (bun bd test test/cli/install/bun-info.test.ts, bun bd test test/cli/install/bun-pm-diff.test.ts).

CI (build 112941, finished): 180 of 181 jobs passed. The one red job, debian 13 x64-asan, fails on test/js/node/test/parallel/test-crypto-dh-leak.js, which fails on main too and does not touch this diff. The other annotations passed on retry.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — focused bugfix with the shared logic extracted and both call sites covered.

What was reviewed:

  • find_by_spec in npm.rs: dist-tag → range fallback with the is_empty() guard; error type is AllocError (OOM only), propagated via ? at both callers as before in pm view.
  • pm_diff_command.rs previously swallowed the parse error with if let Ok(...); now ?-propagates it — checked that Semver::query::parse only fails on allocation, so no user-facing behavior change there.
  • "Recent versions" hint now slices release_versions() (fallback prerelease_versions()) and the "... and N more" count uses start_index from the same slice — no duplicate/off-by-one.
  • Tests: local Bun.serve({ port: 0 }) registry, describe.concurrent, pipes drained via Promise.all, stdout/stderr asserted before exit code; the updated is-number@ 999.0.0 snapshot lives in the file's pre-existing real-registry block (noted in the PR).
Extended reasoning...

Overview

This PR fixes bun info / bun pm view and bun pm diff so that a name@ spec where spec is neither a known dist-tag nor a parseable semver range is reported as an error rather than silently resolving to latest. The root cause was that Semver::query::parse on an arbitrary word returns an empty Group, which find_best_version treats as satisfied by every version. The fix adds PackageManifest::find_by_spec in src/install/npm.rs that centralizes the dist-tag → range fallback and returns None when the parsed range is empty. Both pm_view_command.rs and pm_diff_command.rs now call it, replacing ~10 lines of duplicated labeled-block logic each. A secondary fix corrects the "Recent versions:" hint to read from release_versions() (falling back to a new prerelease_versions() accessor) instead of the raw versions slice that included dist-tag-target duplicates.

Security risks

None. This is CLI presentation and version-resolution logic for pm view/pm diff; no auth, crypto, filesystem writes, or network trust decisions are touched. The only input is a user-typed spec string, and the change makes handling stricter (rejecting more inputs), not looser.

Level of scrutiny

Low-to-moderate. The Rust change is small (~30 net lines), extracts a helper following the exact pattern already present at both call sites plus one is_empty() guard that the PR notes is the same check add_catalog.rs and audit_fix.rs already use for the same purpose. The ?-propagated error from Semver::query::parse is AllocError — the pm view path already propagated it, and pm diff previously swallowed it with if let Ok, so the only behavior change there is on OOM. The "Recent versions" rewrite is a straightforward slice of a sorted list with saturating_sub; the ... and N more count now correctly uses start_index from the same slice. No CODEOWNERS entries cover the changed paths.

Other factors

Test coverage is thorough and follows the repo's test conventions closely: a describe.concurrent block backed by a local Bun.serve({ port: 0 }) packument registry, bunExe()/bunEnv, await using proc, Promise.all to drain stdout/stderr/exited, content asserted before exit code, test.each for the info/pm view alias matrix, and inline snapshots for error output. The positive-path test ("known dist-tags and ranges still resolve") guards against over-rejection. The bun-pm-diff.test.ts addition slots into an existing error-case block. The one pre-existing real-registry snapshot update (is-number@ 999.0.0) is acknowledged in the PR notes and sits alongside neighboring tests that already depend on the same registry data. The bug hunt exited on dry_streak with no findings and no ruled-out candidates, and there are no prior reviews or open threads on the PR.

@robobun

robobun commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 8:50 AM PT - Sep 8th, 2026

❌ @robobun, your commit 21a08b8 has 1 failures in Build #112941 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 41992

That installs a local version of the PR into your bun-41992 executable, so you can run:

bun-41992 --bun

@robobun

robobun commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

Closing in favor of #42063. It fixes the same dist-tag fallback in pm view and pm diff with the same PackageManifest::find_by_spec approach. It also gives a tag-shaped miss the bun add message with the list of existing tags, and it covers wrong-case and dangling tags. Two pieces of this PR are folded into #42063 in 01c1174: pm diff propagates errors other than not-found, and the spec test gains a file: row.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant