fix: harden session transcript path resolution

This commit is contained in:
Peter Steinberger
2026-02-13 01:27:33 +01:00
parent 3eb6a31b6f
commit 4199f9889f
13 changed files with 322 additions and 66 deletions

View File

@@ -1,4 +1,5 @@
import fs from "node:fs";
import path from "node:path";
import type { SessionEntry, SessionSystemPromptReport } from "../../config/sessions/types.js";
import type {
CostUsageSummary,
@@ -291,7 +292,7 @@ export const usageHandlers: GatewayRequestHandlers = {
const specificKey = typeof p.key === "string" ? p.key.trim() : null;
// Load session store for named sessions
const { store } = loadCombinedSessionStoreForGateway(config);
const { storePath, store } = loadCombinedSessionStoreForGateway(config);
const now = Date.now();
// Merge discovered sessions with store entries
@@ -331,9 +332,21 @@ export const usageHandlers: GatewayRequestHandlers = {
const sessionId = storeEntry?.sessionId ?? keyRest;
// Resolve the session file path
const sessionFile = resolveSessionFilePath(sessionId, storeEntry, {
agentId: agentIdFromKey,
});
let sessionFile: string;
try {
const pathOpts =
storePath && storePath !== "(multiple)"
? { sessionsDir: path.dirname(storePath) }
: { agentId: agentIdFromKey };
sessionFile = resolveSessionFilePath(sessionId, storeEntry, pathOpts);
} catch {
respond(
false,
undefined,
errorShape(ErrorCodes.INVALID_REQUEST, `Invalid session reference: ${specificKey}`),
);
return;
}
try {
const stats = fs.statSync(sessionFile);
@@ -756,15 +769,25 @@ export const usageHandlers: GatewayRequestHandlers = {
}
const config = loadConfig();
const { entry } = loadSessionEntry(key);
const { entry, storePath } = loadSessionEntry(key);
// For discovered sessions (not in store), try using key as sessionId directly
const parsed = parseAgentSessionKey(key);
const agentId = parsed?.agentId;
const rawSessionId = parsed?.rest ?? key;
const sessionId = entry?.sessionId ?? rawSessionId;
const sessionFile =
entry?.sessionFile ?? resolveSessionFilePath(rawSessionId, entry, { agentId });
let sessionFile: string;
try {
const pathOpts = storePath ? { sessionsDir: path.dirname(storePath) } : { agentId };
sessionFile = resolveSessionFilePath(sessionId, entry, pathOpts);
} catch {
respond(
false,
undefined,
errorShape(ErrorCodes.INVALID_REQUEST, `Invalid session key: ${key}`),
);
return;
}
const timeseries = await loadSessionUsageTimeSeries({
sessionId,
@@ -798,15 +821,25 @@ export const usageHandlers: GatewayRequestHandlers = {
: 200;
const config = loadConfig();
const { entry } = loadSessionEntry(key);
const { entry, storePath } = loadSessionEntry(key);
// For discovered sessions (not in store), try using key as sessionId directly
const parsed = parseAgentSessionKey(key);
const agentId = parsed?.agentId;
const rawSessionId = parsed?.rest ?? key;
const sessionId = entry?.sessionId ?? rawSessionId;
const sessionFile =
entry?.sessionFile ?? resolveSessionFilePath(rawSessionId, entry, { agentId });
let sessionFile: string;
try {
const pathOpts = storePath ? { sessionsDir: path.dirname(storePath) } : { agentId };
sessionFile = resolveSessionFilePath(sessionId, entry, pathOpts);
} catch {
respond(
false,
undefined,
errorShape(ErrorCodes.INVALID_REQUEST, `Invalid session key: ${key}`),
);
return;
}
const { loadSessionLogs } = await import("../../infra/session-cost-usage.js");
const logs = await loadSessionLogs({