From 3227f03643b0a109d0b9aa0bd9520273d43c02f3 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 6 Sep 2026 08:21:40 -0400 Subject: [PATCH 1/2] fix: decode quoted benchmark shell commands --- scripts/agent-benchmark/driver.mjs | 7 +------ scripts/agent-benchmark/run-guards.mjs | 6 ++++-- scripts/agent-benchmark/run-guards.test.mjs | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/scripts/agent-benchmark/driver.mjs b/scripts/agent-benchmark/driver.mjs index 6e825b34..78a80356 100644 --- a/scripts/agent-benchmark/driver.mjs +++ b/scripts/agent-benchmark/driver.mjs @@ -45,6 +45,7 @@ import { benchmarkCcache, ccacheMeasurements, runnerToolOutput, + topLevelShellCommand, } from './run-guards.mjs'; const launchCrashVariant = 'launch-crash'; @@ -1628,12 +1629,6 @@ function commandEvidence(meta, eventsPath, runDir) { return { commands, activities, completedEvents, invalidReasons }; } -function topLevelShellCommand(command) { - const trimmed = String(command ?? '').trim(); - const match = trimmed.match(/^\/bin\/(?:zsh|bash|sh) -lc (["'])([\s\S]*)\1$/); - return (match?.[2] ?? trimmed).trim(); -} - function agentDeviceOpenCommand(meta, appAlive) { const prefix = agentDeviceCommand(meta, 'open com.appandflow.trailhead --foreground'); if (!meta.deviceTargetingRequired) return prefix; diff --git a/scripts/agent-benchmark/run-guards.mjs b/scripts/agent-benchmark/run-guards.mjs index 9a054403..4661ac31 100644 --- a/scripts/agent-benchmark/run-guards.mjs +++ b/scripts/agent-benchmark/run-guards.mjs @@ -60,10 +60,12 @@ export function benchmarkTarget(config, selection) { return { key, machine: config.machine, ...value }; } -function topLevelShellCommand(command) { +export function topLevelShellCommand(command) { const trimmed = String(command ?? '').trim(); const match = trimmed.match(/^\/bin\/(?:zsh|bash|sh) -lc (["'])([\s\S]*)\1$/); - return (match?.[2] ?? trimmed).trim(); + if (!match) return trimmed; + const source = match[1] === '"' ? match[2].replace(/\\(["\\$`])/g, '$1').replace(/\\\n/g, '') : match[2]; + return source.trim(); } export function shellCommandSegments(command) { diff --git a/scripts/agent-benchmark/run-guards.test.mjs b/scripts/agent-benchmark/run-guards.test.mjs index ec6854f3..421a6a24 100644 --- a/scripts/agent-benchmark/run-guards.test.mjs +++ b/scripts/agent-benchmark/run-guards.test.mjs @@ -6,6 +6,7 @@ import { benchmarkTiming, parseBenchmarkTargets, shellCommandSegments, + topLevelShellCommand, stimShellProvenanceInvalidReasons, benchmarkCcache, assertAndroidDoctorClean, @@ -211,6 +212,22 @@ describe('benchmark run guards', () => { 'echo "a && b"', 'stim guide agent', ]); + const search = 'rg -n "run:android|agent-device|emulator" .'; + const body = `${search} | sed -n '1,180p'`; + const wrapped = `/bin/zsh -lc ${JSON.stringify(body)}`; + expect(shellCommandSegments(wrapped)).toEqual([search, "sed -n '1,180p'"]); + expect(agentDeviceIsolationInvalidReasons([{ command: wrapped }], 'env expected agent-device ')).toEqual([]); + }); + + it('decodes one shell quoting layer while preserving proof command boundaries and literal backslashes', () => { + const proof = + 'env AGENT_DEVICE_STATE_DIR=/tmp/bench AGENT_DEVICE_SESSION=run agent-device wait text "Offline maps"'; + expect(topLevelShellCommand(`/bin/zsh -lc ${JSON.stringify(proof)}`)).toBe(proof); + expect(topLevelShellCommand(`/bin/zsh -lc ${JSON.stringify(`${proof}; agent-device close`)}`)).not.toBe(proof); + const literal = "rg '\\d+\\s' file"; + expect(topLevelShellCommand(`/bin/zsh -lc ${JSON.stringify(literal)}`)).toBe(literal); + expect(topLevelShellCommand('/bin/zsh -lc "echo \\$VALUE"')).toBe('echo $VALUE'); + expect(topLevelShellCommand('/bin/zsh -lc "echo \\q"')).toBe('echo \\q'); }); it('rejects setup recovery inside the timer', () => { From 5830b979f75edbbc88c2d04e74da000c5538b1e2 Mon Sep 17 00:00:00 2001 From: Janic Duplessis Date: Sun, 6 Sep 2026 08:29:44 -0400 Subject: [PATCH 2/2] fix: decode shell escapes in one pass --- scripts/agent-benchmark/run-guards.mjs | 3 ++- scripts/agent-benchmark/run-guards.test.mjs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/agent-benchmark/run-guards.mjs b/scripts/agent-benchmark/run-guards.mjs index 4661ac31..c87b5c4a 100644 --- a/scripts/agent-benchmark/run-guards.mjs +++ b/scripts/agent-benchmark/run-guards.mjs @@ -64,7 +64,8 @@ export function topLevelShellCommand(command) { const trimmed = String(command ?? '').trim(); const match = trimmed.match(/^\/bin\/(?:zsh|bash|sh) -lc (["'])([\s\S]*)\1$/); if (!match) return trimmed; - const source = match[1] === '"' ? match[2].replace(/\\(["\\$`])/g, '$1').replace(/\\\n/g, '') : match[2]; + const source = + match[1] === '"' ? match[2].replace(/\\(["\\$`\n])/g, (_, char) => (char === '\n' ? '' : char)) : match[2]; return source.trim(); } diff --git a/scripts/agent-benchmark/run-guards.test.mjs b/scripts/agent-benchmark/run-guards.test.mjs index 421a6a24..ca8c192a 100644 --- a/scripts/agent-benchmark/run-guards.test.mjs +++ b/scripts/agent-benchmark/run-guards.test.mjs @@ -228,6 +228,9 @@ describe('benchmark run guards', () => { expect(topLevelShellCommand(`/bin/zsh -lc ${JSON.stringify(literal)}`)).toBe(literal); expect(topLevelShellCommand('/bin/zsh -lc "echo \\$VALUE"')).toBe('echo $VALUE'); expect(topLevelShellCommand('/bin/zsh -lc "echo \\q"')).toBe('echo \\q'); + const quotedNewline = "printf '%s' 'before" + '\\'.repeat(2) + "\nafter'"; + expect(topLevelShellCommand(`/bin/zsh -lc "${quotedNewline}"`)).toBe("printf '%s' 'before\\\nafter'"); + expect(topLevelShellCommand('/bin/zsh -lc "echo before\\\nafter"')).toBe('echo beforeafter'); }); it('rejects setup recovery inside the timer', () => {