fix(rate-limits): reject leading-zero stamp values before arithmetic

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.
This commit is contained in:
Brennan Benson
2026-07-21 20:27:53 -07:00
parent 1f7107ae24
commit 6e0b6164ea
2 changed files with 23 additions and 4 deletions
+18 -2
View File
@@ -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}}}'
+5 -2
View File
@@ -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))',