fix(extensions): handle uppercase npm registry schemes - #5437
Conversation
✅ Local verification — recommend mergeI built and tested this PR locally as a merge reference. Verdict: verified, safe to merge. The fix is correct, minimal, well-scoped, and the two new tests genuinely guard it (proven by a mutation test). Environment: dedicated git worktree at PR head Root cause confirmedURL schemes are case-insensitive, and the WHATWG
So an uppercase Verification results1. PR test suite (fixed code) — all green 2. Mutation test (the decisive proof) — the new tests are non-vacuous Exactly the two new tests fail (each because base routes uppercase HTTPS to the 3. Reviewer Test Plan gates — all pass
Reverse audit
ConclusionCorrect root-cause fix, minimal diff, non-vacuous regression coverage, clean typecheck/lint/build. LGTM — recommend merge. 中文版✅ 本地验证 —— 建议合并我在本地构建并测试了该 PR,作为合并参考。结论:验证通过,可安全合并。 修复正确、改动最小、范围清晰,且两个新增测试确实能守护该修复(已用变异测试证明)。 环境: 在 根因确认URL scheme 大小写不敏感,WHATWG
所以大写的 验证结果1. PR 测试套件(修复版)—— 全绿 2. 变异测试(决定性证据)—— 新测试非空过 恰好是这两个新测试失败(因为 base 把大写 HTTPS 路由到了会抛 3. Reviewer Test Plan 各项 gate —— 全部通过
反向审计
结论正确的根因修复、最小 diff、非空过的回归覆盖、typecheck/lint/build 全清。LGTM —— 建议合并。 |
wenshao
left a comment
There was a problem hiding this comment.
No blocking issues — clean fix, and actually a small security improvement. The old url.startsWith('https://') ? https : http was case-sensitive, so an uppercase HTTPS:// registry/tarball URL fell through to the http client — sending the Bearer auth token over plaintext. The new clientForUrl parses the protocol and routes https: over TLS (and throws on unsupported schemes instead of silently downgrading). The 2 new tests genuinely guard it (they fail on main), and every call site already validates the URL via new URL() upstream, so the new parse adds no new failure mode. 26/26 tests pass locally.
Optional, non-blocking nit: the new clientForUrl was inserted between the /** Fetch JSON from a URL… */ JSDoc and fetchNpmJson, so that comment now documents the wrong function (and fetchNpmJson lost its doc). Trivial to move.
中文
无阻断问题 —— 干净的修复,而且其实是个小的安全改进。旧的 url.startsWith('https://') ? https : http 大小写敏感,所以大写的 HTTPS:// registry/tarball URL 会落到 http 客户端 —— 把 Bearer 鉴权 token 走明文发出去。新的 clientForUrl 解析协议并把 https: 走 TLS(对不支持的 scheme 直接抛错,而不是静默降级到 http)。两个新测试确实守护了该行为(在 main 上会失败),而且每个调用点上游都已用 new URL() 校验过 URL,所以这次新增的解析不引入新的失败路径。本地 26/26 测试通过。
可选、非阻塞的小问题:新的 clientForUrl 被插在了 /** Fetch JSON from a URL… */ 这段 JSDoc 与 fetchNpmJson 之间,导致该注释现在文档化了错误的函数(而 fetchNpmJson 丢了自己的注释)。挪一下即可。
— claude-opus-4-8 via Claude Code /qreview
| /** | ||
| * Fetch JSON from a URL, handling both https and http. | ||
| */ | ||
| function clientForUrl(url: string): typeof https | typeof http { |
There was a problem hiding this comment.
[Suggestion] The JSDoc comment /** Fetch JSON from a URL, handling both https and http. */ at line 183 now sits directly above clientForUrl, but it describes fetchNpmJson. clientForUrl returns a module reference, not JSON.
| function clientForUrl(url: string): typeof https | typeof http { | |
| /** | |
| * Return the http or https client module for the given URL's protocol. | |
| */ | |
| function clientForUrl(url: string): typeof https | typeof http { |
…and restore the original JSDoc above fetchNpmJson:
| function clientForUrl(url: string): typeof https | typeof http { | |
| /** | |
| * Fetch JSON from a URL, handling both https and http. | |
| */ | |
| function fetchNpmJson<T>(url: string, authToken?: string): Promise<T> { |
— qwen3.7-max via Qwen Code /review
| 'npm registry request failed with status 404: https://***REDACTED***@registry.example.com/@scope%2fpkg', | ||
| ); | ||
| }); | ||
|
|
There was a problem hiding this comment.
[Suggestion] The new clientForUrl function has three branches (https:, http:, unsupported-protocol throw), but the two new tests only exercise the https: path via uppercase HTTPS:// URLs. The http: branch (e.g., an HTTP:// registry URL) and the unsupported-protocol error path are untested.
Consider adding a test that uses an HTTP:// registry URL and asserts https.get is NOT called, plus a test that passes a ftp:// URL and asserts the call rejects with "Unsupported npm registry URL protocol". This would lock in the fix for both sides of the case-insensitivity bug.
— qwen3.7-max via Qwen Code /review
|
@qwen-code /triage |
|
Thanks for the PR! Template looks good ✓ On direction: clear bug fix — On approach: the fix is minimal and focused — a small Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 方向:明确的 bug 修复—— 方案:改动精简聚焦——引入 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewIndependent proposal: parse the URL with The The two new tests are well-structured: they mock Typecheck ✅, lint ✅, build ✅, 26/26 unit tests ✅ (24 existing + 2 new). Before/After TestingTest script imports the compiled Before (main branch — bug present)On main, the uppercase HTTPS URL is routed to After (this PR)With the fix, the uppercase HTTPS URL is correctly routed to Bug confirmed and fix verified. ✅ 中文说明代码审查独立方案:用
两个新测试结构良好:mock Typecheck ✅,lint ✅,build ✅,26/26 单测 ✅(24 现有 + 2 新增)。 Before/After 测试测试脚本导入编译后的 main 分支上,大写 HTTPS URL 被路由到 PR 修复后,大写 HTTPS URL 正确路由到 Bug 已确认,修复已验证。✅ — Qwen Code · qwen3.7-max |
|
Clean fix, ships it. The bug is real — Before/after testing is conclusive: on main, uppercase Approving. ✅ 中文说明干净的修复,可以合并。 Bug 确实存在—— Before/after 测试结论明确:main 分支上大写 批准。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
🅷 Hold for consolidation — not a code objection (approval stands). The fix itself is correct and even a small security improvement (uppercase #5437 ( Could we please either:
Either way, let's land the shared util once rather than two copies. Thanks! 中文说明🅷 暂缓合并 —— 不是代码问题,approve 保留。 这个修复本身是对的,还是个小安全改进(大写 #5437( 能否二选一:
无论哪种,让这个共用 util 只进仓库一次,而不是两份。谢谢! |
What this PR does
Makes npm extension registry requests choose the HTTP client from the parsed URL protocol instead of checking for a lowercase
https://prefix. This keeps uppercase HTTPS registry and tarball URLs on the HTTPS client.Why it is needed
URL schemes are case-insensitive, but the npm extension path used a case-sensitive string prefix check. A registry URL like
HTTPS://registry.npmjs.orgcould be misrouted tohttp.get, and the same issue applied when downloading tarballs from uppercase HTTPS tarball URLs.Reviewer Test Plan
How to verify
Run
npx vitest run packages/core/src/extension/npm.test.ts,npm run typecheck --workspace=packages/core,npm run lint --workspace=packages/core,npm run build --workspace=packages/core, andgit diff --check. The new tests assert uppercase HTTPS registry metadata and tarball URLs usehttps.getand never callhttp.get.Evidence (Before & After)
N/A
Tested on
Environment (optional)
Local npm workspace on macOS.
Risk & Scope
Linked Issues
Fixes #5436
AI Assistance Disclosure
I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.
中文说明
这个 PR 做了什么
让 npm extension registry 请求根据解析后的 URL protocol 选择 HTTP client,而不是检查小写
https://前缀。这样 uppercase HTTPS registry 和 tarball URL 都会继续走 HTTPS client。为什么需要
URL scheme 本身是大小写不敏感的,但 npm extension 路径之前用了大小写敏感的字符串前缀判断。像
HTTPS://registry.npmjs.org这样的 registry URL 可能会被错误转到http.get,下载 uppercase HTTPS tarball URL 时也有同样问题。Reviewer Test Plan
如何验证
运行
npx vitest run packages/core/src/extension/npm.test.ts、npm run typecheck --workspace=packages/core、npm run lint --workspace=packages/core、npm run build --workspace=packages/core和git diff --check。新增测试会断言 uppercase HTTPS registry metadata 和 tarball URL 都使用https.get,不会调用http.get。Before & After 证据
N/A
Tested on
macOS 已本地验证;Windows 和 Linux 未本地验证,交给 CI 覆盖。
Environment
macOS 本地 npm workspace。
Risk & Scope
Linked Issues
Fixes #5436
AI Assistance Disclosure
I used Codex to review the changes, sanity-check the implementation against existing patterns, and help spot potential edge cases.