fix(mobile): keep a proxied wss host on :443 when editing by ye4241 · Pull Request #11383 · stablyai/orca · GitHub
Skip to content

fix(mobile): keep a proxied wss host on :443 when editing - #11383

Merged
Jinwoo-H merged 3 commits into
stablyai:mainfrom
ye4241:fix/mobile-edit-host-scheme-default-port
Jul 30, 2026
Merged

Jinwoo-H merged 3 commits into
stablyai:mainfrom
ye4241:fix/mobile-edit-host-scheme-default-port

Conversation

@ye4241

@ye4241 ye4241 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Editing a host that was paired through a reverse proxy silently moved it to a port nothing is listening on.

A host paired with an endpoint like wss://desk.example.com carries an implicit :443. Opening Edit host and saving — even when only changing the display name — rewrote the endpoint to wss://desk.example.com:6768, after which the host could no longer connect. There was no warning, and the address field never showed a port, so the change was invisible until the next reconnect failed.

Root cause:

  • endpointPort intentionally reports only explicitly written ports (its doc comment calls this out, since new URL('wss://host:443').port is empty). For wss://desk.example.com it correctly returns undefined.
  • The edit screen passed that undefined straight through as fallbackPort, where resolveFallbackPort substituted the LAN DEFAULT_PORT (6768).

This adds endpointPortOrSchemeDefault, which falls back to the scheme's implicit port for wss and deliberately leaves bare ws as undefined so LAN pairings keep landing on DEFAULT_PORT. The edit screen uses it for its fallback.

normalizeHostEndpoint is not touched: filling a missing port from fallbackPort is its documented contract and is covered by existing tests (fills missing port on scheme URLs from fallbackPort). Changing it would have broken that contract for every caller.

Reproduction

  1. Pair a host with a reverse-proxied endpoint: orca serve --pairing-address wss://desk.example.com --mobile-pairing
  2. On mobile, long-press the host → Edit host
  3. Change only the name, save
  4. The stored endpoint is now wss://desk.example.com:6768 and the host cannot reconnect

Screenshots

No visual change.

Testing

  • pnpm lint
  • pnpm typecheck
  • pnpm test — see the note below on pre-existing failures
  • pnpm build
  • Added or updated high-quality tests that would catch regressions, or explained why tests were not needed

On pnpm test: the root suite reports 43 pre-existing failures (8 files, e.g. src/renderer/src/components/browser-pane/markup/use-markup-draw-hint.test.ts). They are not caused by this PR:

  • This branch's entire diff against upstream/main is three files, all under mobile/; git diff upstream/main -- src/ is empty.
  • The root Vitest config's include covers src/**, config/scripts/**, tools/** and tests/e2e/** — it does not load mobile/ at all, so nothing changed here is even executed by that suite.
  • Re-running the failing file in isolation reproduces it identically, so it is a stable pre-existing failure rather than flake.

My local Node is 26.5.0 while the repo pins 24 (Unsupported engine warning), which may well be the cause — worth a sanity check on CI, but it is orthogonal to this change.

Six tests added to mobile/src/transport/host-endpoint.test.ts, including two that exercise the full edit-host round trip (displayHostEndpoint → normalizeHostEndpoint) rather than just the new function in isolation — that round trip is where the port was being lost.

I verified the tests actually catch the regression by reverting the fix in place: the two meaningful assertions fail (expected undefined to be '443', and the round trip yielding :6768 instead of :443), and pass again once restored. The remaining assertions pin the behavior that must not change: explicit ports are preserved, bare ws still resolves to DEFAULT_PORT, and non-URL input still reports nothing.

mobile is a separate workspace, so its suite was run there as well: 354 files / 2604 tests pass, plus oxlint and tsc --noEmit.

AI Review Report

Reviewed with Claude. Main risks checked:

  • Contract breakage. The obvious fix — making normalizeSchemeUrl use the scheme default — would have silently changed normalizeHostEndpoint('ws://host', { fallbackPort: '9000' }), which an existing test pins. Confirmed the fix stays on the caller side and that no existing assertion changed.
  • Regression surface for LAN pairings. ws://host without a port intentionally still returns undefined so DEFAULT_PORT continues to apply; asserted explicitly rather than left implicit, since the asymmetry between ws and wss is the kind of thing a later refactor would "tidy up" incorrectly.
  • Lint budget. host-endpoint.ts sits near the max-lines ceiling; the first draft pushed it to 302/300. Per AGENTS.md this must never be resolved with a max-lines disable or a per-file bump, so the comments were tightened instead. Final oxlint run is clean.
  • Cross-platform (macOS / Linux / Windows). No platform-specific surface is touched: this is pure string/URL logic in the mobile transport layer, with no filesystem paths, no shell invocation, no keyboard shortcuts or modifier labels, and no Electron main-process or IPC code. The changed module is shared by the Expo app on both iOS and Android and behaves identically on each; nothing here is reachable from the desktop build.

