fix: pricing accuracy, stream leak, CSV injection hardening

- Remove bidirectional fuzzy match in getModelCosts that could return
  wrong pricing when a short canonical name prefix-matched a longer key
- Use explicit undefined check in parseLiteLLMEntry so free models with
  zero cost are not silently dropped from the LiteLLM pricing database
- Destroy read stream in finally block of readSessionLines to prevent
  file descriptor leaks when the generator is abandoned early
- Extend CSV injection escaping to cover tab and carriage-return prefixes
- Add optional chaining fallback for empty periods in exportCsv/exportJson
- Add regression tests for all fixes (models, export, fs-utils)
This commit is contained in:
iamtoruk 2026-04-20 14:49:32 -07:00 committed by AgentSeal
parent b61e7cd32a
commit a4d261a536
6 changed files with 117 additions and 6 deletions

View file

@ -1,5 +1,5 @@
import { describe, it, expect, beforeEach, afterEach } from 'vitest'
import { mkdtemp, readFile, rm } from 'fs/promises'
import { mkdtemp, readFile, readdir, rm } from 'fs/promises'
import { join } from 'path'
import { tmpdir } from 'os'
@ -134,4 +134,26 @@ describe('exportCsv', () => {
expect(content).toContain("'+danger-model")
expect(content).toContain("'@malicious")
})
it('escapes tab and carriage-return prefixes in CSV cells', async () => {
const periods: PeriodExport[] = [
{
label: '30 Days',
projects: [makeProject('\tcmd'), makeProject('\rcmd')],
},
]
const outputPath = join(tmpDir, 'tab-cr.csv')
const folder = await exportCsv(periods, outputPath)
const projects = await readFile(join(folder, 'projects.csv'), 'utf-8')
expect(projects).toContain("'\tcmd")
expect(projects).toContain("'\rcmd")
})
it('does not crash when periods array is empty', async () => {
const outputPath = join(tmpDir, 'empty.csv')
const folder = await exportCsv([], outputPath)
const entries = await readdir(folder)
expect(entries.length).toBeGreaterThanOrEqual(0)
})
})