fix(sessions): tighten gateway model-run key predicate

The model-run prune predicate fell back to testing the raw sessionKey
when parseAgentSessionKey returned null, so unscoped keys like
`explicit:model-run-<uuid>` and shapes with empty agent ids were
eligible for the new default 24h cleanup. Restrict matching to keys
that successfully parse as agent-scoped with a non-empty agent id,
and add negative tests covering unscoped, empty-agent, extra-segment,
and whitespace-padded keys.

Refs #88632 (review feedback before merge).
This commit is contained in:
wanglu241
2026-06-13 01:29:02 +08:00
committed by Josh Lehman
parent 33d0019eaf
commit 2ddedad1d0
2 changed files with 63 additions and 1 deletions
+11 -1
View File
@@ -190,8 +190,18 @@ export function shouldRunSessionEntryMaintenance(params: {
}
export function isGatewayModelRunSessionKey(sessionKey: string): boolean {
if (
!/^agent:[^:]+:explicit:model-run-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
sessionKey,
)
) {
return false;
}
const parsed = parseAgentSessionKey(sessionKey);
const rest = normalizeLowercaseStringOrEmpty(parsed?.rest ?? sessionKey);
if (!parsed || !parsed.agentId.trim()) {
return false;
}
const rest = normalizeLowercaseStringOrEmpty(parsed.rest);
return /^explicit:model-run-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(
rest,
);
+52
View File
@@ -278,6 +278,58 @@ describe("pruneStaleModelRunEntries", () => {
),
).toBe(false);
});
it("rejects non-canonical session keys that do not parse as agent-scoped", () => {
// Unscoped: missing `agent:<id>:` prefix — parseAgentSessionKey returns null.
expect(
isGatewayModelRunSessionKey("explicit:model-run-123e4567-e89b-12d3-a456-426614174000"),
).toBe(false);
// Empty agent id segment: not a canonical `agent:<id>:` scoped key.
expect(
isGatewayModelRunSessionKey("agent::explicit:model-run-123e4567-e89b-12d3-a456-426614174000"),
).toBe(false);
// Extra colon segment between agent id and `explicit:` — rest starts
// with `extra:` and fails the predicate's regex.
expect(
isGatewayModelRunSessionKey(
"agent:main:extra:explicit:model-run-123e4567-e89b-12d3-a456-426614174000",
),
).toBe(false);
// Whitespace-padded keys are non-canonical even though parseAgentSessionKey
// trims before normalizing; the predicate intentionally checks the original
// key shape before accepting a model-run key.
expect(
isGatewayModelRunSessionKey(
" agent:main:explicit:model-run-123e4567-e89b-12d3-a456-426614174000",
),
).toBe(false);
expect(
isGatewayModelRunSessionKey(
"agent:main:explicit:model-run-123e4567-e89b-12d3-a456-426614174000 ",
),
).toBe(false);
});
it("matches canonical keys whose agent id begins with model-run-", () => {
// Guards against an over-tight fix that confuses the agent id segment
// with the `explicit:model-run-<uuid>` rest segment.
expect(
isGatewayModelRunSessionKey(
"agent:model-run-foo:explicit:model-run-123e4567-e89b-12d3-a456-426614174000",
),
).toBe(true);
});
it("preserves case-insensitive matching for canonical keys", () => {
// normalizeLowercaseStringOrEmpty + parseAgentSessionKey's normalization
// lower-case everything outside opaque peer IDs, so a mixed-case
// canonical key still matches.
expect(
isGatewayModelRunSessionKey(
"agent:Main:Explicit:Model-Run-123E4567-E89B-12D3-A456-426614174000",
),
).toBe(true);
});
});
describe("capEntryCount", () => {