Skip to content

CUS-221: Explain port conflicts when two logins run at once - #477

Draft
lurkshark wants to merge 1 commit into
mainfrom
joelweisman/cus-221-p0-cli-fails-with-eaddrinuse-on-port
Draft

lurkshark wants to merge 1 commit into
mainfrom
joelweisman/cus-221-p0-cli-fails-with-eaddrinuse-on-port

Conversation

@lurkshark

Copy link
Copy Markdown
Contributor

Problem

Login uses a fixed local redirect port (52700 for Google, 52701 for Azure) because the OAuth clients only accept exactly registered redirect URIs. If a second p0 login, or any command that starts a login, runs while another login is waiting for browser approval, the second process fails with a raw listen EADDRINUSE: address already in use error that doesn't tell the user what to do.

Status: N/A

Change

withRedirectServer now checks for EADDRINUSE when the redirect server starts listening. In that case it fails with:

Login failed: port <port> is already in use, probably by another `<app> login` waiting for browser approval.
Finish or cancel that login (Ctrl+C in its terminal), then run this command again.
  • The message is thrown as a plain string, per CONTRIBUTING.md, so no stack trace prints. Both the Google and Azure flows get it, since both go through withRedirectServer.
  • Any other listen error is rejected with the original error object, as before.
  • The listen error handler no longer calls redirectReject. redirectPromise is never awaited when listen fails, so rejecting it produced an unhandled rejection. The global handler would print Unhandled Rejection: ... and exit before the new message appeared.
  • Ports and the login flow are unchanged when the port is free.

Check off any of the following areas of code that are modified:

  • authentication / authorization
  • workflow
  • APIs
  • lifecycle SDK
  • datastore abstractions
  • none of the above

Type of Change

  • Bug fix

Validation

  • Testing: new unit test src/common/auth/__tests__/server.test.ts holds a port open with an http server and asserts withRedirectServer rejects with the exact message and never calls beginAuth. Results from the last review pass (no findings):
    • yarn prettier --check .: pass for all source files (only the untracked .ship-ticket handoff files are flagged)
    • yarn eslint --max-warnings 0 .: pass
    • yarn tsc: pass
    • NODE_ENV=unit yarn vitest run: 349 passed, 8 failed. The 8 failures are in src/commands/__tests__/ssh.test.ts and also fail on the base commit (a local tool-installation check). The new test passes.
  • Blast radius: the login redirect server startup in src/common/auth/server.ts, used by Google and Azure login.
  • Risks & mitigations: none expected. The error text is only shown when the port is already taken, which previously failed anyway.

Rollout / rollback

N/A

Tracking (optional)

https://linear.app/p0-security/issue/CUS-221/p0-cli-fails-with-eaddrinuse-on-port-52700-when-two-commands-run-at

Implementation (optional)

The message is written inline at its single call site rather than as a helper or shared constant.

Follow-up Work (optional)

Review raised nothing that went unfixed. Out of scope here:

  • The SIGINT/SIGTERM handlers registered before listen stay registered when listen fails. The process exits right after, so this has no effect today.
  • The 8 failing ssh.test.ts tests and 6 obsolete snapshots predate this change.

Login uses a fixed local redirect port (52700 for Google, 52701 for Azure). If a second `p0 login`, or a command that starts a login, runs while another is waiting for browser approval, binding that port failed with a raw `listen EADDRINUSE` error.

`withRedirectServer` now detects `EADDRINUSE` and fails with a short message naming the port and telling the user to finish or cancel the other login and rerun. The message is thrown as a plain string so no stack trace prints. Other `listen` errors are passed through unchanged, and the ports and the login flow are the same when the port is free. The listen error handler also no longer rejects the redirect promise, which nothing awaits at that point and which would have surfaced as an unhandled rejection that hid the new message.
@lurkshark

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Nov 11, 2026

Copy link
Copy Markdown

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

The redirect server uses the configured port or 0 when it starts listening. If the port is occupied, startup rejects with a login-specific message that identifies the port and explains how to finish or cancel the other login. Other startup errors are rejected unchanged. Startup errors no longer reject redirectPromise. A test checks the occupied-port rejection and verifies that beginAuth is not called.

Merge Risk: Minimal · up to 5ff2c

Port conflicts now produce the intended guidance. No issue established by this review needs to block merging after normal checks.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: explaining port conflicts when concurrent logins use the same redirect port.
Description check Passed The description is complete and follows the repository template. It explains the problem, change, affected authentication flow, bug-fix type, validation results, blast radius, risks, rollout, tracking…
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is complete and follows the repository template. It explains the problem, change, affected authentication flow, bug-fix type, validation results, blast radius, risks, rollout, tracking, and follow-up work.

Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 2 files.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Essentials
  • Run ID: e33d5670-0257-4913-bdd1-54835299648f
Commits

Reviewing files that changed from the base of the PR and between 24afbf0 and 5ff2c5f.

Files selected for processing: 2

  • src/common/auth/__tests__/server.test.ts
  • src/common/auth/server.ts

Included review availability: This review used your included allowance. 4 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.

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