Skip to content

Commit 7c71547

Browse files
Copilotdata-douser
andauthored
Fix LRU cache eviction, consolidate imports, fix SARIF fallback semantics, add result-processor tests
Agent-Logs-Url: https://github.com/advanced-security/codeql-development-mcp-server/sessions/7ce2a157-666f-4975-b9f3-bb31d43f42db Co-authored-by: data-douser <70299490+data-douser@users.noreply.github.com>
1 parent e9db89c commit 7c71547

File tree

7 files changed

+390
-18
lines changed

7 files changed

+390
-18
lines changed

server/dist/codeql-development-mcp-server.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182939,7 +182939,6 @@ async function resolveQueryPath(params, logger2) {
182939182939

182940182940
// src/lib/result-processor.ts
182941182941
init_cli_executor();
182942-
init_cli_executor();
182943182942
import { basename as basename4, dirname as dirname4 } from "path";
182944182943
import { mkdirSync as mkdirSync7, readFileSync as readFileSync6 } from "fs";
182945182944
import { createHash as createHash2 } from "crypto";
@@ -182965,6 +182964,8 @@ async function extractQueryMetadata(queryPath) {
182965182964
mtime = fstatSync(fd).mtimeMs;
182966182965
const cached2 = metadataCache.get(queryPath);
182967182966
if (cached2 && cached2.mtime === mtime) {
182967+
metadataCache.delete(queryPath);
182968+
metadataCache.set(queryPath, cached2);
182968182969
return cached2.metadata;
182969182970
}
182970182971
queryContent = readFileSync4(fd, "utf-8");
@@ -183402,8 +183403,10 @@ var SqliteStore = class _SqliteStore {
183402183403
/**
183403183404
* Write the in-memory database to disk.
183404183405
*
183405-
* Uses write-to-temp + atomic rename so a crash mid-write cannot
183406-
* corrupt the database file.
183406+
* On POSIX: writes to a temp file and renames atomically so a crash mid-write
183407+
* cannot corrupt the database file.
183408+
* On Windows: `renameSync` may fail if the destination exists; the fallback
183409+
* overwrites the file in place (not crash-safe) and cleans up the temp file.
183407183410
*/
183408183411
flush() {
183409183412
if (this.flushTimer) {
@@ -183819,12 +183822,13 @@ var SqliteStore = class _SqliteStore {
183819183822
truncated
183820183823
};
183821183824
} catch {
183822-
const fallback = this.getCacheContentSubset(cacheKey2, { maxLines: options.maxResults ?? 100 });
183825+
const FALLBACK_MAX_LINES = 500;
183826+
const fallback = this.getCacheContentSubset(cacheKey2, { maxLines: FALLBACK_MAX_LINES });
183823183827
if (!fallback) return null;
183824183828
return {
183825183829
content: fallback.content,
183826-
totalResults: fallback.totalLines,
183827-
returnedResults: fallback.returnedLines,
183830+
totalResults: 0,
183831+
returnedResults: 0,
183828183832
truncated: fallback.truncated
183829183833
};
183830183834
}

server/dist/codeql-development-mcp-server.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/src/lib/query-results-evaluator.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ export const BUILT_IN_EVALUATORS = {
3434
export type BuiltInEvaluator = keyof typeof BUILT_IN_EVALUATORS;
3535

3636
/**
37-
* In-memory cache for extracted query metadata, keyed by file path.
37+
* In-memory LRU cache for extracted query metadata, keyed by file path.
3838
* Stores the file modification time to invalidate when the file changes.
39-
* Bounded to {@link METADATA_CACHE_MAX} entries; oldest entries are evicted
40-
* when the limit is reached (Map iteration order = insertion order).
39+
* Bounded to {@link METADATA_CACHE_MAX} entries; least-recently-used entries
40+
* are evicted first (cache hits re-insert the entry to refresh Map order).
4141
*/
4242
const METADATA_CACHE_MAX = 256;
4343
const metadataCache = new Map<string, { mtime: number; metadata: QueryMetadata }>();
@@ -56,6 +56,9 @@ export async function extractQueryMetadata(queryPath: string): Promise<QueryMeta
5656
mtime = fstatSync(fd).mtimeMs;
5757
const cached = metadataCache.get(queryPath);
5858
if (cached && cached.mtime === mtime) {
59+
// Refresh recency: re-insert so Map iteration order reflects last access (true LRU).
60+
metadataCache.delete(queryPath);
61+
metadataCache.set(queryPath, cached);
5962
return cached.metadata;
6063
}
6164
queryContent = readFileSync(fd, 'utf-8');

server/src/lib/result-processor.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
import { basename, dirname } from 'path';
1010
import { mkdirSync, readFileSync } from 'fs';
1111
import { createHash } from 'crypto';
12-
import { executeCodeQLCommand, CLIExecutionResult } from './cli-executor';
13-
import { getActualCodeqlVersion } from './cli-executor';
12+
import { CLIExecutionResult, executeCodeQLCommand, getActualCodeqlVersion } from './cli-executor';
1413
import { evaluateQueryResults, extractQueryMetadata, QueryEvaluationResult } from './query-results-evaluator';
1514
import { resolveQueryPath } from './query-resolver';
1615
import { sessionDataManager } from './session-data-manager';

server/src/lib/sqlite-store.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,10 @@ export class SqliteStore {
252252
/**
253253
* Write the in-memory database to disk.
254254
*
255-
* Uses write-to-temp + atomic rename so a crash mid-write cannot
256-
* corrupt the database file.
255+
* On POSIX: writes to a temp file and renames atomically so a crash mid-write
256+
* cannot corrupt the database file.
257+
* On Windows: `renameSync` may fail if the destination exists; the fallback
258+
* overwrites the file in place (not crash-safe) and cleans up the temp file.
257259
*/
258260
flush(): void {
259261
if (this.flushTimer) {
@@ -763,12 +765,18 @@ export class SqliteStore {
763765
truncated,
764766
};
765767
} catch {
766-
const fallback = this.getCacheContentSubset(cacheKey, { maxLines: options.maxResults ?? 100 });
768+
// Cached content is not valid SARIF JSON; fall back to a line-based excerpt
769+
// so callers still get something useful. Use a fixed maxLines default
770+
// independent of maxResults (which is a SARIF-result concept).
771+
const FALLBACK_MAX_LINES = 500;
772+
const fallback = this.getCacheContentSubset(cacheKey, { maxLines: FALLBACK_MAX_LINES });
767773
if (!fallback) return null;
774+
// Return with a note that the content is not SARIF; use result-neutral field
775+
// names so callers can detect the fallback.
768776
return {
769777
content: fallback.content,
770-
totalResults: fallback.totalLines,
771-
returnedResults: fallback.returnedLines,
778+
totalResults: 0,
779+
returnedResults: 0,
772780
truncated: fallback.truncated,
773781
};
774782
}

0 commit comments

Comments
 (0)