fix(browser): require runtime browser capability

This commit is contained in:
Jinjing
2026-08-12 21:21:39 -07:00
parent aeb7183afe
commit 9c7bcffe2a
2 changed files with 38 additions and 7 deletions
@@ -4,6 +4,7 @@ import {
toRuntimeExecutionHostId,
toSshExecutionHostId
} from '../../../shared/execution-host'
import { BROWSER_SCREENCAST_RUNTIME_CAPABILITY } from '../../../shared/protocol-version'
import {
canOpenWorkspaceBrowserTabOnRuntime,
openWorkspaceBrowserTab
@@ -43,7 +44,10 @@ function ownerState(hostId?: string, runtimeOwnerEnvironmentId?: string): Record
function browserCapableRuntime(environmentId: string): Record<string, unknown> {
return {
runtimeStatusByEnvironmentId: new Map([
[environmentId, { status: { capabilities: ['browser.screencast.v1'] }, checkedAt: 1 }]
[
environmentId,
{ status: { capabilities: [BROWSER_SCREENCAST_RUNTIME_CAPABILITY] }, checkedAt: 1 }
]
])
}
}
@@ -164,6 +168,27 @@ describe('openWorkspaceBrowserTab', () => {
expect(mocks.state.createBrowserTab).not.toHaveBeenCalled()
})
it('does not fall back to a client browser when asserted runtime creation fails', async () => {
mocks.state = {
...ownerState(toRuntimeExecutionHostId('hub-a')),
...browserCapableRuntime('hub-a'),
createBrowserTab: vi.fn(),
defaultBrowserSessionProfileId: 'client-profile',
defaultBrowserSessionProfileIdByHostId: {}
}
mocks.createRemote.mockResolvedValue(false)
await expect(
openWorkspaceBrowserTab({
workspaceId: WORKSPACE_ID,
url: 'https://example.com/',
intent: { kind: 'url' },
expectedRuntimeEnvironmentId: 'hub-a'
})
).rejects.toThrow('Unable to open URL.')
expect(mocks.state.createBrowserTab).not.toHaveBeenCalled()
})
// Two dev servers on one host must not share a tab title.
it('keeps the port in local-dev tab titles', async () => {
const createBrowserTab = vi.fn()
@@ -8,6 +8,7 @@ import {
type ExecutionHostId
} from '../../../shared/execution-host'
import { SEARCH_ENGINE_LABELS, type SearchEngine } from '../../../shared/browser-url'
import { BROWSER_SCREENCAST_RUNTIME_CAPABILITY } from '../../../shared/protocol-version'
import {
getClientCreationActionPolicy,
type ClientCreationActionAvailability
@@ -25,15 +26,21 @@ export type OpenWorkspaceBrowserTabRequest = {
}
function isExpectedRuntimeBrowserRoute(
availability: ClientCreationActionAvailability,
state: AppState,
route: ReturnType<typeof resolveWorktreeOperationRoute>,
expectedRuntimeEnvironmentId: string
): boolean {
if (availability.state !== 'enabled' || availability.provider !== 'paired-runtime' || !route) {
if (!route) {
return false
}
const expectedEnvironmentId = expectedRuntimeEnvironmentId.trim()
const environmentId = route.runtimeEnvironmentId?.trim() || null
if (environmentId !== expectedRuntimeEnvironmentId.trim()) {
const capabilities =
state.runtimeStatusByEnvironmentId?.get(expectedEnvironmentId)?.status?.capabilities
if (
environmentId !== expectedEnvironmentId ||
!capabilities?.includes(BROWSER_SCREENCAST_RUNTIME_CAPABILITY)
) {
return false
}
const host = parseExecutionHostId(route.executionHostId)
@@ -48,9 +55,8 @@ export function canOpenWorkspaceBrowserTabOnRuntime(
workspaceId: string,
expectedRuntimeEnvironmentId: string
): boolean {
const availability = getClientCreationActionPolicy(state, workspaceId)['managed-browser']
const route = resolveWorktreeOperationRoute(state, workspaceId)
return isExpectedRuntimeBrowserRoute(availability, route, expectedRuntimeEnvironmentId)
return isExpectedRuntimeBrowserRoute(state, route, expectedRuntimeEnvironmentId)
}
// Why: concurrent URL tabs are indistinguishable under a shared "Open URL"
@@ -166,7 +172,7 @@ export async function openWorkspaceBrowserTab(
const expectedEnvironmentId = request.expectedRuntimeEnvironmentId?.trim() || null
if (
expectedEnvironmentId &&
!isExpectedRuntimeBrowserRoute(availability, route, expectedEnvironmentId)
!isExpectedRuntimeBrowserRoute(state, route, expectedEnvironmentId)
) {
throw openFailure(presentation.error, 'asserted runtime cannot provide this managed browser')
}