mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-05-22 03:00:55 +00:00
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:
parent
b61e7cd32a
commit
a4d261a536
6 changed files with 117 additions and 6 deletions
|
|
@ -6,7 +6,7 @@ import { getCurrency, convertCost } from './currency.js'
|
|||
import { dateKey } from './day-aggregator.js'
|
||||
|
||||
function escCsv(s: string): string {
|
||||
const sanitized = /^[=+\-@]/.test(s) ? `'${s}` : s
|
||||
const sanitized = /^[\t\r=+\-@]/.test(s) ? `'${s}` : s
|
||||
if (sanitized.includes(',') || sanitized.includes('"') || sanitized.includes('\n')) {
|
||||
return `"${sanitized.replace(/"/g, '""')}"`
|
||||
}
|
||||
|
|
@ -283,7 +283,7 @@ async function clearCodeburnExportFolder(path: string): Promise<void> {
|
|||
/// wipe a sensitive file (prior versions did `rm(path, { force: true })` unconditionally).
|
||||
export async function exportCsv(periods: PeriodExport[], outputPath: string): Promise<string> {
|
||||
const thirtyDays = periods.find(p => p.label === '30 Days')
|
||||
const thirtyDayProjects = thirtyDays?.projects ?? periods[periods.length - 1].projects
|
||||
const thirtyDayProjects = thirtyDays?.projects ?? periods[periods.length - 1]?.projects ?? []
|
||||
|
||||
let folder = resolve(outputPath)
|
||||
if (folder.toLowerCase().endsWith('.csv')) {
|
||||
|
|
@ -325,7 +325,7 @@ export async function exportCsv(periods: PeriodExport[], outputPath: string): Pr
|
|||
|
||||
export async function exportJson(periods: PeriodExport[], outputPath: string): Promise<string> {
|
||||
const thirtyDays = periods.find(p => p.label === '30 Days')
|
||||
const thirtyDayProjects = thirtyDays?.projects ?? periods[periods.length - 1].projects
|
||||
const thirtyDayProjects = thirtyDays?.projects ?? periods[periods.length - 1]?.projects ?? []
|
||||
const { code, rate, symbol } = getCurrency()
|
||||
|
||||
const data = {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue