Files
orca/src/main/ipc/terminal-render-desync-evidence.test.ts
T
mirror 34fa2cd5ca
Skill update round trip / roundtrip (false, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, ubuntu-latest, symlink, latest) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (false, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, macos-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, ubuntu-latest, symlink, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, copy, 1.5.17) (push) Canceled after 0s
Skill update round trip / roundtrip (true, windows-latest, symlink, 1.5.17) (push) Canceled after 0s
source snapshot 2026-09-02
2026-09-02 02:03:16 +08:00

122 lines
4.3 KiB
TypeScript

import { mkdtemp, readFile, readdir, rm, stat } from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
import { afterEach, describe, expect, it, vi } from 'vitest'
const { ipcHandle, isTrustedUIRenderer } = vi.hoisted(() => ({
ipcHandle: vi.fn(),
isTrustedUIRenderer: vi.fn(() => true)
}))
vi.mock('electron', () => ({
app: { getPath: vi.fn(() => '/test/user-data') },
ipcMain: { handle: ipcHandle }
}))
vi.mock('./ui', () => ({ isTrustedUIRenderer }))
import {
registerTerminalRenderDesyncEvidenceHandler,
writeTerminalRenderDesyncEvidence
} from './terminal-render-desync-evidence'
const tempDirectories: string[] = []
afterEach(async () => {
await Promise.all(tempDirectories.splice(0).map((dir) => rm(dir, { recursive: true })))
})
describe('writeTerminalRenderDesyncEvidence', () => {
it('rejects writes from renderers outside the trusted UI boundary', async () => {
isTrustedUIRenderer.mockReturnValue(false)
registerTerminalRenderDesyncEvidenceHandler()
const handler = ipcHandle.mock.calls.at(-1)?.[1]
expect(() =>
handler(
{ sender: { id: 99 } },
{ captureId: 'capture-1', phase: 'corrupt', pngDataUrl: 'data:image/png;base64,eA==' }
)
).toThrow('Unauthorized render-desync evidence sender')
})
it('writes private PNG and metadata files under app-owned user data', async () => {
const userData = await mkdtemp(path.join(os.tmpdir(), 'orca-render-desync-'))
tempDirectories.push(userData)
const result = await writeTerminalRenderDesyncEvidence(userData, {
captureId: 'capture-1',
phase: 'corrupt',
pngDataUrl: `data:image/png;base64,${Buffer.from('png-bytes').toString('base64')}`,
metadata: { bufferText: 'private terminal text' }
})
expect(await readFile(result.pngPath, 'utf8')).toBe('png-bytes')
expect(JSON.parse(await readFile(result.metadataPath!, 'utf8'))).toEqual({
bufferText: 'private terminal text'
})
if (process.platform !== 'win32') {
expect((await stat(result.directory)).mode & 0o777).toBe(0o700)
expect((await stat(result.pngPath)).mode & 0o777).toBe(0o600)
}
})
it('rejects path traversal and non-PNG payloads', async () => {
const userData = await mkdtemp(path.join(os.tmpdir(), 'orca-render-desync-'))
tempDirectories.push(userData)
await expect(
writeTerminalRenderDesyncEvidence(userData, {
captureId: '../outside',
phase: 'corrupt',
pngDataUrl: 'data:image/png;base64,eA=='
})
).rejects.toThrow('Invalid render-desync capture id')
await expect(
writeTerminalRenderDesyncEvidence(userData, {
captureId: 'capture-2',
phase: 'corrupt',
pngDataUrl: 'data:text/plain;base64,eA=='
})
).rejects.toThrow('Invalid render-desync PNG payload')
})
it('rejects a phase outside the IPC filename allowlist', async () => {
const userData = await mkdtemp(path.join(os.tmpdir(), 'orca-render-desync-'))
tempDirectories.push(userData)
await expect(
writeTerminalRenderDesyncEvidence(userData, {
captureId: 'capture-1',
phase: '../escaped' as 'corrupt',
pngDataUrl: 'data:image/png;base64,eA=='
})
).rejects.toThrow('Invalid render-desync evidence phase')
})
it('retains only the newest four capture directories', async () => {
const userData = await mkdtemp(path.join(os.tmpdir(), 'orca-render-desync-'))
tempDirectories.push(userData)
for (let capture = 1; capture <= 6; capture++) {
await writeTerminalRenderDesyncEvidence(userData, {
captureId: `capture-${capture}`,
phase: 'corrupt',
pngDataUrl: 'data:image/png;base64,eA=='
})
}
const captures = await readdir(path.join(userData, 'terminal-render-desync-evidence'))
expect(captures.sort()).toEqual(['capture-3', 'capture-4', 'capture-5', 'capture-6'])
})
it('rejects metadata that exceeds its storage budget', async () => {
const userData = await mkdtemp(path.join(os.tmpdir(), 'orca-render-desync-'))
tempDirectories.push(userData)
await expect(
writeTerminalRenderDesyncEvidence(userData, {
captureId: 'capture-large-metadata',
phase: 'corrupt',
pngDataUrl: 'data:image/png;base64,eA==',
metadata: { bufferText: 'x'.repeat(1024 * 1024) }
})
).rejects.toThrow('metadata exceeds the storage budget')
})
})