codeburn/tests/sqlite-tcc-preflight.test.ts
Resham Joshi e1e27de2db
Some checks are pending
macOS Menubar CI / test (push) Waiting to run
CI / semgrep (push) Waiting to run
Tests / test (22) (push) Waiting to run
Tests / test (22.13.0) (push) Waiting to run
Tests / test (24) (push) Waiting to run
Tests / test (26) (push) Waiting to run
Tests / test-platforms (macos-latest) (push) Waiting to run
Tests / test-platforms (windows-latest) (push) Waiting to run
Tests / desktop (push) Waiting to run
fix: stop a Full Disk Access blocked Warp read from freezing serve, and harden the Grok Bot quota reader (#1487)
The Warp Full Disk Access probe ran synchronously on the serve request thread, so a denial froze the whole serve for about six seconds every sixty seconds; the recurring re-probe now returns the last known verdict instantly and refreshes off the request path. A probe child that cannot start on a Group Container path now fails closed, skipping Warp with the grant-access notice, instead of opening the file and re-wedging. The desktop Grok Bot quota reader opened Cursor's database with no busy timeout, so a Cursor write-lock could hang it; it now uses the same busy timeout the CLI uses and waits out the lock. The FIFO-based preflight test is skipped on Windows, where named pipes are not available.
2026-09-18 15:23:22 -07:00

77 lines
3.4 KiB
TypeScript

import { execFileSync } from 'node:child_process'
import { mkdtempSync, writeFileSync } from 'node:fs'
import { homedir, tmpdir } from 'node:os'
import { join } from 'node:path'
import { describe, expect, it, vi } from 'vitest'
import { assertDatabaseReadable, isBlockedDatabaseError, probeDatabaseBlocked } from '../src/sqlite.js'
// A real open() on a Full-Disk-Access-protected path never returns, and no test
// can reproduce that; a child that just sleeps wedges the preflight the same way.
const SLEEPS_FOREVER = 'setTimeout(() => {}, 1e9)'
const groupContainerPath = (name: string) =>
join(homedir(), 'Library', 'Group Containers', '2BBY89MBSN.dev.warp.test', name)
const normalDir = () => mkdtempSync(join(tmpdir(), 'codeburn-tcc-'))
describe('Group Container preflight', () => {
// A readable file exits 0 whatever directory it lives in, so its verdict does
// not depend on the Group Container prefix; the real protected dir cannot be
// written to in a test, so a normal readable file stands in for both.
it('passes a readable file', () => {
const file = join(normalDir(), 'warp.sqlite')
writeFileSync(file, 'x')
expect(probeDatabaseBlocked(file)).toBe(false)
})
it('blocks a hang on a Group Container path', () => {
const started = Date.now()
expect(probeDatabaseBlocked(groupContainerPath('hang.sqlite'), SLEEPS_FOREVER)).toBe(true)
expect(Date.now() - started).toBeLessThan(10_000)
})
// mkfifo has no Windows equivalent, so this hang can only be reproduced on POSIX.
it.skipIf(process.platform === 'win32')('blocks a hanging open (FIFO) on a normal path', () => {
const fifo = join(normalDir(), 'warp.fifo')
execFileSync('mkfifo', [fifo])
const started = Date.now()
// The default probe opens argv[1] for read; a FIFO with no writer blocks it
// exactly like a TCC-wedged open, and the timeout kill classifies as blocked.
expect(probeDatabaseBlocked(fifo)).toBe(true)
expect(Date.now() - started).toBeLessThan(10_000)
})
it('fails closed on a Group Container path the probe could not run for', () => {
const missingNode = join(tmpdir(), 'codeburn-no-such-node')
expect(probeDatabaseBlocked(groupContainerPath('spawn-fail.sqlite'), SLEEPS_FOREVER, missingNode)).toBe(true)
})
it('does not blame a normal-path file when the probe itself cannot run', () => {
const missingNode = join(tmpdir(), 'codeburn-no-such-node')
expect(probeDatabaseBlocked(join(normalDir(), 'spawn-fail.sqlite'), SLEEPS_FOREVER, missingNode)).toBe(false)
})
it('warns once per run and leaves the error marked as blocked', () => {
const stderr = vi.spyOn(process.stderr, 'write').mockImplementation(() => true)
try {
let thrown: unknown
for (const name of ['first.sqlite', 'second.sqlite']) {
try {
assertDatabaseReadable(groupContainerPath(name), SLEEPS_FOREVER)
throw new Error('expected the preflight to throw')
} catch (err) {
thrown = err
}
}
expect(isBlockedDatabaseError(thrown)).toBe(true)
const warnings = stderr.mock.calls.filter(([msg]) => String(msg).includes('Full Disk Access'))
expect(warnings).toHaveLength(1)
expect(warnings[0]![0]).toBe(
"codeburn: skipped warp: macOS blocked access to Warp's database; grant Full Disk Access to the app " +
'running codeburn (System Settings > Privacy & Security) and retry\n',
)
} finally {
stderr.mockRestore()
}
})
})