From 62ca38859a69e4de2a882be3e159591b59198033 Mon Sep 17 00:00:00 2001 From: Sylvester Kaczmarek <16242628+sylvesterkaczmarek@users.noreply.github.com> Date: Tue, 18 Aug 2026 10:38:57 +0100 Subject: [PATCH 1/2] fix(logs): stop saved activity at scan completion --- sdk/typescript/src/scan-logs.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sdk/typescript/src/scan-logs.ts b/sdk/typescript/src/scan-logs.ts index 36ca1164f..e65f24e4a 100644 --- a/sdk/typescript/src/scan-logs.ts +++ b/sdk/typescript/src/scan-logs.ts @@ -75,6 +75,13 @@ export async function readScanLogs(options: ScanLogOptions) { } } } + const parsedCompletedAt = + options.completedAt === undefined || options.completedAt === null + ? Number.NaN + : Date.parse(options.completedAt); + const completedAt = Number.isFinite(parsedCompletedAt) + ? parsedCompletedAt + : null; const events: Record[] = []; for (const session of sessions) { let replaying = false; @@ -96,6 +103,10 @@ export async function readScanLogs(options: ScanLogOptions) { } replaying = false; } + if (completedAt !== null && typeof event["timestamp"] === "string") { + const timestamp = Date.parse(event["timestamp"]); + if (Number.isFinite(timestamp) && timestamp > completedAt) continue; + } events.push({ threadId: session.threadId, event }); } } From 60b5de14c178121f3c0bad46ab9dd4a41b297367 Mon Sep 17 00:00:00 2001 From: Sylvester Kaczmarek <16242628+sylvesterkaczmarek@users.noreply.github.com> Date: Tue, 18 Aug 2026 10:39:14 +0100 Subject: [PATCH 2/2] test(logs): enforce saved completion boundary --- .../tests-ts/scan-logs-completion.test.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 sdk/typescript/tests-ts/scan-logs-completion.test.ts diff --git a/sdk/typescript/tests-ts/scan-logs-completion.test.ts b/sdk/typescript/tests-ts/scan-logs-completion.test.ts new file mode 100644 index 000000000..bc3b90375 --- /dev/null +++ b/sdk/typescript/tests-ts/scan-logs-completion.test.ts @@ -0,0 +1,61 @@ +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "bun:test"; +import { readScanLogs } from "../src/scan-logs.js"; + +test("excludes same-thread events emitted after saved scan completion", async () => { + const home = await mkdtemp(join(tmpdir(), "codex-security-scan-log-boundary-")); + const directory = join(home, "sessions", "2026", "08", "18"); + const path = join(directory, "rollout-parent.jsonl"); + await mkdir(directory, { recursive: true }); + + try { + await writeFile( + path, + [ + { + type: "session_meta", + payload: { + id: "parent", + timestamp: "2026-08-18T08:00:00.000Z", + }, + }, + { + type: "response_item", + timestamp: "2026-08-18T08:01:00.000Z", + payload: { type: "message", role: "assistant", content: "SCAN EVENT" }, + }, + { + type: "response_item", + timestamp: "2026-08-18T08:03:00.000Z", + payload: { + type: "message", + role: "assistant", + content: "POST SCAN EVENT", + }, + }, + { + type: "response_item", + payload: { type: "message", role: "assistant", content: "LEGACY EVENT" }, + }, + ] + .map((event) => JSON.stringify(event)) + .join("\n"), + ); + + const result = await readScanLogs({ + scanId: "scan-1", + threadId: "parent", + codexHome: home, + completedAt: "2026-08-18T08:02:00.000Z", + }); + const serialized = JSON.stringify(result); + + expect(serialized).toContain("SCAN EVENT"); + expect(serialized).toContain("LEGACY EVENT"); + expect(serialized).not.toContain("POST SCAN EVENT"); + } finally { + await rm(home, { recursive: true, force: true }); + } +});