Skip to content

feat(browser): in-app browser tab with webview security hardening#3181

Open
MattPua wants to merge 8 commits into
mainfrom
posthog-code/browser-tab
Open

feat(browser): in-app browser tab with webview security hardening#3181
MattPua wants to merge 8 commits into
mainfrom
posthog-code/browser-tab

Conversation

@MattPua

@MattPua MattPua commented Jul 6, 2026

Copy link
Copy Markdown
Member

Problem

Working on web changes means bouncing between the app and an external browser. There's no way to view a page (docs, a local dev server, a PR) inside the app next to your task.

Changes

CleanShot.2026-07-06.at.13.12.17.mp4

Adds an embedded browser tab. The panel tab bar "+" is now a dropdown (Terminal / Browser); it stays a plain add-terminal button when the browser flag is off. Gated behind posthog-code-browser-tab (always on in dev).

  • BrowserPanel (features/browser/): address bar with back/forward/reload over an Electron <webview>; host-agnostic via onUrlChange/onTitleChange callbacks
  • Main-process hardening in window.ts (the authoritative boundary — guest pages can't script around it):
    • will-attach-webview strips preload/node access, forces context isolation
    • Navigation guard: http/https/about only, link-local metadata range (169.254.0.0/16) blocked
    • Device permissions (camera/mic/geo/USB/...) denied — the profile is shared and persisted, grants would stick
    • Popups denied and routed to the OS browser, http(s) targets only
  • Address bar normalizes input: scheme passthrough, bare-host detection (loopback defaults to http), everything else becomes a search; disallowed schemes (file:, chrome:, javascript:...) become searches
  • Loading feedback: indeterminate progress bar while a page loads; reload button becomes a stop button mid-load
  • Blank tabs focus the address bar and show a placeholder instead of literal about:blank
  • Last committed url persists on the tab for restore-on-reload; title becomes the tab label

Accepted residual risks (deliberate): loopback/LAN reachable (dev servers are a first-class target), shared authenticated profile across tabs, host blocking is literal-IPv4 (no resolved-IP/IPv6 filtering).

How did you test this?

  • normalizeAddress unit tests (incl. disallowed schemes), panel transform tests
  • Drove the running app over CDP: + dropdown opens Terminal/Browser and each adds a tab
  • @posthog/ui + @posthog/core suites pass, typecheck + biome clean

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

@trunk-io

trunk-io Bot commented Jul 6, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. apps/code/src/main/window.ts, line 71-76 (link)

    P2 Session-level handlers reset on every webview attach

    guest.session is the shared persist:browser session, so setPermissionRequestHandler / setPermissionCheckHandler are overwritten each time a new browser tab is opened. The logic is idempotent here so the behaviour is correct today, but it is worth noting that calling setPermissionRequestHandler again replaces the previous handler rather than composing with it — if the handler ever diverges between webviews this will silently drop the earlier one.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "feat(browser): in-app browser tab with w..." | Re-trigger Greptile

Comment thread packages/core/src/panels/panelLayoutTransforms.test.ts
Comment thread packages/core/src/panels/panelLayoutTransforms.test.ts
- Globe button in panel tab bars opens an embedded browser tab
  (Electron <webview>), gated behind posthog-code-browser-tab flag
- Main-process hardening: preload/node stripped from guests, scheme
  allowlist (http/https/about), link-local metadata range blocked,
  powerful permissions denied, popups routed http(s)-only to OS browser
- Address bar normalizes input (scheme passthrough, host detection,
  search fallback); disallowed schemes become searches
- Last committed url persists on the tab for restore-on-reload

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
@MattPua MattPua force-pushed the posthog-code/browser-tab branch from b4db740 to 7ca9a4e Compare July 6, 2026 15:01
@MattPua

MattPua commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Addressed the review feedback (PostHog Code, on behalf of the author):

  • Both P1 silent test bail-outs: explicit expect(...).toBe("leaf") assertions added before the type-narrowing guards
  • P2 (session handlers reset on every attach): permission handlers now install once per session via a WeakSet guard (hardenWebviewSession), so a future per-guest divergence can't silently replace an earlier handler
  • Rebased onto latest main — resolved conflicts with the new autoresearch tab type, conflicts are cleared

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

React Doctor found 7 issues in 1 file · 7 warnings.

7 warnings

src/features/browser/BrowserPanel.tsx

Reviewed by React Doctor for commit 675f339.

MattPua added 3 commits July 6, 2026 11:10
Single "+" opens a Terminal/Browser menu instead of a row of icon
buttons; falls back to the direct add-terminal button when the browser
flag is off (a one-item menu is worse than a plain button).

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
- Indeterminate top bar (shared quill-section-loading swoop) over the
  page area during loads
- Reload button becomes a stop button mid-load

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
@MattPua MattPua force-pushed the posthog-code/browser-tab branch from 82f4907 to deae0e5 Compare July 6, 2026 17:10
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx Outdated
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts
MattPua added 4 commits July 6, 2026 16:11
Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
Block the IPv6-mapped metadata address and GCP's metadata DNS name, which
the IPv4-only host check let through. Extract the pure navigation guard to
a testable module with regression coverage.

Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
…elper

updateTabLabel/updateTabMetadata/updateBrowserTabUrl shared the same
find-tab-walk-and-map dance. Extract updateTabById; add coverage for the
two transforms that lacked it.

Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
@MattPua MattPua marked this pull request as ready for review July 6, 2026 20:38
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