From 6e0b6164ea676aa9dd4700f1e156da285ff13ce5 Mon Sep 17 00:00:00 2001 From: Brennan Benson <79079362+brennanb2025@users.noreply.github.com> Date: Tue, 21 Jul 2026 20:27:53 -0700 Subject: [PATCH] fix(rate-limits): reject leading-zero stamp values before arithmetic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All-digits validation still admitted values like 008, which are invalid octal inside $(( )) — and dash treats that expansion error as fatal, so the script died before rewriting the stamp and the pane's live usage feed stayed dark until the file was deleted. Allow-list canonical decimals (same pattern as the duration parse) on both the stamp and the computed clock so malformed values fail open to posting. Verified under dash: the old digits-only check aborts at the arithmetic (Illegal number: 008); the allow-list survives and posts. --- src/main/claude/statusline-script.test.ts | 20 ++++++++++++++++++-- src/main/claude/statusline-script.ts | 7 +++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/claude/statusline-script.test.ts b/src/main/claude/statusline-script.test.ts index 690d206044a..09fc0854ef5 100644 --- a/src/main/claude/statusline-script.test.ts +++ b/src/main/claude/statusline-script.test.ts @@ -148,8 +148,14 @@ describe('statusline curl throttle (posix)', () => { expect(durationIndex).toBeLessThan(intervalIndex) expect(intervalIndex).toBeLessThan(curlIndex) // Fail-open shape: non-numeric date output or stamp content must never suppress the post. - expect(script).toContain('case "$orca_statusline_now" in \'\'|*[!0-9]*) orca_statusline_now=') - expect(script).toContain('case "$orca_statusline_last" in \'\'|*[!0-9]*) orca_statusline_last=') + // Why: the allow-list (not a mere digits check) matters — leading-zero values like 008 are + // invalid octal inside $(( )) and abort the whole script under dash, wedging the stamp. + expect(script).toContain( + 'case "$orca_statusline_now" in 0|[1-9]|[1-9][0-9]*) ;; *) orca_statusline_now=' + ) + expect(script).toContain( + 'case "$orca_statusline_last" in 0|[1-9]|[1-9][0-9]*) ;; *) orca_statusline_last=' + ) }) }) @@ -262,6 +268,16 @@ describe.skipIf(process.platform === 'win32')('statusline curl throttle (posix b expect(readFileSync(stampPathFor(dir), 'utf8')).toMatch(/^[0-9]+$/) }) + it('fails open and repairs a leading-zero stamp instead of dying in arithmetic', async () => { + const { scriptPath, dir, curlLog } = makeHarness() + // Why: 008 is all-digits but invalid octal inside $(( )) — under dash the old digits-only + // check made the script abort before rewriting the stamp, wedging this pane's feed dark. + writeFileSync(stampPathFor(dir), '008') + await runScript(scriptPath, dir, rateLimitPayload(1_000)) + expect(lineCount(curlLog)).toBe(1) + expect(readFileSync(stampPathFor(dir), 'utf8')).toBe('1') + }) + it('uses the clock fallback when the payload omits session duration', async () => { const { scriptPath, dir, curlLog, dateLog } = makeHarness() const payload = '{"rate_limits":{"five_hour":{"used_percentage":12}}}' diff --git a/src/main/claude/statusline-script.ts b/src/main/claude/statusline-script.ts index 341b93330f9..f1ff016afd3 100644 --- a/src/main/claude/statusline-script.ts +++ b/src/main/claude/statusline-script.ts @@ -126,11 +126,14 @@ export function getManagedStatusLineScript(target: 'local' | 'posix' = 'local'): 'if [ -z "$orca_statusline_now" ]; then', ' orca_statusline_now=$(date +%s 2>/dev/null) || orca_statusline_now=', 'fi', - 'case "$orca_statusline_now" in \'\'|*[!0-9]*) orca_statusline_now= ;; esac', + // Why: leading zeros read as octal inside $(( )), and a bad constant (008) is FATAL in dash — + // the script would die before rewriting the stamp, wedging the pane dark. Allow-list canonical + // decimals so any malformed value fails open to posting instead. + 'case "$orca_statusline_now" in 0|[1-9]|[1-9][0-9]*) ;; *) orca_statusline_now= ;; esac', 'if [ -n "$orca_statusline_now" ] && [ -f "$orca_statusline_stamp" ]; then', ' orca_statusline_last=', ' IFS= read -r orca_statusline_last <"$orca_statusline_stamp" 2>/dev/null || :', - ' case "$orca_statusline_last" in \'\'|*[!0-9]*) orca_statusline_last= ;; esac', + ' case "$orca_statusline_last" in 0|[1-9]|[1-9][0-9]*) ;; *) orca_statusline_last= ;; esac', ' if [ "${#orca_statusline_last}" -gt 15 ]; then orca_statusline_last=; fi', ' if [ -n "$orca_statusline_last" ]; then', ' orca_statusline_elapsed=$((orca_statusline_now - orca_statusline_last))',