Skip to content

fix(npm): normalize bin names with path separators#35555

Merged
bartlomieju merged 4 commits into
denoland:mainfrom
nathanwhitbot:orcha/impl-b0328041
Jun 29, 2026
Merged

fix(npm): normalize bin names with path separators#35555
bartlomieju merged 4 commits into
denoland:mainfrom
nathanwhitbot:orcha/impl-b0328041

Conversation

@nathanwhitbot

Copy link
Copy Markdown
Contributor

Closes #35553.

Summary

  • Normalize npm bin map entry names by using the last non-empty path segment, matching npm/pnpm behavior for names like @eslint/config-inspector.
  • Apply the normalized name before .bin symlink and Windows shim setup so separators are not interpreted as directories.
  • Preserve existing default package bin name behavior.

Validation

  • cargo fmt -p deno_npm_installer
  • cargo test -p deno_npm_installer bin_entries

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed a follow-up that replaces the new test's direct Path::exists() calls with sys.fs_exists(...), fixing the clippy disallowed_methods lint while keeping the regression assertions unchanged.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed a CI setup fix for the failing test unit release linux-x86_64 job. The job was failing before tests because the runner's preinstalled Azure CLI apt source returned 403 during apt-get update; the workflow now disables that unrelated source before installing LLVM packages.

@bartlomieju

Copy link
Copy Markdown
Member

Review

The core fix looks correct and well-tested. normalize_bin_name() is applied consistently at all three relevant points — collision detection in add(), within-run dedup in for_each_entry(), and the actual symlink/Windows-shim setup in set_up_bin_entry() — so the normalized name flows through everywhere it needs to (including warn_missing_entrypoint). The repro case (@eslint/config-inspectorconfig-inspector) resolves to the same name pnpm produces, and the String bin branch stays consistent since it already basenames via default_bin_name().

Test coverage is strong: the unix test asserts both that .bin/config-inspector is created and that no .bin/@eslint subdir leaks, which directly pins the bug.

A few notes:

  • Scope: please split out the CI change. This PR also bundles an unrelated CI workflow change (ci.ts + the regenerated blocks in ci.generated.yml disabling an azure-cli apt source that returns 403). That has nothing to do with npm bin names and should be its own PR to keep history focused.

  • Minor — edge cases. normalize_bin_name returns "" for inputs like "" / "/", and passes bare ".."/"." through unchanged (embedded separators are stripped, so "../foo""foo", but ".." alone survives). Not a regression — these were already mishandled and stripping separators actually reduces the path-escape surface — but an early guard or a comment noting these are out of scope would make intent explicit.

  • Nit. The intermediate binding in normalize_bin_name can be dropped (rename the trimmed binding and unwrap_or(trimmed)), purely cosmetic.

Net positive on security too: taking the basename closes the previous write-outside-.bin path. Approve on the substance — just please pull the CI change into a separate PR.

@nathanwhitbot

Copy link
Copy Markdown
Contributor Author

Pushed 036363b9208c to address this: the unrelated CI workflow workaround is removed from this PR, and normalize_bin_name() now uses the trimmed binding directly with a short comment clarifying that empty/special-name validation is outside this basename normalization.

@bartlomieju
bartlomieju merged commit 0532e63 into denoland:main Jun 29, 2026
136 checks passed
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.

deno install fails on an npm package whose bin name contains "/" (e.g. @eslint/config-inspector)

3 participants