diff --git a/integration-tests/interactive/cron-interactive.test.ts b/integration-tests/interactive/cron-interactive.test.ts index 122a732ad62..9f9519dce45 100644 --- a/integration-tests/interactive/cron-interactive.test.ts +++ b/integration-tests/interactive/cron-interactive.test.ts @@ -91,15 +91,14 @@ function makeEnv(): NodeJS.ProcessEnv { ); await session.idle(5000); - await session.send('Reply with exactly USERPRIORITY77 nothing else'); + const userPriorityMarker = 'USERPRIORITY77'; + await session.send(`Reply with exactly ${userPriorityMarker} nothing else`); await session.waitForScreen( - (scr) => scr.includes('USERPRIORITY77'), + (scr) => + scr.indexOf(userPriorityMarker) !== scr.lastIndexOf(userPriorityMarker), 'model response containing USERPRIORITY77', ); - - const screen = await session.screen(); - expect(screen).toContain('Type your message'); }); it( diff --git a/packages/core/src/utils/shellAstParser.test.ts b/packages/core/src/utils/shellAstParser.test.ts index 8f32755b341..d349cd003a3 100644 --- a/packages/core/src/utils/shellAstParser.test.ts +++ b/packages/core/src/utils/shellAstParser.test.ts @@ -510,6 +510,8 @@ describe('isShellCommandReadOnlyAST', () => { // ========================================================================= describe('classifyShellCommandSafety', () => { + const maxClassificationCpuMs = 1000; + it.each([ 'ls -la', 'git status --short', @@ -908,20 +910,23 @@ describe('classifyShellCommandSafety', () => { expect(await classifyShellCommandSafety(command)).toBe('unknown'); }); - it('classifies deeply nested redirected substitutions without repeated traversal', async () => { + it('classifies deeply nested redirected substitutions within the CPU budget', async () => { const commands = ['git status', 'git status']; for (let depth = 0; depth < 20; depth++) { commands[0] = `echo $(${commands[0]}) < /dev/null`; commands[1] = `< <(${commands[1]}) cat`; } - const startedAt = performance.now(); + const startedCpuUsage = process.cpuUsage(); await expect( Promise.all(commands.map(classifyShellCommandSafety)), ).resolves.toEqual(['unknown', 'unknown']); - expect(performance.now() - startedAt).toBeLessThan(1000); + const cpuUsage = process.cpuUsage(startedCpuUsage); + expect((cpuUsage.user + cpuUsage.system) / 1000).toBeLessThan( + maxClassificationCpuMs, + ); }); - it('classifies adversarial rule inputs in bounded time', async () => { + it('classifies adversarial rule inputs within the CPU budget', async () => { const backslashes = '\\'.repeat(10_000); const repeatedSed = 'p;'.repeat(10_000); const repeatedPrint = 'print value; '.repeat(10_000); @@ -935,7 +940,7 @@ describe('classifyShellCommandSafety', () => { `find . ${repeatedFindExec}`, `git status ${unmatchedBraces}`, ]; - const startedAt = performance.now(); + const startedCpuUsage = process.cpuUsage(); await expect( Promise.all(commands.map(classifyShellCommandSafety)), ).resolves.toEqual([ @@ -946,7 +951,10 @@ describe('classifyShellCommandSafety', () => { 'unknown', 'read-only', ]); - expect(performance.now() - startedAt).toBeLessThan(1000); + const cpuUsage = process.cpuUsage(startedCpuUsage); + expect((cpuUsage.user + cpuUsage.system) / 1000).toBeLessThan( + maxClassificationCpuMs, + ); }); });