Skip to content

feat(core): implement direct web login for official npm registry#13

Merged
syi0808 merged 7 commits intomainfrom
feat/npm-direct-web-login
Apr 10, 2026
Merged

feat(core): implement direct web login for official npm registry#13
syi0808 merged 7 commits intomainfrom
feat/npm-direct-web-login

Conversation

@syi0808
Copy link
Copy Markdown
Owner

@syi0808 syi0808 commented Apr 10, 2026

Summary

  • Implement npm web login protocol directly via fetch() instead of parsing npm CLI output, fixing URL redaction issues in npm 11+
  • Only applies to official npm registry (registry.npmjs.org); private registries keep existing npm login fallback
  • Protocol: POST /-/v1/login → receive loginUrl/doneUrl → open browser → poll doneUrl → save token

Changes

  • Add NPM_OFFICIAL_REGISTRY constant and isOfficialNpmRegistry() helper
  • Implement runDirectWebLogin(task) method (direct web login protocol)
  • Add official/private registry dispatch in runInteractiveLogin(task)
  • No changes to existing code (validateNpmLoginUrl, extractNpmLoginUrl, readInteractiveStream, checkAvailability, npmLoginPromise dedup)

Test plan

  • Happy path: POST → 202 polling → 200 token → npm config set → isLoggedIn
  • Error cases: missing loginUrl/doneUrl, invalid URLs, 200 without token, unexpected status, POST failure, network errors, empty token, ftp:// URLs
  • Browser open failure: openUrl rejection still allows login to succeed
  • Token save failure: specific error message on npm config set failure
  • Private registry fallback: spawnInteractive path preserved
  • Concurrent dedup: npmLoginPromise shared promise behavior preserved
  • Security: doneUrl and token never exposed in task.output
  • Regression: post-login N2/N3 checks proceed correctly, "Waiting for npm login..." displayed
  • Full suite: 2124 tests passing, coverage thresholds maintained

syi0808 added 6 commits April 10, 2026 20:33
Add 17 new test scenarios covering:
- Multiple 202 polling cycles before success
- Retry-After header value respected
- POST and polling network errors (fetch throws)
- Empty JSON body, empty string token, ftp:// protocol URLs
- Still not logged in after successful token save
- Error message wrapping format verification
- Already logged in skips login entirely
- Shared promise cleared after failure for retry
- Second package sees "Waiting for npm login..." output
- LoginUrl with query parameters
- doneUrl and token never exposed in task.output (security)
- Post-login flow proceeds to N2/N3 checks correctly
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

2 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/core/src/registry/npm.ts">

<violation number="1" location="packages/core/src/registry/npm.ts:494">
P1: The `.includes("registry.npmjs.org")` check is too loose and matches domains like `my-registry.npmjs.org` or `registry.npmjs.org.evil.com`. Use strict equality against the normalized canonical form to avoid routing private-registry users through the official npm login flow.</violation>

<violation number="2" location="packages/core/src/registry/npm.ts:588">
P2: `pollRes.json()` is called unconditionally before checking the status code. If the server returns a non-JSON body for an unexpected status (e.g., 500 with an HTML error page), a `SyntaxError` propagates instead of the descriptive `NpmError`. Parse the body only after confirming a 200 or 202 status.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.

Comment thread packages/core/src/registry/npm.ts Outdated
Comment thread packages/core/src/registry/npm.ts Outdated
- Replace .includes() with === for isOfficialNpmRegistry to prevent
  subdomain matching (e.g. my-registry.npmjs.org)
- Move .json() call after status check in web login polling to avoid
  SyntaxError on non-JSON error responses
@github-actions
Copy link
Copy Markdown

Coverage Report for @pubm/core (packages/core)

Status Category Percentage Covered / Total
🔵 Lines 96.35% (🎯 95%) 4656 / 4832
🔵 Statements 95.92% (🎯 95%) 4914 / 5123
🔵 Functions 95.76% (🎯 95%) 882 / 921
🔵 Branches 90.47% (🎯 90%) 2535 / 2802
Generated in workflow #470 for commit a2b2fcc by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown

Coverage Report for pubm (packages/pubm)

Status Category Percentage Covered / Total
🔵 Lines 99.35% (🎯 95%) 153 / 154
🔵 Statements 98.76% (🎯 95%) 160 / 162
🔵 Functions 95.83% (🎯 95%) 23 / 24
🔵 Branches 91.74% (🎯 90%) 100 / 109
Generated in workflow #470 for commit a2b2fcc by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown

Coverage Report for @pubm/plugin-external-version-sync (packages/plugins/plugin-external-version-sync)

Status Category Percentage Covered / Total
🔵 Lines 98.3% (🎯 95%) 58 / 59
🔵 Statements 98.41% (🎯 95%) 62 / 63
🔵 Functions 100% (🎯 95%) 9 / 9
🔵 Branches 94.11% (🎯 90%) 32 / 34
Generated in workflow #470 for commit a2b2fcc by the Vitest Coverage Report Action

@github-actions
Copy link
Copy Markdown

Coverage Report for @pubm/plugin-brew (packages/plugins/plugin-brew)

Status Category Percentage Covered / Total
🔵 Lines 0% (🎯 90%) 0 / 0
🔵 Statements 0% (🎯 90%) 0 / 0
🔵 Functions 0% (🎯 90%) 0 / 0
🔵 Branches 0% (🎯 90%) 0 / 0
Generated in workflow #470 for commit a2b2fcc by the Vitest Coverage Report Action

@syi0808 syi0808 merged commit 5a3a31d into main Apr 10, 2026
6 checks passed
@syi0808 syi0808 deleted the feat/npm-direct-web-login branch April 10, 2026 12:29
syi0808 added a commit that referenced this pull request Apr 10, 2026
feat(core): implement direct web login for official npm registry
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