fix(browser): filter non-page CDP targets (#103115)

* fix(browser): filter non-page CDP targets

* fix(browser): require page CDP targets

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
llagy007
2026-07-10 00:18:04 +01:00
committed by GitHub
co-authored by Peter Steinberger
parent beda4218af
commit 910886814d
4 changed files with 26 additions and 8 deletions
@@ -16,6 +16,7 @@ const BROWSER_INTERNAL_TARGET_URL_PREFIXES = [
type BrowserTargetUrlLike = {
url?: string | null;
type?: string | null;
};
/** Return true for browser-owned chrome/devtools/internal URLs. */
@@ -24,7 +25,7 @@ function isBrowserInternalTargetUrl(url: string | null | undefined): boolean {
return BROWSER_INTERNAL_TARGET_URL_PREFIXES.some((prefix) => normalized.startsWith(prefix));
}
/** Return true when a CDP target should be selectable by user-facing actions. */
/** Return true when a CDP page target should be selectable by user-facing actions. */
export function isSelectableCdpBrowserTarget(target: BrowserTargetUrlLike): boolean {
return !isBrowserInternalTargetUrl(target.url);
return target.type === "page" && !isBrowserInternalTargetUrl(target.url);
}
@@ -23,7 +23,6 @@ import type {
import { formatErrorMessage } from "../infra/errors.js";
import { SsrFBlockedError, type SsrFPolicy } from "../infra/net/ssrf.js";
import { withNoProxyForCdpUrl } from "./cdp-proxy-bypass.js";
import { isSelectableCdpBrowserTarget } from "./cdp-target-filter.js";
import {
appendCdpPath,
assertCdpEndpointAllowed,
@@ -1844,9 +1843,6 @@ async function readPagesViaPlaywright(
throw err;
}
}
if (!isSelectableCdpBrowserTarget({ url })) {
continue;
}
results.push({
targetId: tid,
title,
@@ -79,7 +79,7 @@ describe("browser remote profile fallback and attachOnly behavior", () => {
expect(tabs.map((t) => t.targetId)).toEqual(["T1"]);
});
it("filters browser-internal targets from raw CDP tab listing", async () => {
it("filters browser-internal and non-page targets from raw CDP tab listing", async () => {
vi.spyOn(deps.pwAiModule, "getPwAiModule").mockResolvedValue(null);
const { remote } = deps.createRemoteRouteHarness(
vi.fn(
@@ -98,6 +98,27 @@ describe("browser remote profile fallback and attachOnly behavior", () => {
webSocketDebuggerUrl: "wss://1.1.1.1:9222/devtools/page/UNTRUSTED",
type: "page",
},
{
id: "WORKER",
title: "Dedicated Worker",
url: "https://example.com/worker.js",
webSocketDebuggerUrl: "wss://1.1.1.1:9222/devtools/page/WORKER",
type: "worker",
},
{
id: "SERVICE_WORKER",
title: "Service Worker",
url: "https://example.com/sw.js",
webSocketDebuggerUrl: "wss://1.1.1.1:9222/devtools/page/SERVICE_WORKER",
type: "service_worker",
},
{
id: "IFRAME",
title: "Iframe",
url: "https://example.com/frame",
webSocketDebuggerUrl: "wss://1.1.1.1:9222/devtools/page/IFRAME",
type: "iframe",
},
{
id: "T1",
title: "Tab 1",
@@ -158,7 +158,7 @@ type JsonListEntry = {
title: string;
url: string;
webSocketDebuggerUrl: string;
type: "page";
type: string;
};
/** Creates a /json/list fetch mock with static entries. */