test: replace self-fulfilling checks with production boundary assertions (#33006)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-23 19:01:22 -07:00
committed by GitHub
co-authored by OrcaWin
parent 9c262ffe36
commit b4fa75e954
14 changed files with 333 additions and 302 deletions
+5 -4
View File
@@ -428,9 +428,10 @@ async function runBenchmark() {
totalDrain: boundedTotalSummary,
inputTimerDelay: boundedInputTimerSummary
},
runtimeIngress: {
syntheticIngressModel: {
scope: 'Local algorithm model; does not execute the shipped PTY runtime',
legacyRepeatedScans: legacyRuntimeIngressSummary,
currentFastPath: currentRuntimeIngressSummary,
modeledFastPath: currentRuntimeIngressSummary,
estimatedReduction:
legacyRuntimeIngressSummary.max /
Math.max(currentRuntimeIngressSummary.max, Number.EPSILON)
@@ -457,8 +458,8 @@ async function runBenchmark() {
`bounded max first slice: ${formatMs(boundedFirstSliceSummary.max)}`,
`bounded max any slice: ${formatMs(boundedMaxSliceSummary.max)}`,
`bounded max total drain: ${formatMs(boundedTotalSummary.max)}`,
`runtime ingress legacy max: ${formatMs(legacyRuntimeIngressSummary.max)}`,
`runtime ingress current max: ${formatMs(currentRuntimeIngressSummary.max)}`,
`synthetic ingress legacy max: ${formatMs(legacyRuntimeIngressSummary.max)}`,
`synthetic ingress fast-path max: ${formatMs(currentRuntimeIngressSummary.max)}`,
legacyInputTimerSummary
? `legacy max input timer delay: ${formatMs(legacyInputTimerSummary.max)}`
: null,
@@ -55,8 +55,9 @@ describe('pty transcript secret scan', () => {
})
it('claims a span once, so a token inside an email is not double-reported', () => {
const findings = scanTranscriptForSecrets('longlivedaccountname@corp.internal')
expect(findings).toHaveLength(1)
const email = 'longlivedaccountnamefortycharacterslongenough@corp.internal'
const findings = scanTranscriptForSecrets(email)
expect(findings).toMatchObject([{ kind: 'email', match: email, index: 0 }])
})
it('passes a fixture that is already scrubbed, so "prove it is gone" can succeed', () => {
@@ -84,7 +85,7 @@ describe('redaction', () => {
it('leaves the rest of the screen byte-for-byte untouched', () => {
const text = 'line one\nuser@corp.io\nline three'
expect(redactTranscript(text).text.split('\n')[2]).toBe('line three')
expect(redactTranscript(text).text).toBe('line one\nXXXXXXXXXXXX\nline three')
})
})
@@ -96,7 +97,7 @@ describe('committed transcripts', () => {
it.each(transcripts)('%s carries no account identifier or credential', (name) => {
const findings = scanTranscriptForSecrets(readFileSync(join(fixtureDir, name), 'utf8'))
expect(formatFindings(name, findings)).toContain('clean')
expect(findings, formatFindings(name, findings)).toEqual([])
})
})
@@ -9,6 +9,7 @@ import {
publishCompleteDraftReleases,
writeGithubOutputs
} from './publish-complete-draft-releases.mjs'
import { getRequiredReleaseAssetNames } from './verify-release-required-assets.mjs'
function git(cwd, args) {
return execFileSync('git', args, {
@@ -18,13 +19,13 @@ function git(cwd, args) {
}).trim()
}
function withGitRepo(run) {
async function withGitRepo(run) {
const dir = mkdtempSync(join(tmpdir(), 'orca-draft-release-'))
try {
git(dir, ['init', '--initial-branch=main'])
git(dir, ['config', 'user.name', 'Test Bot'])
git(dir, ['config', 'user.email', 'test@example.com'])
run(dir)
return await run(dir)
} finally {
rmSync(dir, { recursive: true, force: true })
}
@@ -74,12 +75,26 @@ describe('isReleaseCutDraft', () => {
author: { login: 'github-actions[bot]' }
})
).toBe(false)
expect(
isReleaseCutDraft({
draft: false,
tag_name: 'v1.4.2-rc.7',
author: { login: 'github-actions[bot]' }
})
).toBe(false)
expect(
isReleaseCutDraft({
draft: true,
tag_name: 'v1.4.2-rc.7',
author: { login: 'release-maintainer' }
})
).toBe(false)
})
})
describe('isTagBuiltFromCurrentRef', () => {
it('accepts a tag on the current release commit', () => {
withGitRepo((repo) => {
it('accepts a tag on the current release commit', async () => {
await withGitRepo((repo) => {
commit(repo, 'initial')
commit(repo, 'release: v1.4.36-rc.6')
git(repo, ['tag', 'v1.4.36-rc.6'])
@@ -88,8 +103,8 @@ describe('isTagBuiltFromCurrentRef', () => {
})
})
it('accepts a tag whose release commit is built from the current ref', () => {
withGitRepo((repo) => {
it('accepts a tag whose release commit is built from the current ref', async () => {
await withGitRepo((repo) => {
commit(repo, 'initial')
const source = git(repo, ['rev-parse', 'HEAD'])
commit(repo, 'release: v1.4.36-rc.6')
@@ -100,8 +115,8 @@ describe('isTagBuiltFromCurrentRef', () => {
})
})
it('rejects a stale tag when the current ref has moved on', () => {
withGitRepo((repo) => {
it('rejects a stale tag when the current ref has moved on', async () => {
await withGitRepo((repo) => {
commit(repo, 'initial')
commit(repo, 'release: v1.4.36-rc.6')
git(repo, ['tag', 'v1.4.36-rc.6'])
@@ -114,91 +129,114 @@ describe('isTagBuiltFromCurrentRef', () => {
describe('publishCompleteDraftReleases', () => {
it('publishes complete release-cut drafts and skips incomplete ones', async () => {
const fetchImpl = vi
.fn()
.mockResolvedValueOnce(
await withGitRepo(async (repo) => {
commit(repo, 'release source')
git(repo, ['tag', 'v1.4.2-rc.7'])
git(repo, ['tag', 'v1.4.2-rc.8'])
const releases = [7, 8].map((id) => ({
id,
draft: true,
tag_name: `v1.4.2-rc.${id}`,
created_at: `2026-05-15T0${id}:31:19Z`,
author: { login: 'github-actions[bot]' },
assets: getRequiredReleaseAssetNames(`v1.4.2-rc.${id}`)
.filter((name) => id === 7 || name !== 'orca-windows-setup.exe')
.map((name, index) => ({ id: id * 100 + index, name, state: 'uploaded', size: 1 }))
}))
const manifestUrls = new Map(
releases.flatMap(({ assets }) =>
assets
.filter(({ name }) => name.startsWith('latest'))
.map(({ id, name }) => [
`https://api.github.com/repos/stablyai/orca/releases/assets/${id}`,
name === 'latest.yml' ? 'path: orca-windows-setup.exe\n' : ''
])
)
)
const fetchImpl = vi.fn(async (url, options) => {
if (url === 'https://api.github.com/repos/stablyai/orca/releases?per_page=100') {
return jsonResponse(releases)
}
if (manifestUrls.has(url) && !options.method) {
return jsonResponse(manifestUrls.get(url))
}
if (
url === 'https://api.github.com/repos/stablyai/orca/releases/7' &&
options.method === 'PATCH'
) {
return jsonResponse({ tag_name: 'v1.4.2-rc.7', draft: false })
}
throw new Error(`Unexpected release request: ${options.method ?? 'GET'} ${url}`)
})
const fetch = vi.spyOn(globalThis, 'fetch').mockImplementation(fetchImpl)
try {
const result = await publishCompleteDraftReleases({
repo: 'stablyai/orca',
token: 'token',
fetchImpl,
isDraftBuiltFromCurrentRef: ({ tag }) => isTagBuiltFromCurrentRef(tag, { cwd: repo }),
log: vi.fn()
})
expect(result).toEqual({
published: ['v1.4.2-rc.7'],
skipped: [
{ tag: 'v1.4.2-rc.8', reason: 'Release v1.4.2-rc.8 is missing required assets.' }
]
})
expect(fetchImpl.mock.calls.filter(([, options]) => options.method === 'PATCH')).toEqual([
[
'https://api.github.com/repos/stablyai/orca/releases/7',
expect.objectContaining({
method: 'PATCH',
body: JSON.stringify({ draft: false, prerelease: true })
})
]
])
} finally {
fetch.mockRestore()
}
})
})
it('skips stale complete drafts before publishing', async () => {
await withGitRepo(async (repo) => {
commit(repo, 'old release source')
git(repo, ['tag', 'v1.4.2-rc.7'])
commit(repo, 'current release source')
const fetchImpl = vi.fn().mockResolvedValueOnce(
jsonResponse([
{
id: 7,
draft: true,
tag_name: 'v1.4.2-rc.7',
created_at: '2026-05-15T07:31:19Z',
author: { login: 'github-actions[bot]' }
},
{
id: 8,
draft: true,
tag_name: 'v1.4.2-rc.8',
created_at: '2026-05-15T10:51:57Z',
author: { login: 'github-actions[bot]' }
author: { login: 'github-actions[bot]' },
assets: getRequiredReleaseAssetNames('v1.4.2-rc.7').map((name) => ({
name,
state: 'uploaded',
size: 1
}))
}
])
)
.mockResolvedValueOnce(jsonResponse({ tag_name: 'v1.4.2-rc.7', draft: false }))
const verifyReleaseAssets = vi.fn(async ({ tag }) => {
if (tag === 'v1.4.2-rc.8') {
throw new Error('Release v1.4.2-rc.8 is missing required assets.')
const fetch = vi.spyOn(globalThis, 'fetch').mockImplementation(fetchImpl)
try {
const result = await publishCompleteDraftReleases({
repo: 'stablyai/orca',
token: 'token',
fetchImpl,
isDraftBuiltFromCurrentRef: ({ tag }) => isTagBuiltFromCurrentRef(tag, { cwd: repo }),
log: vi.fn()
})
expect(result).toEqual({
published: [],
skipped: [{ tag: 'v1.4.2-rc.7', reason: 'tag is not built from the current release ref' }]
})
expect(fetchImpl).toHaveBeenCalledTimes(1)
} finally {
fetch.mockRestore()
}
})
const log = vi.fn()
const result = await publishCompleteDraftReleases({
repo: 'stablyai/orca',
token: 'token',
fetchImpl,
verifyReleaseAssets,
isDraftBuiltFromCurrentRef: vi.fn(async () => true),
log
})
expect(result).toEqual({
published: ['v1.4.2-rc.7'],
skipped: [
{
tag: 'v1.4.2-rc.8',
reason: 'Release v1.4.2-rc.8 is missing required assets.'
}
]
})
expect(fetchImpl).toHaveBeenLastCalledWith(
'https://api.github.com/repos/stablyai/orca/releases/7',
expect.objectContaining({
method: 'PATCH',
body: JSON.stringify({ draft: false, prerelease: true })
})
)
})
it('skips stale complete drafts before publishing', async () => {
const fetchImpl = vi.fn().mockResolvedValueOnce(
jsonResponse([
{
id: 7,
draft: true,
tag_name: 'v1.4.2-rc.7',
created_at: '2026-05-15T07:31:19Z',
author: { login: 'github-actions[bot]' }
}
])
)
const verifyReleaseAssets = vi.fn()
const log = vi.fn()
const result = await publishCompleteDraftReleases({
repo: 'stablyai/orca',
token: 'token',
fetchImpl,
verifyReleaseAssets,
isDraftBuiltFromCurrentRef: vi.fn(async () => false),
log
})
expect(result).toEqual({
published: [],
skipped: [{ tag: 'v1.4.2-rc.7', reason: 'tag is not built from the current release ref' }]
})
expect(verifyReleaseAssets).not.toHaveBeenCalled()
expect(fetchImpl).toHaveBeenCalledTimes(1)
})
})
@@ -25,6 +25,11 @@ function before(relPath, prefixes) {
}
return false
}
for (const predicate of [before, after]) {
assert.equal(predicate('packages/app', ['packages/app']), true)
assert.equal(predicate('packages/app/file.ts', ['packages/app']), true)
assert.equal(predicate('packages/app2/file.ts', ['packages/app']), false)
}
const files = Array.from(
{ length: 100000 },
(_, index) => `src/components/group-${index % 100}/file-${index}.tsx`
+3 -1
View File
@@ -137,7 +137,9 @@ describe('count baseline', () => {
['src/a.ts', 1],
['src/c.ts', 0]
])
expect(parseCountBaseline(formatCountBaseline(counts, ['# header']))).toEqual(
const formatted = formatCountBaseline(counts, ['# header'])
expect(formatted).toBe('# header\n1 src/a.ts\n2 src/b.ts\n')
expect(parseCountBaseline(formatted)).toEqual(
new Map([
['src/a.ts', 1],
['src/b.ts', 2]
@@ -1,4 +1,8 @@
import { describe, expect, it, vi } from 'vitest'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { resetWslInteropSpawnDirectoryCache } from '../wsl-interop-spawn-directory'
const { spawnMock } = vi.hoisted(() => ({
spawnMock: vi.fn((..._args: unknown[]) => ({ pid: 1 }))
@@ -9,14 +13,30 @@ vi.mock('node:child_process', () => ({ spawn: spawnMock }))
import { spawnWslRelayProcess } from './wsl-hook-relay-launch'
describe('spawnWslRelayProcess', () => {
it('names an explicit Windows directory rather than inheriting one', () => {
spawnWslRelayProcess('Ubuntu', {}, '1.2.3')
it('launches from the system directory instead of the current worktree', () => {
const systemRoot = mkdtempSync(join(tmpdir(), 'wsl-relay-launch-'))
const env = { ORCA_AGENT_HOOK_PORT: '1234' }
vi.stubEnv('SystemRoot', systemRoot)
resetWslInteropSpawnDirectoryCache()
try {
spawnWslRelayProcess('Ubuntu', env, '1.2.3')
// A stable Windows cwd prevents deleted WSL worktrees from breaking future CreateProcessW calls.
expect(spawnMock).toHaveBeenCalledWith(
'wsl.exe',
expect.arrayContaining(['-d', 'Ubuntu', '--exec']),
expect.objectContaining({ cwd: expect.any(String) })
)
expect(spawnMock).toHaveBeenCalledExactlyOnceWith(
'wsl.exe',
[
'-d',
'Ubuntu',
'--exec',
'sh',
'-c',
'exec sh "$HOME/.orca-wsl/hook-relay/1.2.3/launch.sh"'
],
{ env, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true, cwd: systemRoot }
)
} finally {
vi.unstubAllEnvs()
resetWslInteropSpawnDirectoryCache()
rmSync(systemRoot, { recursive: true, force: true })
}
})
})
@@ -3,13 +3,14 @@ import { describe, expect, it, vi } from 'vitest'
import { ensureWslHookRelayForReattach } from './wsl-hook-relay-reattach'
describe('ensureWslHookRelayForReattach', () => {
it('refreshes the surviving session distro after a local reattach', () => {
it('refreshes exact surviving distros across local reattachments', () => {
const ensure = vi.fn()
ensureWslHookRelayForReattach({ isReattach: true, wslDistro: 'Ubuntu-24.04' }, null, ensure)
for (const wslDistro of ['Ubuntu-24.04', 'Ubuntu', 'Debian']) {
ensureWslHookRelayForReattach({ isReattach: true, wslDistro }, null, ensure)
}
expect(ensure).toHaveBeenCalledOnce()
expect(ensure).toHaveBeenCalledWith('Ubuntu-24.04')
expect(ensure.mock.calls).toEqual([['Ubuntu-24.04'], ['Ubuntu'], ['Debian']])
})
it.each([
@@ -25,13 +26,4 @@ describe('ensureWslHookRelayForReattach', () => {
expect(ensure).not.toHaveBeenCalled()
})
it('preserves exact distro ownership across multiple local reattachments', () => {
const ensure = vi.fn()
ensureWslHookRelayForReattach({ isReattach: true, wslDistro: 'Ubuntu' }, null, ensure)
ensureWslHookRelayForReattach({ isReattach: true, wslDistro: 'Debian' }, null, ensure)
expect(ensure.mock.calls).toEqual([['Ubuntu'], ['Debian']])
})
})
+71 -8
View File
@@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest'
import { clampGrabPayload } from './browser-grab-payload'
function makeRawPayload(overrides: Record<string, unknown> = {}): Record<string, unknown> {
function makeRawPayload(overrides: Record<string, unknown> = {}) {
return {
page: {
sanitizedUrl: 'https://example.com/page?access_token=secret#hash',
@@ -66,7 +66,7 @@ describe('clampGrabPayload', () => {
const payload = clampGrabPayload(
makeRawPayload({
target: {
...(makeRawPayload().target as Record<string, unknown>),
...makeRawPayload().target,
cssClasses: 'primary access_token=secret'
}
})
@@ -79,7 +79,7 @@ describe('clampGrabPayload', () => {
const payload = clampGrabPayload(
makeRawPayload({
target: {
...(makeRawPayload().target as Record<string, unknown>),
...makeRawPayload().target,
elementPath: 'main > button[aria-label="access_token=secret"]',
fullPath: 'body > main > button#client_secret',
reactComponents: '<App> <PasswordSecretPanel>',
@@ -110,7 +110,7 @@ describe('clampGrabPayload', () => {
const payload = clampGrabPayload(
makeRawPayload({
target: {
...(makeRawPayload().target as Record<string, unknown>),
...makeRawPayload().target,
nearbyElements: Array.from({ length: 10 }, (_, index) => `item-${index}`),
reactComponents: '<App>'.repeat(200),
sourceFile: 'src/Button.tsx:12:4'
@@ -118,8 +118,15 @@ describe('clampGrabPayload', () => {
})
)
expect(payload?.target.nearbyElements).toHaveLength(6)
expect(payload?.target.reactComponents?.length).toBeLessThanOrEqual(512)
expect(payload?.target.nearbyElements).toEqual([
'item-0',
'item-1',
'item-2',
'item-3',
'item-4',
'item-5'
])
expect(payload?.target.reactComponents).toBe(`${'<App>'.repeat(100)} (truncated)`)
expect(payload?.target.sourceFile).toBe('src/Button.tsx:12:4')
})
@@ -127,11 +134,11 @@ describe('clampGrabPayload', () => {
const payload = clampGrabPayload(
makeRawPayload({
page: {
...(makeRawPayload().page as Record<string, unknown>),
...makeRawPayload().page,
sanitizedUrl: 'javascript:alert(1)'
},
target: {
...(makeRawPayload().target as Record<string, unknown>),
...makeRawPayload().target,
attributes: {
href: 'javascript:alert(1)',
src: 'data:text/html,<script>alert(1)</script>',
@@ -148,4 +155,60 @@ describe('clampGrabPayload', () => {
expect(payload?.target.attributes.action).toBe('')
expect(payload?.target.attributes.title).toBe('Safe label')
})
it('keeps safe and ARIA attributes while stripping unsafe names', () => {
const payload = clampGrabPayload(
makeRawPayload({
target: {
...makeRawPayload().target,
attributes: {
ID: 'checkout',
class: 'source-code stateful auth token',
role: 'button',
type: 'button',
'aria-label': 'Submit',
'aria-labelledby': 'checkout-label',
'aria-hidden': 'false',
onclick: 'alert(1)',
style: 'display:none',
'data-secret': 'hidden',
'notaria-label': 'unexpected'
}
}
})
)
expect(payload?.target.attributes).toEqual({
id: 'checkout',
class: 'source-code stateful auth token',
role: 'button',
type: 'button',
'aria-label': 'Submit',
'aria-labelledby': 'checkout-label',
'aria-hidden': 'false'
})
})
it.each([
'access_token=credential',
'API_KEY=credential',
'password=credential',
'secret=credential',
'session_id=credential',
'csrf=credential'
])('redacts %s in allowed attribute values', (value) => {
const payload = clampGrabPayload(
makeRawPayload({
target: {
...makeRawPayload().target,
attributes: { title: value, 'aria-label': value }
}
})
)
expect(payload?.target.attributes).toEqual({
title: '[redacted]',
'aria-label': '[redacted]'
})
})
})
+27 -52
View File
@@ -1,5 +1,4 @@
import { describe, expect, it } from 'vitest'
import { z } from 'zod'
import { REMOTE_RUNTIME_MAX_SUBSCRIPTION_PARAM_BYTES } from './remote-runtime-memory-limits'
import {
BROWSER_CLIENT_HOST_PAGE_INVENTORY_MAX_BYTES,
@@ -238,41 +237,6 @@ describe('browser client-host control protocol', () => {
).toThrow('Browser page inventory identity exceeds its JSON byte budget')
})
it('keeps old attach and ready decoders compatible with optional inventory fields', () => {
const legacyAttach = z.object({
authorityRuntimeId: z.string(),
browserHostClientId: z.string(),
hostCapabilities: z.array(z.string()),
pageCommandProtocolVersion: z.literal(1).optional()
})
const legacyReady = z.object({
type: z.literal('ready'),
authorityEpoch: z.string(),
browserHostGeneration: z.number(),
pageCommandProtocolVersion: z.literal(1).optional()
})
expect(
legacyAttach.parse({
authorityRuntimeId: 'runtime-a',
browserHostClientId: 'host-a',
hostCapabilities: ['webview'],
pageInventoryProtocolVersion: 1,
pageInventory: [],
leaseReconnectProtocolVersion: 1
})
).not.toHaveProperty('pageInventory')
expect(
legacyReady.parse({
type: 'ready',
authorityEpoch: 'epoch-a',
browserHostGeneration: 2,
pageInventoryProtocolVersion: 1,
leaseReconnectProtocolVersion: 1
})
).not.toHaveProperty('pageInventoryProtocolVersion')
})
it('binds create-page commands and results to exact bounded authority', () => {
const authority = {
authorityRuntimeId: 'runtime-a',
@@ -359,24 +323,35 @@ describe('browser client-host control protocol', () => {
).toThrow()
})
it('requires every lease and execution-host fence on tunnel attach', () => {
it.each([
{ scope: 'attach', field: 'authorityRuntimeId' },
{ scope: 'attach', field: 'authorityEpoch' },
{ scope: 'attach', field: 'browserHostClientId' },
{ scope: 'attach', field: 'browserHostGeneration' },
{ scope: 'attach', field: 'executionHost' },
{ scope: 'executionHost', field: 'kind' },
{ scope: 'executionHost', field: 'runtimeId' },
{ scope: 'executionHost', field: 'revision' }
])('requires $field in $scope on tunnel attach', ({ scope, field }) => {
const attach = {
authorityRuntimeId: 'runtime-a',
authorityEpoch: 'epoch-a',
browserHostClientId: 'host-a',
browserHostGeneration: 1,
executionHost: { kind: 'native', runtimeId: 'runtime-a', revision: 1 }
}
expect(BrowserNetworkTunnelAttachParams.parse(attach)).toEqual(attach)
const incomplete = Object.fromEntries(
Object.entries(scope === 'attach' ? attach : attach.executionHost).filter(
([key]) => key !== field
)
)
expect(() =>
BrowserNetworkTunnelAttachParams.parse({
authorityRuntimeId: 'runtime-a',
browserHostClientId: 'host-a',
browserHostGeneration: 1,
executionHost: { kind: 'native', runtimeId: 'runtime-a', revision: 1 }
})
BrowserNetworkTunnelAttachParams.parse(
scope === 'attach' ? incomplete : { ...attach, executionHost: incomplete }
)
).toThrow()
expect(
BrowserNetworkTunnelAttachParams.parse({
authorityRuntimeId: 'runtime-a',
authorityEpoch: 'epoch-a',
browserHostClientId: 'host-a',
browserHostGeneration: 1,
executionHost: { kind: 'native', runtimeId: 'runtime-a', revision: 1 }
})
).toMatchObject({ authorityEpoch: 'epoch-a', browserHostGeneration: 1 })
})
it('decodes an exact SSH provider authority without changing native v1 attaches', () => {
@@ -1,5 +1,4 @@
import { describe, expect, it } from 'vitest'
import { z } from 'zod'
import {
BROWSER_CLIENT_HOST_PAGE_RECONCILIATION_PROTOCOL_VERSION,
BrowserClientHostAttachParams,
@@ -77,43 +76,6 @@ describe('browser client-host reconciliation protocol', () => {
}
})
it('keeps optional negotiation fields invisible to old attach and ready decoders', () => {
const legacyAttach = z.object({
authorityRuntimeId: z.string(),
browserHostClientId: z.string(),
hostCapabilities: z.array(z.string()),
pageCommandProtocolVersion: z.literal(1).optional()
})
const legacyReady = z.object({
type: z.literal('ready'),
authorityEpoch: z.string(),
browserHostGeneration: z.number(),
pageCommandProtocolVersion: z.literal(1).optional()
})
expect(
legacyAttach.parse({
authorityRuntimeId: 'runtime-a',
browserHostClientId: 'host-a',
hostCapabilities: ['webview'],
pageCommandProtocolVersion: 1,
pageInventoryProtocolVersion: 1,
pageInventory: [],
pageReconciliationProtocolVersion: 1
})
).not.toHaveProperty('pageReconciliationProtocolVersion')
expect(
legacyReady.parse({
type: 'ready',
authorityEpoch: 'epoch-new',
browserHostGeneration: 4,
pageCommandProtocolVersion: 1,
pageInventoryProtocolVersion: 1,
pageReconciliationProtocolVersion: 1
})
).not.toHaveProperty('pageReconciliationProtocolVersion')
})
it('decodes exact reclaim, close, and restore commands only after negotiation', () => {
const previousAuthority = {
authorityRuntimeId: 'runtime-a',
@@ -180,16 +142,19 @@ describe('browser client-host reconciliation protocol', () => {
).toThrow()
})
it('leaves legacy create and navigate commands unchanged', () => {
const legacyCommand = {
...command({
type: 'createPage',
browserProfileId: 'profile-a',
executionHostKey: 'native:runtime-a:1'
})
}
delete (legacyCommand as { pageReconciliationProtocolVersion?: number })
.pageReconciliationProtocolVersion
it.each([
{
type: 'createPage',
browserProfileId: 'profile-a',
executionHostKey: 'native:runtime-a:1'
},
{ type: 'navigate', url: 'https://remote.internal/' }
])('leaves legacy $type commands unchanged', (legacyPageCommand) => {
const legacyCommand = Object.fromEntries(
Object.entries(command(legacyPageCommand)).filter(
([key]) => key !== 'pageReconciliationProtocolVersion'
)
)
expect(BrowserClientHostCommandEvent.parse(legacyCommand)).toEqual(legacyCommand)
})
@@ -1,15 +1,22 @@
import { describe, expect, it } from 'vitest'
import {
BROWSER_CLIENT_HOSTING_RUNTIME_CAPABILITIES,
expectsBrowserClientHosting,
runtimeAdvertisesBrowserClientHosting
} from './browser-client-hosting-eligibility'
const CLIENT_HOST_CAPABILITIES = [
'browser.clientHost.v1',
'browser.clientHost.pageMetadata.v1',
'browser.clientHost.automation.v1',
'network.browserTunnel.v1',
'network.browserTunnel.executionHosts.v1'
]
const ELIGIBLE = {
enabled: true,
preference: 'auto' as const,
deviceScope: 'desktop',
capabilities: [...BROWSER_CLIENT_HOSTING_RUNTIME_CAPABILITIES, 'browser.screencast.v1']
capabilities: [...CLIENT_HOST_CAPABILITIES, 'browser.screencast.v1']
}
describe('expectsBrowserClientHosting', () => {
@@ -30,9 +37,7 @@ describe('expectsBrowserClientHosting', () => {
expect(expectsBrowserClientHosting({ ...ELIGIBLE, ...input })).toBe(false)
})
// Why each capability gets its own case: the set is the contract between this client's guest
// renderer and the runtime, and dropping any one of them leaves a host that cannot serve it.
it.each(BROWSER_CLIENT_HOSTING_RUNTIME_CAPABILITIES)('refuses without %s', (missing) => {
it.each(CLIENT_HOST_CAPABILITIES)('refuses without %s', (missing) => {
const capabilities = ELIGIBLE.capabilities.filter((capability) => capability !== missing)
expect(runtimeAdvertisesBrowserClientHosting(capabilities)).toBe(false)
-57
View File
@@ -1,57 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
GRAB_SAFE_ATTRIBUTE_NAMES,
GRAB_SECRET_PATTERNS,
isAriaAttribute
} from './browser-grab-types'
describe('browser-grab-types', () => {
describe('isAriaAttribute', () => {
it('returns true for aria- prefixed attributes', () => {
expect(isAriaAttribute('aria-label')).toBe(true)
expect(isAriaAttribute('aria-labelledby')).toBe(true)
expect(isAriaAttribute('aria-hidden')).toBe(true)
})
it('returns false for non-aria attributes', () => {
expect(isAriaAttribute('class')).toBe(false)
expect(isAriaAttribute('id')).toBe(false)
expect(isAriaAttribute('notaria-label')).toBe(false)
})
})
describe('GRAB_SAFE_ATTRIBUTE_NAMES', () => {
it('includes core safe attributes', () => {
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('id')).toBe(true)
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('class')).toBe(true)
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('role')).toBe(true)
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('type')).toBe(true)
})
it('does not include unsafe attributes', () => {
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('onclick')).toBe(false)
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('style')).toBe(false)
expect(GRAB_SAFE_ATTRIBUTE_NAMES.has('data-secret')).toBe(false)
})
})
describe('GRAB_SECRET_PATTERNS', () => {
it('includes precise secret patterns', () => {
expect(GRAB_SECRET_PATTERNS).toContain('access_token')
expect(GRAB_SECRET_PATTERNS).toContain('api_key')
expect(GRAB_SECRET_PATTERNS).toContain('password')
expect(GRAB_SECRET_PATTERNS).toContain('secret')
expect(GRAB_SECRET_PATTERNS).toContain('session_id')
expect(GRAB_SECRET_PATTERNS).toContain('csrf')
})
it('does not include overly broad patterns', () => {
// Why: 'code' and 'state' match normal CSS classes like 'source-code'
// and 'stateful', causing false positive redactions on most sites.
expect(GRAB_SECRET_PATTERNS).not.toContain('code')
expect(GRAB_SECRET_PATTERNS).not.toContain('state')
expect(GRAB_SECRET_PATTERNS).not.toContain('auth')
expect(GRAB_SECRET_PATTERNS).not.toContain('token')
})
})
})
@@ -27,19 +27,20 @@ describe('browser network tunnel stream framing', () => {
expect(errors).toEqual([])
})
it('fails closed on oversized or empty frames', () => {
const oversizedError = vi.fn()
const oversized = new Uint8Array(4)
new DataView(oversized.buffer).setUint32(0, 2 * 1024 * 1024, false)
const oversizedDecoder = new BrowserNetworkTunnelStreamFrameDecoder(() => {}, oversizedError)
const emptyError = vi.fn()
const emptyDecoder = new BrowserNetworkTunnelStreamFrameDecoder(() => {}, emptyError)
it.each([0, 2 * 1024 * 1024])('stays closed after rejecting a %i-byte frame', (length) => {
const onFrame = vi.fn()
const onError = vi.fn()
const header = new Uint8Array(4)
new DataView(header.buffer).setUint32(0, length, false)
const decoder = new BrowserNetworkTunnelStreamFrameDecoder(onFrame, onError)
oversizedDecoder.feed(oversized)
emptyDecoder.feed(new Uint8Array([0, 0, 0, 0]))
decoder.feed(header)
decoder.feed(encodeBrowserNetworkTunnelStreamFrame(new Uint8Array([1])))
expect(oversizedError).toHaveBeenCalledOnce()
expect(emptyError).toHaveBeenCalledOnce()
expect(onFrame).not.toHaveBeenCalled()
expect(onError).toHaveBeenCalledExactlyOnceWith(
expect.objectContaining({ message: 'browser_tunnel_stream_frame_invalid' })
)
})
it('fails the stream when a frame consumer rejects input', () => {
+29 -9
View File
@@ -76,16 +76,36 @@ describe('browser screencast binary protocol', () => {
expect(decodeBrowserScreencastFrame(encoded)).toBeNull()
})
it('rejects oversized metadata before decoding it', () => {
const encoded = new Uint8Array(16 + BROWSER_SCREENCAST_MAX_METADATA_BYTES + 1)
const view = new DataView(encoded.buffer)
encoded[0] = 0x62
encoded[1] = 1
encoded[2] = BrowserScreencastOpcode.Frame
encoded[3] = 1
view.setUint32(8, BROWSER_SCREENCAST_MAX_METADATA_BYTES + 1, true)
it('rejects oversized valid metadata before decoding it', () => {
const metadata = { deviceWidth: 1280, padding: '' }
metadata.padding = 'x'.repeat(
BROWSER_SCREENCAST_MAX_METADATA_BYTES -
new TextEncoder().encode(JSON.stringify(metadata)).byteLength
)
const withinBudget = encodeBrowserScreencastFrame({
opcode: BrowserScreencastOpcode.Frame,
seq: 1,
format: 'jpeg',
metadata,
image: new Uint8Array([1])
})
expect(decodeBrowserScreencastFrame(withinBudget)?.metadata).toEqual({ deviceWidth: 1280 })
expect(decodeBrowserScreencastFrame(encoded)).toBeNull()
const oversizedMetadata = { ...metadata, padding: `${metadata.padding}x` }
const oversized = encodeBrowserScreencastFrame({
opcode: BrowserScreencastOpcode.Frame,
seq: 1,
format: 'jpeg',
metadata: oversizedMetadata,
image: new Uint8Array([1])
})
const decode = vi.spyOn(TextDecoder.prototype, 'decode')
try {
expect(decodeBrowserScreencastFrame(oversized)).toBeNull()
expect(decode).not.toHaveBeenCalled()
} finally {
decode.mockRestore()
}
})
it('rejects excessive metadata nesting before JSON.parse', () => {