Security Audit

  • Input handling. The new function only reads an endpoint string already persisted by the pairing flow and delegates parsing to the existing endpointPort / endpointScheme. No new parser, no regex, no additional trust placed in the input.
  • Value provenance. The only value it can introduce is the literal '443'; it never derives a port from user-typed text. Validation of anything the user types still runs through normalizeHostEndpoint, unchanged.
  • Blast radius. The practical effect is that a host stays on the port it was paired with instead of being silently moved to 6768 — it narrows, rather than widens, where the client will dial.
  • Not touched. No command execution, path handling, auth/secret material, IPC, or dependency changes. No new packages.
  • Follow-up. None identified.

Notes

  • Two related papercuts were found while investigating but are not in this PR, to keep it reviewable:
    • displayHostEndpoint drops the scheme when no explicit port is present, so wss://desk.example.com is shown as a bare desk.example.com. That is a large part of why this bug was invisible to the user, but fixing it affects other callers and deserves its own change.
    • normalizeHostEndpoint's DEFAULT_PORT fallback for scheme URLs is arguably surprising in general (RFC 6455 would imply :80 / :443), but it is the documented contract here and changing it is a product decision, not a bug fix.
  • Reported symptom context: this reproduces whenever Orca is reached over a reverse proxy on a standard port rather than LAN/Tailscale on 6768, which appears to be outside the shapes the existing tests cover — every ws(s):// case in host-endpoint.test.ts carries an explicit port.

@greptile-apps

greptile-apps Bot commented Jul 29, 2026 •

Copy link
Copy Markdown

@coderabbitai

coderabbitai Bot commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf474017-d838-4c1f-aee1-dae74bba1f71

📥 Commits

Reviewing files that changed from the base of the PR and between 0f0cbad54e115be2d1c2bdeee9f6058c1224a2a1 and 6a35f5d.

📒 Files selected for processing (4)
  • mobile/app/h/[hostId]/edit.tsx
  • mobile/src/host-edit-save-flow.test.ts
  • mobile/src/transport/host-endpoint-edit.test.ts
  • mobile/src/transport/host-endpoint-edit.ts

📝 Walkthrough

Walkthrough

Adds resolveHostEndpointEdit with unchanged, changed, and invalid results. It preserves stored endpoint formatting and route suffixes, handles scheme and port semantics, compares equivalent authorities, and validates invalid input. The host edit screen now uses these results for save gating, persistence, reconnect behavior, and connection previews. Tests cover normalization cases, route preservation, invalid input, idempotent edits, and rename-only saves.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, specific, and accurately summarizes the main mobile editing fix.
Description check ✅ Passed The description follows the template and includes the required summary, screenshots, testing, review, security, and notes sections.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

ye4241 and others added 3 commits July 29, 2026 19:13
A host paired through a reverse proxy is stored as `wss://desk.example.com`
with no explicit port. Editing it — even to only change the display name —
rewrote the endpoint to `wss://desk.example.com:6768` and stranded the host,
with no warning.

`endpointPort` intentionally reports only explicitly written ports, so it
returns undefined for that endpoint. The edit screen passed that undefined
straight through as `fallbackPort`, where `resolveFallbackPort` substituted
the LAN `DEFAULT_PORT`.

Add `endpointPortOrSchemeDefault`, which falls back to the scheme's implicit
port for wss and leaves bare ws alone so LAN pairings keep landing on
DEFAULT_PORT, and use it for the edit screen's fallback. `normalizeHostEndpoint`
is untouched — filling a missing port from `fallbackPort` is its documented
contract and stays covered by its existing tests.
@Jinwoo-H
Jinwoo-H force-pushed the fix/mobile-edit-host-scheme-default-port branch from 0f0cbad to 6a35f5d Compare July 30, 2026 02:15
@Jinwoo-H
Jinwoo-H merged commit 6b1139f into stablyai:main Jul 30, 2026
42 checks passed
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…1383)

* fix(mobile): keep a proxied wss host on :443 when editing

A host paired through a reverse proxy is stored as `wss://desk.example.com`
with no explicit port. Editing it — even to only change the display name —
rewrote the endpoint to `wss://desk.example.com:6768` and stranded the host,
with no warning.

`endpointPort` intentionally reports only explicitly written ports, so it
returns undefined for that endpoint. The edit screen passed that undefined
straight through as `fallbackPort`, where `resolveFallbackPort` substituted
the LAN `DEFAULT_PORT`.

Add `endpointPortOrSchemeDefault`, which falls back to the scheme's implicit
port for wss and leaves bare ws alone so LAN pairings keep landing on
DEFAULT_PORT, and use it for the edit screen's fallback. `normalizeHostEndpoint`
is untouched — filling a missing port from `fallbackPort` is its documented
contract and stays covered by its existing tests.

* review(mobile): preserve untouched host endpoints

* fix(mobile): preserve routed endpoint edits

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
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.

3 participants