Skip to content

Add external URL bypass rules for embedded browser opens - #768

Merged
lawrencecchen merged 2 commits into
mainfrom
task-external-browser-open-rules
Mar 3, 2026
Merged

lawrencecchen merged 2 commits into
mainfrom
task-external-browser-open-rules

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Mar 3, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Add a new Browser setting for URLs that should always open in the system browser, with one rule per line (plain substring or re: regex)
  • Apply the same external-bypass rules in both terminal link clicks and the Resources/bin/open wrapper path for intercepted open http(s) commands
  • Add regression coverage for settings matching and wrapper behavior, including invalid-regex handling

Testing

  • python3 tests/test_open_wrapper.py (pass)
  • xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -only-testing:cmuxTests/BrowserLinkOpenSettingsTests test (pass)
  • xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -only-testing:cmuxTests/CmuxWebViewKeyEquivalentTests test (pass)
  • xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux -configuration Debug -destination 'platform=macOS' build (pass)
  • codex exec review --uncommitted -m gpt-5.3-codex --dangerously-bypass-approvals-and-sandbox -c model_reasoning_effort="medium" (0 actionable findings)

Issues

  • Related task: David Chu feedback that /extra-usage and similar flows auto-open inside cmux browser instead of default browser

Summary by CodeRabbit

  • New Features

    • Added configurable external URL patterns in Settings to control which links open externally versus in-app.
    • Support for literal substring matching (case-insensitive) and regex pattern matching.
    • Unified handling of external URL opening across browser navigation commands.
  • Tests

    • Added comprehensive test coverage for external URL pattern matching.

@vercel

vercel Bot commented Mar 3, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 3, 2026 1:44am

@coderabbitai

coderabbitai Bot commented Mar 3, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The pull request introduces configurable external URL opening across the cmux application. Users can specify URL patterns in settings that should open in the system browser rather than in-app. Pattern matching supports literal substring matches (case-insensitive) and regex patterns (prefixed with "re:"). The feature integrates across the CLI, terminal controller, and browser panel layers.

Changes

Cohort / File(s) Summary
Configuration & Pattern Matching
Sources/Panels/BrowserPanel.swift
Added BrowserLinkOpenSettings helper methods: externalOpenPatterns() to retrieve configured patterns, shouldOpenExternally(_:) for URL matching, and parseExternalPattern() to distinguish regex (prefixed "re:") from literal patterns. Includes case-insensitive substring and regex matching logic.
CLI Environment Integration
CLI/cmux.swift, Resources/bin/open
Added respect_external_open_rules runtime flag parsed from CMUX_RESPECT_EXTERNAL_OPEN_RULES environment variable. The open wrapper script now passes this flag to cmux CLI invocations.
Settings UI
Sources/cmuxApp.swift
Added AppStorage property and UI block in SettingsView for "URLs to Always Open Externally", with TextEditor for newline-separated pattern entry and initialization/reset logic.
Terminal & Browser Flow
Sources/TerminalController.swift, Sources/GhosttyTerminalView.swift
Terminal controller now checks respect_external_open_rules flag and external patterns before opening URLs; on match, attempts external open via NSWorkspace and returns external placement metadata. Ghost terminal view adds early guard to open matched URLs externally, bypassing embedded browser flow.
Test Coverage
cmuxTests/CmuxWebViewKeyEquivalentTests.swift, tests/test_open_wrapper.py
New test cases verifying default empty patterns, case-insensitive literal and regex matching, digit character classes in regex, invalid regex handling, and integration with test open wrapper function.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A bunny hops through URLs with care,
Some stay in-app, while some fly fair,
With patterns set and rules defined,
Each link now finds its rightful kind,
External, internal—the choice is clear! 🌐

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding configurable external URL bypass rules for embedded browser opens.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch task-external-browser-open-rules

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 222a83f6b0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread Resources/bin/open Outdated
@greptile-apps

greptile-apps Bot commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Added a configurable external URL bypass feature that allows users to specify URLs that should always open in the system browser instead of cmux's embedded browser. The implementation supports both plain substring matching and regex patterns (prefixed with re:), applies consistently across terminal link clicks and intercepted open commands, and includes comprehensive test coverage for both Swift and bash components.

  • Implemented dual pattern matching in BrowserPanel.swift (Swift/NSRegularExpression) and Resources/bin/open (bash/POSIX ERE) with case-insensitive matching
  • Added new settings UI with TextEditor and clear documentation including example patterns
  • Invalid regex patterns are gracefully handled by silently skipping them without breaking functionality
  • External patterns are checked before whitelist rules, ensuring correct precedence
  • Test coverage includes: default values, literal matching, regex matching, invalid regex handling, and wrapper script behavior

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - clean implementation with comprehensive test coverage
  • The implementation is well-structured with proper error handling for edge cases (invalid regex, empty patterns). Both Swift and bash implementations follow consistent logic for pattern matching. All tests pass including regression coverage for settings matching and wrapper behavior. No breaking changes to existing functionality.
  • No files require special attention

