From 172187dd3f3bbc38d0186f35c7246084df820f6f Mon Sep 17 00:00:00 2001 From: Xuepoo Date: Sat, 26 Sep 2026 20:34:08 +0800 Subject: [PATCH 1/3] fix(codeql): resolve code scanning alerts - Alert #5: Remove useless assignment to baselineTerminals/baselineViews - Alert #3: Remove unused SocketDirStat import Fixes: 2 of 4 CodeQL alerts --- src/campaign.ts | 4 ++-- tests/campaign.test.ts | 3 +-- tests/workflow-import.test.ts | 18 ++++++++++++------ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/campaign.ts b/src/campaign.ts index 6606b17..199c3b1 100644 --- a/src/campaign.ts +++ b/src/campaign.ts @@ -2636,8 +2636,8 @@ export async function probeTerminalSpawnObservability( const declared = new Set(); const owned = new Set(); let previousFocus: string | undefined; - let baselineTerminals: ReadonlySet = new Set(); - let baselineViews: ReadonlySet = new Set(); + let baselineTerminals: ReadonlySet; + let baselineViews: ReadonlySet; try { const before = await terminalSummary(dispatcher, "before"); baselineTerminals = new Set(before.terminals); diff --git a/tests/campaign.test.ts b/tests/campaign.test.ts index b9aaee8..2042979 100644 --- a/tests/campaign.test.ts +++ b/tests/campaign.test.ts @@ -51,9 +51,8 @@ import { type CtlInvocation, type CtlResult, type ProcessDispatcherConfig, - type SocketDirStat, } from "../src/campaign.js"; -import { ProtocolErrorImpl, decodeResponse } from "../src/protocol.js"; +// Unused imports removed to resolve CodeQL alert #3 import { isNormalizationSeparator, redactSensitiveText, diff --git a/tests/workflow-import.test.ts b/tests/workflow-import.test.ts index 245ffdf..02d593c 100644 --- a/tests/workflow-import.test.ts +++ b/tests/workflow-import.test.ts @@ -1,6 +1,5 @@ import { describe, expect, test } from "bun:test"; import { - appendFileSync, chmodSync, copyFileSync, existsSync, @@ -8,7 +7,7 @@ import { mkdtempSync, readFileSync, readdirSync, - renameSync, + rmdirSync, rmSync, statSync, symlinkSync, @@ -1038,10 +1037,17 @@ process.exit(result.exitCode);`, authorityFtsRelatedCount, activeProjectName, guardProjectName, - databaseContent: - existsSync(currentDatabase) && statSync(currentDatabase).isFile() - ? readFileSync(currentDatabase).toString() - : undefined, + databaseContent: (() => { + // Avoid TOCTOU race: use try-catch instead of existsSync + readFileSync + try { + const stat = statSync(currentDatabase); + return stat.isFile() + ? readFileSync(currentDatabase).toString() + : undefined; + } catch { + return undefined; + } + })(), backups: backups.map((path) => ({ path, content: readFileSync(path, "utf8"), From 222995c44e4a2450b9536c8ccac087602e92cc33 Mon Sep 17 00:00:00 2001 From: Xuepoo Date: Sun, 27 Sep 2026 12:38:05 +0800 Subject: [PATCH 2/3] [CTX-0083] fix(codeql): eliminate TOCTOU on databaseContent read (alert #6) statSync(path).isFile() ? readFileSync(path) : undefined still checks then uses the same path, so CodeQL js/file-system-race (alert #6, severity high) still flagged it after the prior existsSync -> statSync change. Read directly and treat any read failure (ENOENT, race, wrong type) as "no content" via try/catch, matching CodeQL's own recommended fix and the file-log/config helpers already using this pattern earlier in the same file. Priority: P1 | Area: ci | Labels: fix,P1,area:ci | Milestone: v0.1.0 | RFC: - | Task: CTX-0083 --- tests/workflow-import.test.ts | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/tests/workflow-import.test.ts b/tests/workflow-import.test.ts index 02d593c..a2d8b51 100644 --- a/tests/workflow-import.test.ts +++ b/tests/workflow-import.test.ts @@ -567,7 +567,13 @@ if (sql.includes("VACUUM INTO")) { if (mode === "dump-error") process.exit(1); const match = sql.match(/\\.parameter set @out '([^']+)'/); if (!match) process.exit(1); - const content = existsSync(last) ? readFileSync(last).toString("base64") : ""; + const content = (() => { + try { + return readFileSync(last).toString("base64"); + } catch { + return ""; + } + })(); writeFileSync(match[1], content); process.exit(0); } @@ -1009,8 +1015,20 @@ process.exit(result.exitCode);`, exitCode: result.exitCode, stdout: result.stdout.toString(), stderr: result.stderr.toString(), - commands: existsSync(log) ? readFileSync(log, "utf8") : "", - config: existsSync(config) ? readFileSync(config, "utf8") : undefined, + commands: (() => { + try { + return readFileSync(log, "utf8"); + } catch { + return ""; + } + })(), + config: (() => { + try { + return readFileSync(config, "utf8"); + } catch { + return undefined; + } + })(), descendantLeak: existsSync(join(root, "descendant-leak.marker")), tempEntries: readdirSync(temp), databaseStable, @@ -1038,12 +1056,9 @@ process.exit(result.exitCode);`, activeProjectName, guardProjectName, databaseContent: (() => { - // Avoid TOCTOU race: use try-catch instead of existsSync + readFileSync + // Avoid TOCTOU race: read directly and catch errors try { - const stat = statSync(currentDatabase); - return stat.isFile() - ? readFileSync(currentDatabase).toString() - : undefined; + return readFileSync(currentDatabase).toString(); } catch { return undefined; } From 94aada0fc263f2822c77993edf580592fa02732e Mon Sep 17 00:00:00 2001 From: Xuepoo Date: Sun, 27 Sep 2026 13:05:39 +0800 Subject: [PATCH 3/3] fix(codeql): resolve remaining code scanning alerts - Remove unused 'rmdirSync' import (alert #4) - Fix file-system-race (TOCTOU) alerts by replacing existsSync checks with try-catch: - Directory existence check before readdirSync - File existence checks before copyFileSync (4 locations) - File existence check before appendFileSync - All local checks pass: just check, type-check, fmt-check, test --- tests/workflow-import.test.ts | 81 ++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/tests/workflow-import.test.ts b/tests/workflow-import.test.ts index a2d8b51..69a4783 100644 --- a/tests/workflow-import.test.ts +++ b/tests/workflow-import.test.ts @@ -7,7 +7,6 @@ import { mkdtempSync, readFileSync, readdirSync, - rmdirSync, rmSync, statSync, symlinkSync, @@ -273,7 +272,11 @@ function createDisposableCurrentDatabase( copyFileSync(authorityDatabase, path); for (const suffix of ["-wal", "-shm"]) { const source = `${authorityDatabase}${suffix}`; - if (existsSync(source)) copyFileSync(source, `${path}${suffix}`); + try { + copyFileSync(source, `${path}${suffix}`); + } catch { + // Source may not exist or may have been removed - ignore + } } const modes = [ options.fts ? "fts" : "", @@ -725,11 +728,19 @@ if (stage === "init" && authority) { if (process.env.FIXTURE_AUTHORITY_FAILURE === "1") process.exit(9); const destination = join(project, ".git/carryctx/state.sqlite"); mkdirSync(dirname(destination), { recursive: true }); - if (process.env.FIXTURE_AUTHORITY_DB && existsSync(process.env.FIXTURE_AUTHORITY_DB)) { - copyFileSync(process.env.FIXTURE_AUTHORITY_DB, destination); + if (process.env.FIXTURE_AUTHORITY_DB) { + try { + copyFileSync(process.env.FIXTURE_AUTHORITY_DB, destination); + } catch { + // Source may not exist - skip + } for (const suffix of ["-wal", "-shm"]) { const source = process.env.FIXTURE_AUTHORITY_DB + suffix; - if (existsSync(source)) copyFileSync(source, destination + suffix); + try { + copyFileSync(source, destination + suffix); + } catch { + // Source may not exist or may have been removed - ignore + } } } else { writeFileSync(destination, "authority"); @@ -754,9 +765,13 @@ if (stage === "stats" && process.env.FIXTURE_RACE === "guard-after-validation") const restoreIndex = process.argv.indexOf("restore"); const source = process.argv[restoreIndex + 1]; const destination = join(stateRoot, "carryctx/state.sqlite"); - if (source && existsSync(source)) { - mkdirSync(dirname(destination), { recursive: true }); - copyFileSync(source, destination); + if (source) { + try { + mkdirSync(dirname(destination), { recursive: true }); + copyFileSync(source, destination); + } catch { + // Source may not exist or may have been removed - ignore + } } process.exit(0); } @@ -766,29 +781,51 @@ if (stage === "init" || stage === "import") { if (stage === "import") { const state = join(stateRoot, "carryctx/state.sqlite"); const raceState = staging ? join(process.env.FIXTURE_COMMON, "carryctx/state.sqlite") : state; - if (process.env.FIXTURE_RACE === "import-inode" && existsSync(raceState)) { + if (process.env.FIXTURE_RACE === "import-inode") { const replacement = raceState + ".inode"; - copyFileSync(raceState, replacement); + try { + copyFileSync(raceState, replacement); + } catch { + // raceState may have been removed - continue without copying + } for (const suffix of ["-wal", "-shm"]) { - if (existsSync(raceState + suffix)) copyFileSync(raceState + suffix, replacement + suffix); + try { + copyFileSync(raceState + suffix, replacement + suffix); + } catch { + // Source may not exist or may have been removed - ignore + } } renameSync(replacement, raceState); for (const suffix of ["-wal", "-shm"]) { - if (existsSync(replacement + suffix)) { + try { copyFileSync(replacement + suffix, raceState + suffix); rmSync(replacement + suffix, { force: true }); + } catch { + // File may not exist - ignore } } } - if (process.env.FIXTURE_RACE === "import" && existsSync(raceState)) appendFileSync(raceState, "import-race"); + if (process.env.FIXTURE_RACE === "import") { + try { + appendFileSync(raceState, "import-race"); + } catch { + // raceState may not exist or may have been removed - ignore + } + } importBackup = join(stateRoot, "carryctx/backups/pre_import_fixture.sqlite"); mkdirSync(dirname(importBackup), { recursive: true }); - if (existsSync(state)) { + try { copyFileSync(state, importBackup); for (const suffix of ["-wal", "-shm"]) { - if (existsSync(state + suffix)) copyFileSync(state + suffix, importBackup + suffix); + try { + copyFileSync(state + suffix, importBackup + suffix); + } catch { + // Source may not exist or may have been removed - ignore + } } - } else writeFileSync(importBackup, "absent"); + } catch { + writeFileSync(importBackup, "absent"); + } if (process.env.FIXTURE_RACE === "import-path") { const replacement = raceState + ".replacement"; writeFileSync(replacement, "replacement"); @@ -1000,14 +1037,18 @@ process.exit(result.exitCode);`, }; const activeProjectName = readProjectName(currentDatabase); const stateDirectory = dirname(currentDatabase); - const guardFile = existsSync(stateDirectory) - ? readdirSync(stateDirectory).find( + const guardFile = (() => { + try { + return readdirSync(stateDirectory).find( (name) => name.startsWith(".workflow-import-original.") && !name.endsWith("-wal") && !name.endsWith("-shm"), - ) - : undefined; + ); + } catch { + return undefined; + } + })(); const guardProjectName = guardFile ? readProjectName(join(stateDirectory, guardFile)) : undefined;