Important Files Changed

Filename Overview
Resources/bin/open Added external URL pattern matching (literal and regex) with proper error handling for invalid regex patterns
Sources/Panels/BrowserPanel.swift Implemented external pattern matching settings with case-insensitive substring and regex support
Sources/GhosttyTerminalView.swift Added external URL check for terminal link clicks to bypass embedded browser
Sources/cmuxApp.swift Added settings UI for external URL patterns with TextEditor and clear instructions in subtitle
cmuxTests/CmuxWebViewKeyEquivalentTests.swift Added comprehensive tests for external pattern matching including invalid regex handling
tests/test_open_wrapper.py Added Python tests for bash wrapper external pattern behavior and error handling

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[URL Open Request] --> B{Source?}
    B -->|Terminal Link Click| C[GhosttyTerminalView]
    B -->|open command| D[Resources/bin/open wrapper]
    
    C --> E{BrowserLinkOpenSettings<br/>shouldOpenExternally?}
    D --> F[Load browserExternalOpenPatterns<br/>from UserDefaults]
    F --> G{url_matches_external_open_patterns?}
    
    E -->|Yes| H[Open in System Browser]
    E -->|No| I[Continue to embedded browser logic]
    
    G -->|Yes| J[Add to failed_urls array]
    G -->|No| K{Host matches whitelist?}
    
    J --> L[Fallback to system open]
    K -->|Yes| M[Open in cmux browser via CLI]
    K -->|No| N[Add to failed_urls array]
    N --> L
    
    I --> O[Check host whitelist]
    O --> P{Matches?}
    P -->|Yes| Q[Open in embedded browser]
    P -->|No| H
    
    style E fill:#e1f5ff
    style G fill:#e1f5ff
    style H fill:#ffe1e1
    style Q fill:#e1ffe1
    style M fill:#e1ffe1
Loading

Last reviewed commit: 222a83f

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/test_open_wrapper.py (1)

242-329: Add one negative-match regression case for external patterns.

The new coverage validates matching and invalid-regex behavior well. I’d also add a non-matching pattern case to lock in intended behavior when external_patterns is present but does not match the URL.

➕ Suggested test addition
+def test_external_pattern_non_match_behavior_is_stable(failures: list[str]) -> None:
+    url = "https://unmatched.example.net/path"
+    open_log, cmux_log, code, stderr = run_wrapper(
+        args=[url],
+        intercept_setting="1",
+        whitelist="",
+        external_patterns="platform.openai.com/account/usage",
+    )
+    expect(code == 0, f"external non-match: wrapper exited {code}: {stderr}", failures)
+    # Assert the intended contract explicitly (choose expected branch and lock it in).
+    # Example if deferral-for-all is intended:
+    expect(cmux_log == [f"browser open {url}"], f"external non-match: unexpected cmux log {cmux_log}", failures)
+    expect(open_log == [], f"external non-match: expected no system open calls, got {open_log}", failures)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_open_wrapper.py` around lines 242 - 329, Add a negative-match test
that ensures when external_patterns is provided but doesn't match the URL the
wrapper falls back to the system open path: create a new test function (e.g.,
test_external_pattern_non_matching_opens_system) that calls run_wrapper with a
URL like "https://example.com/path", intercept_setting="1", whitelist="", and
external_patterns set to a non-matching literal (e.g., "platform.openai.com"),
then assert code == 0, cmux_log == [] (no cmux/browser open), open_log ==
[f"system open {url}"], and that stderr does not contain "invalid regular
expression"; add this next to the other test_* functions so it covers the
non-matching pattern regression.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@tests/test_open_wrapper.py`:
- Around line 242-329: Add a negative-match test that ensures when
external_patterns is provided but doesn't match the URL the wrapper falls back
to the system open path: create a new test function (e.g.,
test_external_pattern_non_matching_opens_system) that calls run_wrapper with a
URL like "https://example.com/path", intercept_setting="1", whitelist="", and
external_patterns set to a non-matching literal (e.g., "platform.openai.com"),
then assert code == 0, cmux_log == [] (no cmux/browser open), open_log ==
[f"system open {url}"], and that stderr does not contain "invalid regular
expression"; add this next to the other test_* functions so it covers the
non-matching pattern regression.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6f6485 and 3fd4ada.

📒 Files selected for processing (8)
  • CLI/cmux.swift
  • Resources/bin/open
  • Sources/GhosttyTerminalView.swift
  • Sources/Panels/BrowserPanel.swift
  • Sources/TerminalController.swift
  • Sources/cmuxApp.swift
  • cmuxTests/CmuxWebViewKeyEquivalentTests.swift
  • tests/test_open_wrapper.py

@lawrencecchen
lawrencecchen merged commit fdc38a3 into main Mar 3, 2026
8 checks passed
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
…#768)

* Add external URL bypass rules for embedded browser opens

* Align open-wrapper external regex handling with app-side matcher

This branch was successfully deployed

1 active deployment
Preview — 3fd4ada0 Deployed Mar 3, 2026 by vercel[bot]
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