codeql-development-mcp-server 2.25.2 → 2.25.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/codeql-development-mcp-server.js +616 -155
- package/dist/codeql-development-mcp-server.js.map +3 -3
- package/package.json +9 -8
- package/ql/actions/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/actions/tools/src/codeql-pack.yml +2 -2
- package/ql/cpp/tools/src/codeql-pack.lock.yml +12 -12
- package/ql/cpp/tools/src/codeql-pack.yml +2 -2
- package/ql/csharp/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/csharp/tools/src/codeql-pack.yml +2 -2
- package/ql/go/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/go/tools/src/codeql-pack.yml +2 -2
- package/ql/java/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/java/tools/src/codeql-pack.yml +2 -2
- package/ql/javascript/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/javascript/tools/src/codeql-pack.yml +2 -2
- package/ql/python/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/python/tools/src/codeql-pack.yml +2 -2
- package/ql/ruby/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/ruby/tools/src/codeql-pack.yml +2 -2
- package/ql/rust/tools/src/codeql-pack.lock.yml +12 -12
- package/ql/rust/tools/src/codeql-pack.yml +2 -2
- package/ql/swift/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/swift/tools/src/codeql-pack.yml +2 -2
|
@@ -3600,49 +3600,49 @@ var require_fast_uri = __commonJS({
|
|
|
3600
3600
|
schemelessOptions.skipEscape = true;
|
|
3601
3601
|
return serialize(resolved, schemelessOptions);
|
|
3602
3602
|
}
|
|
3603
|
-
function resolveComponent(base,
|
|
3603
|
+
function resolveComponent(base, relative4, options, skipNormalization) {
|
|
3604
3604
|
const target = {};
|
|
3605
3605
|
if (!skipNormalization) {
|
|
3606
3606
|
base = parse4(serialize(base, options), options);
|
|
3607
|
-
|
|
3607
|
+
relative4 = parse4(serialize(relative4, options), options);
|
|
3608
3608
|
}
|
|
3609
3609
|
options = options || {};
|
|
3610
|
-
if (!options.tolerant &&
|
|
3611
|
-
target.scheme =
|
|
3612
|
-
target.userinfo =
|
|
3613
|
-
target.host =
|
|
3614
|
-
target.port =
|
|
3615
|
-
target.path = removeDotSegments(
|
|
3616
|
-
target.query =
|
|
3610
|
+
if (!options.tolerant && relative4.scheme) {
|
|
3611
|
+
target.scheme = relative4.scheme;
|
|
3612
|
+
target.userinfo = relative4.userinfo;
|
|
3613
|
+
target.host = relative4.host;
|
|
3614
|
+
target.port = relative4.port;
|
|
3615
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3616
|
+
target.query = relative4.query;
|
|
3617
3617
|
} else {
|
|
3618
|
-
if (
|
|
3619
|
-
target.userinfo =
|
|
3620
|
-
target.host =
|
|
3621
|
-
target.port =
|
|
3622
|
-
target.path = removeDotSegments(
|
|
3623
|
-
target.query =
|
|
3618
|
+
if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
|
|
3619
|
+
target.userinfo = relative4.userinfo;
|
|
3620
|
+
target.host = relative4.host;
|
|
3621
|
+
target.port = relative4.port;
|
|
3622
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3623
|
+
target.query = relative4.query;
|
|
3624
3624
|
} else {
|
|
3625
|
-
if (!
|
|
3625
|
+
if (!relative4.path) {
|
|
3626
3626
|
target.path = base.path;
|
|
3627
|
-
if (
|
|
3628
|
-
target.query =
|
|
3627
|
+
if (relative4.query !== void 0) {
|
|
3628
|
+
target.query = relative4.query;
|
|
3629
3629
|
} else {
|
|
3630
3630
|
target.query = base.query;
|
|
3631
3631
|
}
|
|
3632
3632
|
} else {
|
|
3633
|
-
if (
|
|
3634
|
-
target.path = removeDotSegments(
|
|
3633
|
+
if (relative4.path[0] === "/") {
|
|
3634
|
+
target.path = removeDotSegments(relative4.path);
|
|
3635
3635
|
} else {
|
|
3636
3636
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
3637
|
-
target.path = "/" +
|
|
3637
|
+
target.path = "/" + relative4.path;
|
|
3638
3638
|
} else if (!base.path) {
|
|
3639
|
-
target.path =
|
|
3639
|
+
target.path = relative4.path;
|
|
3640
3640
|
} else {
|
|
3641
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
3641
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
|
|
3642
3642
|
}
|
|
3643
3643
|
target.path = removeDotSegments(target.path);
|
|
3644
3644
|
}
|
|
3645
|
-
target.query =
|
|
3645
|
+
target.query = relative4.query;
|
|
3646
3646
|
}
|
|
3647
3647
|
target.userinfo = base.userinfo;
|
|
3648
3648
|
target.host = base.host;
|
|
@@ -3650,7 +3650,7 @@ var require_fast_uri = __commonJS({
|
|
|
3650
3650
|
}
|
|
3651
3651
|
target.scheme = base.scheme;
|
|
3652
3652
|
}
|
|
3653
|
-
target.fragment =
|
|
3653
|
+
target.fragment = relative4.fragment;
|
|
3654
3654
|
return target;
|
|
3655
3655
|
}
|
|
3656
3656
|
function equal(uriA, uriB, options) {
|
|
@@ -13305,7 +13305,7 @@ var require_src = __commonJS({
|
|
|
13305
13305
|
// ../node_modules/depd/index.js
|
|
13306
13306
|
var require_depd = __commonJS({
|
|
13307
13307
|
"../node_modules/depd/index.js"(exports, module) {
|
|
13308
|
-
var
|
|
13308
|
+
var relative4 = __require("path").relative;
|
|
13309
13309
|
module.exports = depd;
|
|
13310
13310
|
var basePath = process.cwd();
|
|
13311
13311
|
function containsNamespace(str2, namespace) {
|
|
@@ -13497,7 +13497,7 @@ var require_depd = __commonJS({
|
|
|
13497
13497
|
return formatted;
|
|
13498
13498
|
}
|
|
13499
13499
|
function formatLocation(callSite) {
|
|
13500
|
-
return
|
|
13500
|
+
return relative4(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
|
|
13501
13501
|
}
|
|
13502
13502
|
function getStack() {
|
|
13503
13503
|
var limit = Error.stackTraceLimit;
|
|
@@ -32676,9 +32676,8 @@ var require_side_channel_list = __commonJS({
|
|
|
32676
32676
|
}
|
|
32677
32677
|
},
|
|
32678
32678
|
"delete": function(key) {
|
|
32679
|
-
var root = $o && $o.next;
|
|
32680
32679
|
var deletedNode = listDelete($o, key);
|
|
32681
|
-
if (deletedNode &&
|
|
32680
|
+
if (deletedNode && $o && !$o.next) {
|
|
32682
32681
|
$o = void 0;
|
|
32683
32682
|
}
|
|
32684
32683
|
return !!deletedNode;
|
|
@@ -34321,9 +34320,9 @@ var require_parse = __commonJS({
|
|
|
34321
34320
|
var limit = options.parameterLimit === Infinity ? void 0 : options.parameterLimit;
|
|
34322
34321
|
var parts = cleanStr.split(
|
|
34323
34322
|
options.delimiter,
|
|
34324
|
-
options.throwOnLimitExceeded ? limit + 1 : limit
|
|
34323
|
+
options.throwOnLimitExceeded && typeof limit !== "undefined" ? limit + 1 : limit
|
|
34325
34324
|
);
|
|
34326
|
-
if (options.throwOnLimitExceeded && parts.length > limit) {
|
|
34325
|
+
if (options.throwOnLimitExceeded && typeof limit !== "undefined" && parts.length > limit) {
|
|
34327
34326
|
throw new RangeError("Parameter limit exceeded. Only " + limit + " parameter" + (limit === 1 ? "" : "s") + " allowed.");
|
|
34328
34327
|
}
|
|
34329
34328
|
var skipIndex = -1;
|
|
@@ -35004,7 +35003,7 @@ var require_view = __commonJS({
|
|
|
35004
35003
|
var path3 = __require("node:path");
|
|
35005
35004
|
var fs3 = __require("node:fs");
|
|
35006
35005
|
var dirname10 = path3.dirname;
|
|
35007
|
-
var
|
|
35006
|
+
var basename11 = path3.basename;
|
|
35008
35007
|
var extname3 = path3.extname;
|
|
35009
35008
|
var join23 = path3.join;
|
|
35010
35009
|
var resolve15 = path3.resolve;
|
|
@@ -35043,7 +35042,7 @@ var require_view = __commonJS({
|
|
|
35043
35042
|
var root = roots[i];
|
|
35044
35043
|
var loc = resolve15(root, name);
|
|
35045
35044
|
var dir = dirname10(loc);
|
|
35046
|
-
var file =
|
|
35045
|
+
var file = basename11(loc);
|
|
35047
35046
|
path4 = this.resolve(dir, file);
|
|
35048
35047
|
}
|
|
35049
35048
|
return path4;
|
|
@@ -35073,7 +35072,7 @@ var require_view = __commonJS({
|
|
|
35073
35072
|
if (stat && stat.isFile()) {
|
|
35074
35073
|
return path4;
|
|
35075
35074
|
}
|
|
35076
|
-
path4 = join23(dir,
|
|
35075
|
+
path4 = join23(dir, basename11(file, ext), "index" + ext);
|
|
35077
35076
|
stat = tryStat(path4);
|
|
35078
35077
|
if (stat && stat.isFile()) {
|
|
35079
35078
|
return path4;
|
|
@@ -38371,10 +38370,8 @@ var require_content_disposition = __commonJS({
|
|
|
38371
38370
|
"use strict";
|
|
38372
38371
|
module.exports = contentDisposition;
|
|
38373
38372
|
module.exports.parse = parse4;
|
|
38374
|
-
var
|
|
38373
|
+
var utf8Decoder = new TextDecoder("utf-8");
|
|
38375
38374
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
38376
|
-
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
38377
|
-
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
38378
38375
|
var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g;
|
|
38379
38376
|
var QESC_REGEXP = /\\([\u0000-\u007f])/g;
|
|
38380
38377
|
var QUOTE_REGEXP = /([\\"])/g;
|
|
@@ -38406,11 +38403,11 @@ var require_content_disposition = __commonJS({
|
|
|
38406
38403
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
38407
38404
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
38408
38405
|
}
|
|
38409
|
-
var name =
|
|
38406
|
+
var name = basename11(filename);
|
|
38410
38407
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
38411
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
38408
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename11(fallback);
|
|
38412
38409
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
38413
|
-
if (hasFallback || !isQuotedString ||
|
|
38410
|
+
if (hasFallback || !isQuotedString || hasHexEscape(name)) {
|
|
38414
38411
|
params["filename*"] = name;
|
|
38415
38412
|
}
|
|
38416
38413
|
if (isQuotedString || hasFallback) {
|
|
@@ -38437,26 +38434,32 @@ var require_content_disposition = __commonJS({
|
|
|
38437
38434
|
return string3;
|
|
38438
38435
|
}
|
|
38439
38436
|
function decodefield(str2) {
|
|
38440
|
-
|
|
38437
|
+
const match = EXT_VALUE_REGEXP.exec(str2);
|
|
38441
38438
|
if (!match) {
|
|
38442
38439
|
throw new TypeError("invalid extended field value");
|
|
38443
38440
|
}
|
|
38444
|
-
|
|
38445
|
-
|
|
38446
|
-
var value;
|
|
38447
|
-
var binary2 = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode);
|
|
38441
|
+
const charset = match[1].toLowerCase();
|
|
38442
|
+
const encoded = match[2];
|
|
38448
38443
|
switch (charset) {
|
|
38449
|
-
case "iso-8859-1":
|
|
38450
|
-
|
|
38451
|
-
|
|
38444
|
+
case "iso-8859-1": {
|
|
38445
|
+
const binary2 = decodeHexEscapes(encoded);
|
|
38446
|
+
return getlatin1(binary2);
|
|
38447
|
+
}
|
|
38452
38448
|
case "utf-8":
|
|
38453
|
-
case "utf8":
|
|
38454
|
-
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
38449
|
+
case "utf8": {
|
|
38450
|
+
try {
|
|
38451
|
+
return decodeURIComponent(encoded);
|
|
38452
|
+
} catch {
|
|
38453
|
+
const binary2 = decodeHexEscapes(encoded);
|
|
38454
|
+
const bytes = new Uint8Array(binary2.length);
|
|
38455
|
+
for (let idx = 0; idx < binary2.length; idx++) {
|
|
38456
|
+
bytes[idx] = binary2.charCodeAt(idx);
|
|
38457
|
+
}
|
|
38458
|
+
return utf8Decoder.decode(bytes);
|
|
38459
|
+
}
|
|
38460
|
+
}
|
|
38458
38461
|
}
|
|
38459
|
-
|
|
38462
|
+
throw new TypeError("unsupported charset in extended field");
|
|
38460
38463
|
}
|
|
38461
38464
|
function getlatin1(val) {
|
|
38462
38465
|
return String(val).replace(NON_LATIN1_REGEXP, "?");
|
|
@@ -38506,9 +38509,6 @@ var require_content_disposition = __commonJS({
|
|
|
38506
38509
|
}
|
|
38507
38510
|
return new ContentDisposition(type2, params);
|
|
38508
38511
|
}
|
|
38509
|
-
function pdecode(str2, hex) {
|
|
38510
|
-
return String.fromCharCode(parseInt(hex, 16));
|
|
38511
|
-
}
|
|
38512
38512
|
function pencode(char) {
|
|
38513
38513
|
return "%" + String(char).charCodeAt(0).toString(16).toUpperCase();
|
|
38514
38514
|
}
|
|
@@ -38525,6 +38525,51 @@ var require_content_disposition = __commonJS({
|
|
|
38525
38525
|
this.type = type2;
|
|
38526
38526
|
this.parameters = parameters;
|
|
38527
38527
|
}
|
|
38528
|
+
function basename11(path3) {
|
|
38529
|
+
const normalized = path3.replaceAll("\\", "/");
|
|
38530
|
+
let end = normalized.length;
|
|
38531
|
+
while (end > 0 && normalized[end - 1] === "/") {
|
|
38532
|
+
end--;
|
|
38533
|
+
}
|
|
38534
|
+
if (end === 0) {
|
|
38535
|
+
return "";
|
|
38536
|
+
}
|
|
38537
|
+
let start = end - 1;
|
|
38538
|
+
while (start >= 0 && normalized[start] !== "/") {
|
|
38539
|
+
start--;
|
|
38540
|
+
}
|
|
38541
|
+
return normalized.slice(start + 1, end);
|
|
38542
|
+
}
|
|
38543
|
+
function isHexDigit(char) {
|
|
38544
|
+
const code = char.charCodeAt(0);
|
|
38545
|
+
return code >= 48 && code <= 57 || // 0-9
|
|
38546
|
+
code >= 65 && code <= 70 || // A-F
|
|
38547
|
+
code >= 97 && code <= 102;
|
|
38548
|
+
}
|
|
38549
|
+
function hasHexEscape(str2) {
|
|
38550
|
+
const maxIndex = str2.length - 3;
|
|
38551
|
+
let lastIndex = -1;
|
|
38552
|
+
while ((lastIndex = str2.indexOf("%", lastIndex + 1)) !== -1 && lastIndex <= maxIndex) {
|
|
38553
|
+
if (isHexDigit(str2[lastIndex + 1]) && isHexDigit(str2[lastIndex + 2])) {
|
|
38554
|
+
return true;
|
|
38555
|
+
}
|
|
38556
|
+
}
|
|
38557
|
+
return false;
|
|
38558
|
+
}
|
|
38559
|
+
function decodeHexEscapes(str2) {
|
|
38560
|
+
const firstEscape = str2.indexOf("%");
|
|
38561
|
+
if (firstEscape === -1) return str2;
|
|
38562
|
+
let result = str2.slice(0, firstEscape);
|
|
38563
|
+
for (let idx = firstEscape; idx < str2.length; idx++) {
|
|
38564
|
+
if (str2[idx] === "%" && idx + 2 < str2.length && isHexDigit(str2[idx + 1]) && isHexDigit(str2[idx + 2])) {
|
|
38565
|
+
result += String.fromCharCode(Number.parseInt(str2[idx + 1] + str2[idx + 2], 16));
|
|
38566
|
+
idx += 2;
|
|
38567
|
+
} else {
|
|
38568
|
+
result += str2[idx];
|
|
38569
|
+
}
|
|
38570
|
+
}
|
|
38571
|
+
return result;
|
|
38572
|
+
}
|
|
38528
38573
|
}
|
|
38529
38574
|
});
|
|
38530
38575
|
|
|
@@ -38735,7 +38780,7 @@ var require_send = __commonJS({
|
|
|
38735
38780
|
var join23 = path3.join;
|
|
38736
38781
|
var normalize2 = path3.normalize;
|
|
38737
38782
|
var resolve15 = path3.resolve;
|
|
38738
|
-
var
|
|
38783
|
+
var sep5 = path3.sep;
|
|
38739
38784
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
38740
38785
|
var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
|
|
38741
38786
|
var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
|
|
@@ -38896,14 +38941,14 @@ var require_send = __commonJS({
|
|
|
38896
38941
|
var parts;
|
|
38897
38942
|
if (root !== null) {
|
|
38898
38943
|
if (path4) {
|
|
38899
|
-
path4 = normalize2("." +
|
|
38944
|
+
path4 = normalize2("." + sep5 + path4);
|
|
38900
38945
|
}
|
|
38901
38946
|
if (UP_PATH_REGEXP.test(path4)) {
|
|
38902
38947
|
debug('malicious path "%s"', path4);
|
|
38903
38948
|
this.error(403);
|
|
38904
38949
|
return res;
|
|
38905
38950
|
}
|
|
38906
|
-
parts = path4.split(
|
|
38951
|
+
parts = path4.split(sep5);
|
|
38907
38952
|
path4 = normalize2(join23(root, path4));
|
|
38908
38953
|
} else {
|
|
38909
38954
|
if (UP_PATH_REGEXP.test(path4)) {
|
|
@@ -38911,7 +38956,7 @@ var require_send = __commonJS({
|
|
|
38911
38956
|
this.error(403);
|
|
38912
38957
|
return res;
|
|
38913
38958
|
}
|
|
38914
|
-
parts = normalize2(path4).split(
|
|
38959
|
+
parts = normalize2(path4).split(sep5);
|
|
38915
38960
|
path4 = resolve15(path4);
|
|
38916
38961
|
}
|
|
38917
38962
|
if (containsDotFile(parts)) {
|
|
@@ -39005,7 +39050,7 @@ var require_send = __commonJS({
|
|
|
39005
39050
|
var self2 = this;
|
|
39006
39051
|
debug('stat "%s"', path4);
|
|
39007
39052
|
fs3.stat(path4, function onstat(err, stat) {
|
|
39008
|
-
var pathEndsWithSep = path4[path4.length - 1] ===
|
|
39053
|
+
var pathEndsWithSep = path4[path4.length - 1] === sep5;
|
|
39009
39054
|
if (err && err.code === "ENOENT" && !extname3(path4) && !pathEndsWithSep) {
|
|
39010
39055
|
return next(err);
|
|
39011
39056
|
}
|
|
@@ -40383,8 +40428,8 @@ var require_main = __commonJS({
|
|
|
40383
40428
|
const shortPaths = [];
|
|
40384
40429
|
for (const filePath of optionPaths) {
|
|
40385
40430
|
try {
|
|
40386
|
-
const
|
|
40387
|
-
shortPaths.push(
|
|
40431
|
+
const relative4 = path3.relative(process.cwd(), filePath);
|
|
40432
|
+
shortPaths.push(relative4);
|
|
40388
40433
|
} catch (e) {
|
|
40389
40434
|
if (debug) {
|
|
40390
40435
|
_debug(`failed to load ${filePath} ${e.message}`);
|
|
@@ -40392,7 +40437,7 @@ var require_main = __commonJS({
|
|
|
40392
40437
|
lastError = e;
|
|
40393
40438
|
}
|
|
40394
40439
|
}
|
|
40395
|
-
_log(`
|
|
40440
|
+
_log(`injected env (${keysCount}) from ${shortPaths.join(",")} ${dim(`// tip: ${_getRandomTip()}`)}`);
|
|
40396
40441
|
}
|
|
40397
40442
|
if (lastError) {
|
|
40398
40443
|
return { parsed: parsedAll, error: lastError };
|
|
@@ -172214,8 +172259,8 @@ var require_adm_zip = __commonJS({
|
|
|
172214
172259
|
return null;
|
|
172215
172260
|
}
|
|
172216
172261
|
function fixPath(zipPath) {
|
|
172217
|
-
const { join: join23, normalize: normalize2, sep:
|
|
172218
|
-
return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(
|
|
172262
|
+
const { join: join23, normalize: normalize2, sep: sep5 } = pth.posix;
|
|
172263
|
+
return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(sep5 + zipPath.split("\\").join(sep5) + sep5));
|
|
172219
172264
|
}
|
|
172220
172265
|
function filenameFilter(filterfn) {
|
|
172221
172266
|
if (filterfn instanceof RegExp) {
|
|
@@ -188585,12 +188630,13 @@ init_logger();
|
|
|
188585
188630
|
// src/lib/log-directory-manager.ts
|
|
188586
188631
|
init_temp_dir();
|
|
188587
188632
|
import { mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
|
|
188588
|
-
import { join as join7, resolve as resolve3 } from "path";
|
|
188633
|
+
import { join as join7, resolve as resolve3, sep, relative, isAbsolute as isAbsolute3 } from "path";
|
|
188589
188634
|
import { randomBytes } from "crypto";
|
|
188590
188635
|
function ensurePathWithinBase(baseDir, targetPath) {
|
|
188591
188636
|
const absBase = resolve3(baseDir);
|
|
188592
188637
|
const absTarget = resolve3(targetPath);
|
|
188593
|
-
|
|
188638
|
+
const rel = relative(absBase, absTarget);
|
|
188639
|
+
if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute3(rel)) {
|
|
188594
188640
|
throw new Error(`Provided log directory is outside the allowed base directory: ${absBase}`);
|
|
188595
188641
|
}
|
|
188596
188642
|
return absTarget;
|
|
@@ -188726,7 +188772,7 @@ import { createHash as createHash2 } from "crypto";
|
|
|
188726
188772
|
init_cli_executor();
|
|
188727
188773
|
init_logger();
|
|
188728
188774
|
import { closeSync, fstatSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync } from "fs";
|
|
188729
|
-
import { dirname as dirname3, isAbsolute as
|
|
188775
|
+
import { dirname as dirname3, isAbsolute as isAbsolute4 } from "path";
|
|
188730
188776
|
var BUILT_IN_EVALUATORS = {
|
|
188731
188777
|
"json-decode": "JSON format decoder for query results",
|
|
188732
188778
|
"csv-decode": "CSV format decoder for query results",
|
|
@@ -188979,7 +189025,7 @@ async function evaluateQueryResults(bqrsPath, queryPath, evaluationFunction, out
|
|
|
188979
189025
|
case "mermaid-graph":
|
|
188980
189026
|
return await evaluateWithMermaidGraph(bqrsPath, queryPath, outputPath);
|
|
188981
189027
|
default:
|
|
188982
|
-
if (
|
|
189028
|
+
if (isAbsolute4(evalFunc)) {
|
|
188983
189029
|
return await evaluateWithCustomScript(bqrsPath, queryPath, evalFunc, outputPath);
|
|
188984
189030
|
} else {
|
|
188985
189031
|
return {
|
|
@@ -189396,10 +189442,43 @@ function diffSarifRules(sarifA, sarifB) {
|
|
|
189396
189442
|
unchangedRules
|
|
189397
189443
|
};
|
|
189398
189444
|
}
|
|
189445
|
+
function computeFingerprintOverlap(resultA, resultB) {
|
|
189446
|
+
const fpA = resultA.partialFingerprints;
|
|
189447
|
+
const fpB = resultB.partialFingerprints;
|
|
189448
|
+
if (!fpA || !fpB || Object.keys(fpA).length === 0 || Object.keys(fpB).length === 0) {
|
|
189449
|
+
return {
|
|
189450
|
+
fingerprintMatch: false,
|
|
189451
|
+
overlaps: false,
|
|
189452
|
+
overlapMode: "fingerprint",
|
|
189453
|
+
sharedLocations: []
|
|
189454
|
+
};
|
|
189455
|
+
}
|
|
189456
|
+
const matchedFingerprints = {};
|
|
189457
|
+
for (const key of Object.keys(fpA)) {
|
|
189458
|
+
if (key in fpB && fpA[key] === fpB[key]) {
|
|
189459
|
+
matchedFingerprints[key] = fpA[key];
|
|
189460
|
+
}
|
|
189461
|
+
}
|
|
189462
|
+
const hasMatch = Object.keys(matchedFingerprints).length > 0;
|
|
189463
|
+
return {
|
|
189464
|
+
fingerprintMatch: hasMatch,
|
|
189465
|
+
matchedFingerprints: hasMatch ? matchedFingerprints : void 0,
|
|
189466
|
+
overlaps: hasMatch,
|
|
189467
|
+
overlapMode: "fingerprint",
|
|
189468
|
+
sharedLocations: []
|
|
189469
|
+
};
|
|
189470
|
+
}
|
|
189399
189471
|
function computeLocationOverlap(resultA, resultB, mode = "sink") {
|
|
189400
189472
|
let locsA;
|
|
189401
189473
|
let locsB;
|
|
189402
189474
|
switch (mode) {
|
|
189475
|
+
case "fingerprint": {
|
|
189476
|
+
const fpResult = computeFingerprintOverlap(resultA, resultB);
|
|
189477
|
+
if (fpResult.fingerprintMatch) {
|
|
189478
|
+
return fpResult;
|
|
189479
|
+
}
|
|
189480
|
+
return computeLocationOverlap(resultA, resultB, "full-path");
|
|
189481
|
+
}
|
|
189403
189482
|
case "sink":
|
|
189404
189483
|
locsA = extractPrimaryLocations(resultA);
|
|
189405
189484
|
locsB = extractPrimaryLocations(resultB);
|
|
@@ -189439,6 +189518,99 @@ function computeLocationOverlap(resultA, resultB, mode = "sink") {
|
|
|
189439
189518
|
sharedLocations: shared
|
|
189440
189519
|
};
|
|
189441
189520
|
}
|
|
189521
|
+
function findOverlappingAlerts(resultsA, ruleA, resultsB, ruleB, mode = "sink") {
|
|
189522
|
+
const overlaps = [];
|
|
189523
|
+
for (let i = 0; i < resultsA.length; i++) {
|
|
189524
|
+
for (let j = 0; j < resultsB.length; j++) {
|
|
189525
|
+
const overlapDetails = computeLocationOverlap(resultsA[i], resultsB[j], mode);
|
|
189526
|
+
if (overlapDetails.overlaps) {
|
|
189527
|
+
overlaps.push({
|
|
189528
|
+
overlapDetails,
|
|
189529
|
+
resultA: resultsA[i],
|
|
189530
|
+
resultAIndex: i,
|
|
189531
|
+
resultB: resultsB[j],
|
|
189532
|
+
resultBIndex: j,
|
|
189533
|
+
ruleIdA: ruleA.id,
|
|
189534
|
+
ruleIdB: ruleB.id
|
|
189535
|
+
});
|
|
189536
|
+
}
|
|
189537
|
+
}
|
|
189538
|
+
}
|
|
189539
|
+
return overlaps;
|
|
189540
|
+
}
|
|
189541
|
+
function lineInHunks(line, hunks) {
|
|
189542
|
+
for (const hunk of hunks) {
|
|
189543
|
+
const hunkEnd = hunk.startLine + Math.max(hunk.lineCount - 1, 0);
|
|
189544
|
+
if (line >= hunk.startLine && line <= hunkEnd) {
|
|
189545
|
+
return true;
|
|
189546
|
+
}
|
|
189547
|
+
}
|
|
189548
|
+
return false;
|
|
189549
|
+
}
|
|
189550
|
+
function diffSarifByCommits(sarif, diffFiles, refRange, granularity = "file") {
|
|
189551
|
+
const results = sarif.runs[0]?.results ?? [];
|
|
189552
|
+
const newResults = [];
|
|
189553
|
+
const preExistingResults = [];
|
|
189554
|
+
const normalizedDiffEntries = diffFiles.map((df) => ({
|
|
189555
|
+
entry: df,
|
|
189556
|
+
normalized: normalizeUri(df.path)
|
|
189557
|
+
}));
|
|
189558
|
+
for (let i = 0; i < results.length; i++) {
|
|
189559
|
+
const result = results[i];
|
|
189560
|
+
const primaryLoc = result.locations?.[0]?.physicalLocation;
|
|
189561
|
+
const uri = primaryLoc?.artifactLocation?.uri;
|
|
189562
|
+
if (!uri) {
|
|
189563
|
+
preExistingResults.push({
|
|
189564
|
+
file: "<unknown>",
|
|
189565
|
+
resultIndex: i,
|
|
189566
|
+
ruleId: result.ruleId
|
|
189567
|
+
});
|
|
189568
|
+
continue;
|
|
189569
|
+
}
|
|
189570
|
+
const startLine = primaryLoc?.region?.startLine;
|
|
189571
|
+
const normalizedUri = normalizeUri(uri);
|
|
189572
|
+
let matchingDiff;
|
|
189573
|
+
for (const { entry, normalized } of normalizedDiffEntries) {
|
|
189574
|
+
if (normalized === normalizedUri || normalized.endsWith(normalizedUri) || normalizedUri.endsWith(normalized)) {
|
|
189575
|
+
matchingDiff = entry;
|
|
189576
|
+
break;
|
|
189577
|
+
}
|
|
189578
|
+
}
|
|
189579
|
+
let isNew = false;
|
|
189580
|
+
if (matchingDiff) {
|
|
189581
|
+
if (granularity === "file") {
|
|
189582
|
+
isNew = true;
|
|
189583
|
+
} else if (startLine !== void 0 && matchingDiff.hunks.length > 0) {
|
|
189584
|
+
isNew = lineInHunks(startLine, matchingDiff.hunks);
|
|
189585
|
+
} else if (matchingDiff.hunks.length === 0 && !matchingDiff.hunksParsed) {
|
|
189586
|
+
isNew = true;
|
|
189587
|
+
}
|
|
189588
|
+
}
|
|
189589
|
+
const classified = {
|
|
189590
|
+
file: matchingDiff ? matchingDiff.path : normalizedUri,
|
|
189591
|
+
line: startLine,
|
|
189592
|
+
resultIndex: i,
|
|
189593
|
+
ruleId: result.ruleId
|
|
189594
|
+
};
|
|
189595
|
+
if (isNew) {
|
|
189596
|
+
newResults.push(classified);
|
|
189597
|
+
} else {
|
|
189598
|
+
preExistingResults.push(classified);
|
|
189599
|
+
}
|
|
189600
|
+
}
|
|
189601
|
+
return {
|
|
189602
|
+
granularity,
|
|
189603
|
+
newResults,
|
|
189604
|
+
preExistingResults,
|
|
189605
|
+
summary: {
|
|
189606
|
+
diffFileCount: diffFiles.length,
|
|
189607
|
+
refRange,
|
|
189608
|
+
totalNew: newResults.length,
|
|
189609
|
+
totalPreExisting: preExistingResults.length,
|
|
189610
|
+
totalResults: results.length
|
|
189611
|
+
}
|
|
189612
|
+
};
|
|
189613
|
+
}
|
|
189442
189614
|
|
|
189443
189615
|
// src/lib/session-data-manager.ts
|
|
189444
189616
|
init_temp_dir();
|
|
@@ -190314,8 +190486,8 @@ var MonitoringConfigSchema = external_exports.object({
|
|
|
190314
190486
|
enableRecommendations: external_exports.boolean().default(true),
|
|
190315
190487
|
enableMonitoringTools: external_exports.boolean().default(false),
|
|
190316
190488
|
// Opt-in: session_* tools disabled by default for end-users
|
|
190317
|
-
enableAnnotationTools: external_exports.boolean().default(
|
|
190318
|
-
//
|
|
190489
|
+
enableAnnotationTools: external_exports.boolean().default(true)
|
|
190490
|
+
// Controls auto-caching behaviour in result-processor; tools are always registered
|
|
190319
190491
|
});
|
|
190320
190492
|
|
|
190321
190493
|
// src/lib/session-data-manager.ts
|
|
@@ -190602,7 +190774,7 @@ function parseBoolEnv(envVar, defaultValue) {
|
|
|
190602
190774
|
var sessionDataManager = new SessionDataManager({
|
|
190603
190775
|
storageLocation: process.env.MONITORING_STORAGE_LOCATION || join9(getProjectTmpBase(), ".ql-mcp-tracking"),
|
|
190604
190776
|
enableMonitoringTools: parseBoolEnv(process.env.ENABLE_MONITORING_TOOLS, false),
|
|
190605
|
-
enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS,
|
|
190777
|
+
enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS, true)
|
|
190606
190778
|
});
|
|
190607
190779
|
|
|
190608
190780
|
// src/lib/result-processor.ts
|
|
@@ -190932,7 +191104,7 @@ function cacheDatabaseAnalyzeResults(params, logger2) {
|
|
|
190932
191104
|
// src/lib/cli-tool-registry.ts
|
|
190933
191105
|
init_package_paths();
|
|
190934
191106
|
import { existsSync as existsSync6, mkdirSync as mkdirSync8, realpathSync, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
190935
|
-
import { delimiter as delimiter5, dirname as dirname5, isAbsolute as
|
|
191107
|
+
import { basename as basename5, delimiter as delimiter5, dirname as dirname5, isAbsolute as isAbsolute5, join as join10, resolve as resolve4 } from "path";
|
|
190936
191108
|
|
|
190937
191109
|
// ../node_modules/js-yaml/dist/js-yaml.mjs
|
|
190938
191110
|
function isNothing(subject) {
|
|
@@ -193711,12 +193883,12 @@ function registerCLITool(server, definition) {
|
|
|
193711
193883
|
if (tests && Array.isArray(tests)) {
|
|
193712
193884
|
const userDir = getUserWorkspaceDir();
|
|
193713
193885
|
positionalArgs = [...positionalArgs, ...tests.map(
|
|
193714
|
-
(t) =>
|
|
193886
|
+
(t) => isAbsolute5(t) ? t : resolve4(userDir, t)
|
|
193715
193887
|
)];
|
|
193716
193888
|
}
|
|
193717
193889
|
break;
|
|
193718
193890
|
case "codeql_query_run": {
|
|
193719
|
-
if (options.database && typeof options.database === "string" && !
|
|
193891
|
+
if (options.database && typeof options.database === "string" && !isAbsolute5(options.database)) {
|
|
193720
193892
|
options.database = resolve4(getUserWorkspaceDir(), options.database);
|
|
193721
193893
|
logger.info(`Resolved database path to: ${options.database}`);
|
|
193722
193894
|
}
|
|
@@ -193836,6 +194008,19 @@ function registerCLITool(server, definition) {
|
|
|
193836
194008
|
break;
|
|
193837
194009
|
}
|
|
193838
194010
|
case "codeql_query_compile":
|
|
194011
|
+
if (query) {
|
|
194012
|
+
positionalArgs = [...positionalArgs, query];
|
|
194013
|
+
}
|
|
194014
|
+
if (options["dump-dil"] === void 0) {
|
|
194015
|
+
const pending = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
|
|
194016
|
+
const hasDilOverride = pending.some(
|
|
194017
|
+
(arg) => arg === "--no-dump-dil" || arg === "--dump-dil"
|
|
194018
|
+
);
|
|
194019
|
+
if (!hasDilOverride) {
|
|
194020
|
+
options["dump-dil"] = true;
|
|
194021
|
+
}
|
|
194022
|
+
}
|
|
194023
|
+
break;
|
|
193839
194024
|
case "codeql_resolve_metadata":
|
|
193840
194025
|
if (query) {
|
|
193841
194026
|
positionalArgs = [...positionalArgs, query];
|
|
@@ -193885,8 +194070,25 @@ function registerCLITool(server, definition) {
|
|
|
193885
194070
|
mkdirSync8(outputDir, { recursive: true });
|
|
193886
194071
|
}
|
|
193887
194072
|
}
|
|
193888
|
-
|
|
194073
|
+
let effectiveDumpDilEnabled = false;
|
|
194074
|
+
let rawAdditionalArgs = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
|
|
193889
194075
|
delete options.additionalArgs;
|
|
194076
|
+
if (name === "codeql_query_compile") {
|
|
194077
|
+
const lastDumpDilFlag = [...rawAdditionalArgs].reverse().find(
|
|
194078
|
+
(arg) => arg === "--dump-dil" || arg === "--no-dump-dil"
|
|
194079
|
+
);
|
|
194080
|
+
if (lastDumpDilFlag === "--dump-dil") {
|
|
194081
|
+
options["dump-dil"] = true;
|
|
194082
|
+
} else if (lastDumpDilFlag === "--no-dump-dil") {
|
|
194083
|
+
options["dump-dil"] = false;
|
|
194084
|
+
}
|
|
194085
|
+
if (lastDumpDilFlag !== void 0) {
|
|
194086
|
+
rawAdditionalArgs = rawAdditionalArgs.filter(
|
|
194087
|
+
(arg) => arg !== "--dump-dil" && arg !== "--no-dump-dil"
|
|
194088
|
+
);
|
|
194089
|
+
}
|
|
194090
|
+
effectiveDumpDilEnabled = options["dump-dil"] !== false;
|
|
194091
|
+
}
|
|
193890
194092
|
const managedFlagNames = /* @__PURE__ */ new Set([
|
|
193891
194093
|
"evaluator-log",
|
|
193892
194094
|
"logdir",
|
|
@@ -193918,7 +194120,7 @@ function registerCLITool(server, definition) {
|
|
|
193918
194120
|
let cwd;
|
|
193919
194121
|
if ((name === "codeql_pack_install" || name === "codeql_pack_ls") && (dir || packDir)) {
|
|
193920
194122
|
const rawCwd = dir || packDir;
|
|
193921
|
-
cwd =
|
|
194123
|
+
cwd = isAbsolute5(rawCwd) ? rawCwd : resolve4(getUserWorkspaceDir(), rawCwd);
|
|
193922
194124
|
}
|
|
193923
194125
|
const defaultExamplesPath = resolve4(packageRootDir, "ql", "javascript", "examples");
|
|
193924
194126
|
const additionalPacksPath = process.env.CODEQL_ADDITIONAL_PACKS || (existsSync6(defaultExamplesPath) ? defaultExamplesPath : void 0);
|
|
@@ -193980,7 +194182,36 @@ function registerCLITool(server, definition) {
|
|
|
193980
194182
|
const resolvedDb = typeof params.database === "string" ? resolveDatabasePath(params.database) : params.database;
|
|
193981
194183
|
cacheDatabaseAnalyzeResults({ ...params, database: resolvedDb, output: options.output, format: options.format }, logger);
|
|
193982
194184
|
}
|
|
193983
|
-
|
|
194185
|
+
let dilFilePath;
|
|
194186
|
+
if (name === "codeql_query_compile" && result.success && effectiveDumpDilEnabled && result.stdout) {
|
|
194187
|
+
try {
|
|
194188
|
+
const compileLogDir = getOrCreateLogDirectory(customLogDir);
|
|
194189
|
+
logger.info(`Using log directory for ${name}: ${compileLogDir}`);
|
|
194190
|
+
const queryBaseName = query ? basename5(query, ".ql") : "query";
|
|
194191
|
+
dilFilePath = join10(compileLogDir, `${queryBaseName}.dil`);
|
|
194192
|
+
writeFileSync4(dilFilePath, result.stdout, "utf8");
|
|
194193
|
+
logger.info(`Saved DIL output to ${dilFilePath}`);
|
|
194194
|
+
} catch (dilError) {
|
|
194195
|
+
logger.warn(`Failed to save DIL output: ${dilError}`);
|
|
194196
|
+
dilFilePath = void 0;
|
|
194197
|
+
}
|
|
194198
|
+
}
|
|
194199
|
+
let processedResult;
|
|
194200
|
+
if (dilFilePath) {
|
|
194201
|
+
const stdoutBytes = Buffer.byteLength(result.stdout ?? "", "utf8");
|
|
194202
|
+
processedResult = `Compiled successfully. DIL output written to file (${stdoutBytes} bytes).`;
|
|
194203
|
+
if (result.stderr) {
|
|
194204
|
+
processedResult += `
|
|
194205
|
+
|
|
194206
|
+
Warnings/Info:
|
|
194207
|
+
${result.stderr}`;
|
|
194208
|
+
}
|
|
194209
|
+
processedResult += `
|
|
194210
|
+
|
|
194211
|
+
DIL file: ${dilFilePath}`;
|
|
194212
|
+
} else {
|
|
194213
|
+
processedResult = resultProcessor(result, params);
|
|
194214
|
+
}
|
|
193984
194215
|
return {
|
|
193985
194216
|
content: [{
|
|
193986
194217
|
type: "text",
|
|
@@ -195252,7 +195483,7 @@ var codeqlPackLsTool = {
|
|
|
195252
195483
|
|
|
195253
195484
|
// src/tools/codeql/profile-codeql-query-from-logs.ts
|
|
195254
195485
|
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
195255
|
-
import { basename as
|
|
195486
|
+
import { basename as basename7, dirname as dirname7, join as join15 } from "path";
|
|
195256
195487
|
|
|
195257
195488
|
// src/lib/evaluator-log-parser.ts
|
|
195258
195489
|
init_logger();
|
|
@@ -195584,7 +195815,7 @@ function buildDetailFile(profile, topN) {
|
|
|
195584
195815
|
lines.push("");
|
|
195585
195816
|
for (let qIdx = 0; qIdx < profile.queries.length; qIdx++) {
|
|
195586
195817
|
const query = profile.queries[qIdx];
|
|
195587
|
-
const qName =
|
|
195818
|
+
const qName = basename7(query.queryName);
|
|
195588
195819
|
lines.push(`== Query: ${qName} ==`);
|
|
195589
195820
|
lines.push(` Total: ${query.totalDurationMs.toFixed(2)}ms | Predicates evaluated: ${query.predicateCount} | Cache hits: ${query.cacheHits}`);
|
|
195590
195821
|
lines.push("");
|
|
@@ -195743,7 +195974,7 @@ init_cli_executor();
|
|
|
195743
195974
|
init_logger();
|
|
195744
195975
|
import { writeFileSync as writeFileSync6, existsSync as existsSync12 } from "fs";
|
|
195745
195976
|
import { createReadStream as createReadStream2 } from "fs";
|
|
195746
|
-
import { join as join16, dirname as dirname8, basename as
|
|
195977
|
+
import { join as join16, dirname as dirname8, basename as basename8 } from "path";
|
|
195747
195978
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
195748
195979
|
import { createInterface as createInterface2 } from "readline";
|
|
195749
195980
|
async function parseEvaluatorLog2(logPath) {
|
|
@@ -195869,7 +196100,7 @@ function formatAsMermaid(profile) {
|
|
|
195869
196100
|
lines.push("```mermaid");
|
|
195870
196101
|
lines.push("graph TD");
|
|
195871
196102
|
lines.push("");
|
|
195872
|
-
lines.push(` QUERY["${
|
|
196103
|
+
lines.push(` QUERY["${basename8(profile.queryName)}<br/>Total: ${profile.totalDuration.toFixed(2)}ms"]`);
|
|
195873
196104
|
lines.push("");
|
|
195874
196105
|
profile.pipelines.forEach((pipeline) => {
|
|
195875
196106
|
const nodeId = `P${pipeline.eventId}`;
|
|
@@ -196000,7 +196231,7 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
196000
196231
|
...outputFiles.map((f) => ` - ${f}`),
|
|
196001
196232
|
"",
|
|
196002
196233
|
"Profile Summary:",
|
|
196003
|
-
` - Query: ${
|
|
196234
|
+
` - Query: ${basename8(profile.queryName)}`,
|
|
196004
196235
|
` - Total Duration: ${profile.totalDuration.toFixed(2)} ms`,
|
|
196005
196236
|
` - Total Pipelines: ${profile.pipelines.length}`,
|
|
196006
196237
|
` - Total Events: ${profile.totalEvents}`,
|
|
@@ -196037,13 +196268,15 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
196037
196268
|
// src/tools/codeql/query-compile.ts
|
|
196038
196269
|
var codeqlQueryCompileTool = {
|
|
196039
196270
|
name: "codeql_query_compile",
|
|
196040
|
-
description: "Compile and validate CodeQL queries",
|
|
196271
|
+
description: "Compile and validate CodeQL queries. By default, produces a .dil file containing the optimized DIL intermediate representation alongside the compilation output.",
|
|
196041
196272
|
command: "codeql",
|
|
196042
196273
|
subcommand: "query compile",
|
|
196043
196274
|
inputSchema: {
|
|
196044
196275
|
query: external_exports.string().describe("Path to the CodeQL query file (.ql)"),
|
|
196045
196276
|
database: external_exports.string().optional().describe("Path to the CodeQL database"),
|
|
196277
|
+
"dump-dil": external_exports.boolean().optional().describe("Print the optimized DIL intermediate representation to standard output while compiling. Enabled by default; pass false or --no-dump-dil to disable."),
|
|
196046
196278
|
library: external_exports.string().optional().describe("Path to query library"),
|
|
196279
|
+
logDir: external_exports.string().optional().describe("Custom directory for compilation DIL output (overrides CODEQL_QUERY_LOG_DIR environment variable). If not provided, uses CODEQL_QUERY_LOG_DIR or defaults to .tmp/query-logs/<unique-id>"),
|
|
196047
196280
|
output: external_exports.string().optional().describe("Output file path"),
|
|
196048
196281
|
warnings: external_exports.enum(["hide", "show", "error"]).optional().describe("How to handle compilation warnings"),
|
|
196049
196282
|
verbose: external_exports.boolean().optional().describe("Enable verbose output"),
|
|
@@ -196051,6 +196284,7 @@ var codeqlQueryCompileTool = {
|
|
|
196051
196284
|
},
|
|
196052
196285
|
examples: [
|
|
196053
196286
|
"codeql query compile --database=/path/to/db MyQuery.ql",
|
|
196287
|
+
"codeql query compile --dump-dil --database=/path/to/db MyQuery.ql",
|
|
196054
196288
|
"codeql query compile --library=/path/to/lib --output=compiled.qlo MyQuery.ql"
|
|
196055
196289
|
]
|
|
196056
196290
|
};
|
|
@@ -196699,7 +196933,7 @@ var codeqlResolveTestsTool = {
|
|
|
196699
196933
|
|
|
196700
196934
|
// src/tools/codeql/search-ql-code.ts
|
|
196701
196935
|
import { closeSync as closeSync2, createReadStream as createReadStream3, fstatSync as fstatSync2, lstatSync, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync12, realpathSync as realpathSync2 } from "fs";
|
|
196702
|
-
import { basename as
|
|
196936
|
+
import { basename as basename9, extname as extname2, join as join19, resolve as resolve9 } from "path";
|
|
196703
196937
|
import { createInterface as createInterface3 } from "readline";
|
|
196704
196938
|
|
|
196705
196939
|
// src/lib/scan-exclude.ts
|
|
@@ -196747,10 +196981,13 @@ var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
|
196747
196981
|
var MAX_FILES_TRAVERSED = 1e4;
|
|
196748
196982
|
var MAX_CONTEXT_LINES = 50;
|
|
196749
196983
|
var MAX_MAX_RESULTS = 1e4;
|
|
196750
|
-
|
|
196984
|
+
function getSkipDirs() {
|
|
196985
|
+
return getScanExcludeDirs();
|
|
196986
|
+
}
|
|
196751
196987
|
function collectFiles(paths, extensions, fileCount) {
|
|
196752
196988
|
const files = [];
|
|
196753
196989
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
196990
|
+
const skipDirs = getSkipDirs();
|
|
196754
196991
|
function walk(p) {
|
|
196755
196992
|
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
196756
196993
|
let stat;
|
|
@@ -196766,7 +197003,7 @@ function collectFiles(paths, extensions, fileCount) {
|
|
|
196766
197003
|
}
|
|
196767
197004
|
fileCount.value++;
|
|
196768
197005
|
} else if (stat.isDirectory()) {
|
|
196769
|
-
if (
|
|
197006
|
+
if (skipDirs.has(basename9(p))) return;
|
|
196770
197007
|
let realPath;
|
|
196771
197008
|
try {
|
|
196772
197009
|
realPath = realpathSync2(p);
|
|
@@ -197310,7 +197547,7 @@ var server_prompts_default = "# MCP Server Prompts\n\nThis resource provides a c
|
|
|
197310
197547
|
var server_queries_default = '# MCP Server Bundled Queries\n\nThis resource describes the tools queries bundled with the CodeQL Development MCP Server. These queries run via `codeql_query_run` and provide structural insight into how source code is represented in a CodeQL database. Use them to understand code structure before writing detection queries.\n\nFor general QL query writing guidance (syntax, metadata, `from`/`where`/`select`, testing conventions), see `codeql://learning/query-basics`.\n\n## Bundled Tools Queries\n\nThe server bundles five tools queries that operate on CodeQL databases:\n\n| Query | Purpose | Output Format |\n| ----------------- | ------------------------------------------------------- | ------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree of source code | `@kind graph` (graphtext) |\n| `PrintCFG` | Visualize the Control Flow Graph of a function | `@kind graph` (graphtext) |\n| `CallGraphFrom` | Show all functions called FROM a given function | `@kind graph` (graphtext) |\n| `CallGraphTo` | Show all call sites that call TO a given function | `@kind graph` (graphtext) |\n| `CallGraphFromTo` | Show calls FROM one function TO another (bidirectional) | `@kind graph` (graphtext) |\n\nAll five queries use `@kind graph` metadata and produce output in graphtext format.\n\n## PrintAST\n\n**Purpose**: Outputs a hierarchical representation of the Abstract Syntax Tree showing parent-child relationships between declarations, statements, and expressions.\n\n**When to use**: Before writing any CodeQL query, run `PrintAST` on your test source code to understand which QL classes represent which source constructs and which predicates are available for matching.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintAST"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFiles: "<comma-separated-filenames>" (optional \u2014 filter to specific files)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A tree showing each AST node with its QL class name, properties, and position in the hierarchy. This reveals exactly which QL classes and predicates to use in `from`/`where`/`select` clauses.\n\n## PrintCFG\n\n**Purpose**: Produces a Control Flow Graph representation showing the order in which statements and expressions execute, including branching paths.\n\n**When to use**: When writing queries that reason about execution order, reachability, or branching logic (e.g., "is this check always performed before this call?").\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintCFG"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>" (optional \u2014 target a specific function)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: Nodes representing CFG basic blocks and edges representing possible execution transitions (successor relationships).\n\n## CallGraphFrom\n\n**Purpose**: Shows all functions called FROM a specified source function \u2014 the outbound call dependencies.\n\n**When to use**: When analyzing what a function does by tracing the functions it invokes. Useful for understanding call chains and identifying potential data flow paths.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFrom"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each call site within the source function and the target function being called.\n\n## CallGraphTo\n\n**Purpose**: Shows all call sites that invoke a specified target function \u2014 the inbound callers.\n\n**When to use**: When performing impact analysis to understand where a function is used, or when identifying all locations that pass data to a particular sink function.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n targetFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each caller function and the specific call site where the target function is invoked.\n\n## CallGraphFromTo\n\n**Purpose**: Shows the call relationship between two specific functions \u2014 whether function A calls function B (directly or transitively) and what the call path looks like.\n\n**When to use**: When investigating whether a specific source function can reach a specific sink function through the call graph. Useful for validating dataflow hypotheses before writing taint-tracking queries.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFromTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<calling-function-name>"\n targetFunction: "<called-function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing the call path from the source function to the target function, including intermediate call sites.\n\n## Language Support\n\n| Language | PrintAST | PrintCFG | CallGraphFrom | CallGraphTo | CallGraphFromTo |\n| ---------- | :------: | :------: | :-----------: | :---------: | :-------------: |\n| actions | \u2713 | \u2713 | | | |\n| cpp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| csharp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| go | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| java | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| javascript | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| python | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| ruby | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| rust | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| swift | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n\nNote: The `actions` language supports PrintAST and PrintCFG only (no call graph queries).\n\n## Recommended Workflow\n\nUse the `tools_query_workflow` prompt for a guided step-by-step workflow:\n\n1. **Identify or create a database**: Use `list_codeql_databases` or `codeql_database_create`\n2. **Run PrintAST**: Understand how the source code maps to QL classes\n3. **Run PrintCFG**: Understand control flow for the functions of interest\n4. **Run CallGraphFrom / CallGraphTo**: Trace call relationships to identify sources and sinks\n5. **Run CallGraphFromTo**: Verify specific source-to-sink call paths\n6. **Write detection queries**: Use the insights from steps 2\u20135 to select the right QL classes and predicates\n\n## Related Resources\n\n- `codeql://learning/query-basics` \u2014 QL query writing reference (syntax, metadata, patterns, testing)\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n';
|
|
197311
197548
|
|
|
197312
197549
|
// src/resources/server-tools.md
|
|
197313
|
-
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------- |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
197550
|
+
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------- | ---------------------------------------------------------------------------------------------------- |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_deduplicate_rules` | Find duplicate rules across two SARIF files using fingerprint-first, full-path-fallback overlap |\n| `sarif_diff_by_commits` | Correlate SARIF results with a git diff to classify findings as "new" or "pre-existing" |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_store` | Cache SARIF content in the session store and return a cache key for use by downstream SARIF tools |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `sarif_diff_by_commits` \u2014 correlate SARIF results with git diff to triage new vs pre-existing\n9. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
197314
197551
|
|
|
197315
197552
|
// src/lib/resources.ts
|
|
197316
197553
|
function getLearningQueryBasics() {
|
|
@@ -197547,7 +197784,7 @@ import { pathToFileURL as pathToFileURL3 } from "url";
|
|
|
197547
197784
|
// src/tools/lsp/lsp-server-helper.ts
|
|
197548
197785
|
init_server_manager();
|
|
197549
197786
|
init_logger();
|
|
197550
|
-
import { isAbsolute as
|
|
197787
|
+
import { isAbsolute as isAbsolute6, resolve as resolve11 } from "path";
|
|
197551
197788
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
197552
197789
|
async function getInitializedLanguageServer(opts = {}) {
|
|
197553
197790
|
const { packageRootDir: pkgRoot, getUserWorkspaceDir: getUserWorkspaceDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
@@ -197563,7 +197800,7 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
197563
197800
|
const server = await manager.getLanguageServer(config2);
|
|
197564
197801
|
let effectiveUri = opts.workspaceUri;
|
|
197565
197802
|
if (effectiveUri && !effectiveUri.startsWith("file://")) {
|
|
197566
|
-
const absWorkspace =
|
|
197803
|
+
const absWorkspace = isAbsolute6(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
|
|
197567
197804
|
effectiveUri = pathToFileURL2(absWorkspace).href;
|
|
197568
197805
|
}
|
|
197569
197806
|
effectiveUri = effectiveUri ?? pathToFileURL2(resolve11(pkgRoot, "ql")).href;
|
|
@@ -197728,7 +197965,7 @@ function registerLspDiagnosticsTool(server) {
|
|
|
197728
197965
|
init_logger();
|
|
197729
197966
|
init_package_paths();
|
|
197730
197967
|
import { readFile as readFile3 } from "fs/promises";
|
|
197731
|
-
import { isAbsolute as
|
|
197968
|
+
import { isAbsolute as isAbsolute7, resolve as resolve12 } from "path";
|
|
197732
197969
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
197733
197970
|
async function getInitializedServer(params) {
|
|
197734
197971
|
return getInitializedLanguageServer({
|
|
@@ -197737,7 +197974,7 @@ async function getInitializedServer(params) {
|
|
|
197737
197974
|
});
|
|
197738
197975
|
}
|
|
197739
197976
|
function prepareDocumentPosition(params) {
|
|
197740
|
-
const absPath =
|
|
197977
|
+
const absPath = isAbsolute7(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
|
|
197741
197978
|
const docUri = pathToFileURL4(absPath).href;
|
|
197742
197979
|
return { absPath, docUri };
|
|
197743
197980
|
}
|
|
@@ -198167,7 +198404,7 @@ function registerLanguageResources(server) {
|
|
|
198167
198404
|
|
|
198168
198405
|
// src/prompts/workflow-prompts.ts
|
|
198169
198406
|
import { access as access2 } from "fs/promises";
|
|
198170
|
-
import { basename as
|
|
198407
|
+
import { basename as basename10, isAbsolute as isAbsolute8, normalize, relative as relative3, resolve as resolve13, sep as sep4 } from "path";
|
|
198171
198408
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
198172
198409
|
|
|
198173
198410
|
// src/prompts/constants.ts
|
|
@@ -198187,13 +198424,13 @@ var SUPPORTED_LANGUAGES = [
|
|
|
198187
198424
|
// src/prompts/prompt-completions.ts
|
|
198188
198425
|
import { readdir, readFile as readFile4 } from "fs/promises";
|
|
198189
198426
|
import { homedir as homedir2 } from "os";
|
|
198190
|
-
import { dirname as dirname9, join as join22, relative, sep as
|
|
198427
|
+
import { dirname as dirname9, join as join22, relative as relative2, sep as sep3 } from "path";
|
|
198191
198428
|
init_logger();
|
|
198192
198429
|
init_package_paths();
|
|
198193
198430
|
var MAX_FILE_COMPLETIONS = 50;
|
|
198194
198431
|
var MAX_SCAN_DEPTH = 8;
|
|
198195
198432
|
var CACHE_TTL_MS = 5e3;
|
|
198196
|
-
var
|
|
198433
|
+
var SKIP_DIRS2 = getScanExcludeDirs();
|
|
198197
198434
|
var scanCache = /* @__PURE__ */ new Map();
|
|
198198
198435
|
function getCachedResults(cacheKey2) {
|
|
198199
198436
|
const entry = scanCache.get(cacheKey2);
|
|
@@ -198221,14 +198458,14 @@ async function findFilesByExtension(dir, baseDir, extensions, maxDepth, results)
|
|
|
198221
198458
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198222
198459
|
const fullPath = join22(dir, entry.name);
|
|
198223
198460
|
if (entry.isDirectory()) {
|
|
198224
|
-
if (
|
|
198461
|
+
if (SKIP_DIRS2.has(entry.name)) {
|
|
198225
198462
|
continue;
|
|
198226
198463
|
}
|
|
198227
198464
|
await findFilesByExtension(fullPath, baseDir, extensions, maxDepth - 1, results);
|
|
198228
198465
|
} else if (entry.isFile()) {
|
|
198229
198466
|
const lower = entry.name.toLowerCase();
|
|
198230
198467
|
if (extensions.some((ext) => lower.endsWith(ext))) {
|
|
198231
|
-
results.push(
|
|
198468
|
+
results.push(relative2(baseDir, fullPath));
|
|
198232
198469
|
}
|
|
198233
198470
|
}
|
|
198234
198471
|
}
|
|
@@ -198312,7 +198549,7 @@ async function completeDatabasePath(value) {
|
|
|
198312
198549
|
}
|
|
198313
198550
|
const lower = (value || "").toLowerCase();
|
|
198314
198551
|
const filtered = allResults.filter((p) => {
|
|
198315
|
-
const lastSeg = p.split(
|
|
198552
|
+
const lastSeg = p.split(sep3).pop() ?? "";
|
|
198316
198553
|
return p.toLowerCase().includes(lower) || lastSeg.toLowerCase().includes(lower);
|
|
198317
198554
|
}).sort();
|
|
198318
198555
|
return filtered.slice(0, MAX_FILE_COMPLETIONS);
|
|
@@ -198334,7 +198571,7 @@ async function findDatabaseDirs(dir, _baseDir, maxDepth, results) {
|
|
|
198334
198571
|
}
|
|
198335
198572
|
for (const entry of entries) {
|
|
198336
198573
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198337
|
-
if (entry.isDirectory() && !
|
|
198574
|
+
if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
|
|
198338
198575
|
await findDatabaseDirs(join22(dir, entry.name), _baseDir, maxDepth - 1, results);
|
|
198339
198576
|
}
|
|
198340
198577
|
}
|
|
@@ -198357,11 +198594,11 @@ async function completePackRoot(value) {
|
|
|
198357
198594
|
(e) => e.isFile() && e.name === "codeql-pack.yml"
|
|
198358
198595
|
);
|
|
198359
198596
|
if (hasPackYml) {
|
|
198360
|
-
results.push(
|
|
198597
|
+
results.push(relative2(workspace, dir) || ".");
|
|
198361
198598
|
}
|
|
198362
198599
|
for (const entry of entries) {
|
|
198363
198600
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198364
|
-
if (entry.isDirectory() && !
|
|
198601
|
+
if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
|
|
198365
198602
|
await scan(join22(dir, entry.name), depth - 1);
|
|
198366
198603
|
}
|
|
198367
198604
|
}
|
|
@@ -198599,11 +198836,11 @@ async function resolvePromptFilePath(filePath, workspaceRoot) {
|
|
|
198599
198836
|
}
|
|
198600
198837
|
const effectiveRoot = workspaceRoot ?? getUserWorkspaceDir();
|
|
198601
198838
|
const normalizedPath = normalize(effectivePath);
|
|
198602
|
-
const inputWasAbsolute =
|
|
198839
|
+
const inputWasAbsolute = isAbsolute8(normalizedPath);
|
|
198603
198840
|
const absolutePath = inputWasAbsolute ? normalizedPath : resolve13(effectiveRoot, normalizedPath);
|
|
198604
198841
|
if (!inputWasAbsolute) {
|
|
198605
|
-
const rel =
|
|
198606
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
198842
|
+
const rel = relative3(effectiveRoot, absolutePath);
|
|
198843
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute8(rel)) {
|
|
198607
198844
|
return {
|
|
198608
198845
|
blocked: true,
|
|
198609
198846
|
resolvedPath: "",
|
|
@@ -198873,7 +199110,7 @@ ${content}`
|
|
|
198873
199110
|
const langResult = await getEffectiveLanguage("workshop_creation_workflow", language, resolvedQueryPath);
|
|
198874
199111
|
const effectiveLanguage = langResult.language;
|
|
198875
199112
|
if (langResult.warning) warnings.push(langResult.warning);
|
|
198876
|
-
const derivedName = workshopName ||
|
|
199113
|
+
const derivedName = workshopName || basename10(resolvedQueryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
|
|
198877
199114
|
const contextSection = buildWorkshopContext(
|
|
198878
199115
|
resolvedQueryPath,
|
|
198879
199116
|
effectiveLanguage ?? "unknown",
|
|
@@ -200247,13 +200484,6 @@ function generateListRecommendations(sessions) {
|
|
|
200247
200484
|
// src/tools/annotation-tools.ts
|
|
200248
200485
|
init_logger();
|
|
200249
200486
|
function registerAnnotationTools(server) {
|
|
200250
|
-
const config2 = sessionDataManager.getConfig();
|
|
200251
|
-
if (!config2.enableAnnotationTools) {
|
|
200252
|
-
logger.info(
|
|
200253
|
-
"Annotation tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable annotation_* tools."
|
|
200254
|
-
);
|
|
200255
|
-
return;
|
|
200256
|
-
}
|
|
200257
200487
|
registerAnnotationCreateTool(server);
|
|
200258
200488
|
registerAnnotationGetTool(server);
|
|
200259
200489
|
registerAnnotationListTool(server);
|
|
@@ -200388,13 +200618,6 @@ function registerAnnotationSearchTool(server) {
|
|
|
200388
200618
|
init_logger();
|
|
200389
200619
|
var AUDIT_CATEGORY = "audit-finding";
|
|
200390
200620
|
function registerAuditTools(server) {
|
|
200391
|
-
const config2 = sessionDataManager.getConfig();
|
|
200392
|
-
if (!config2.enableAnnotationTools) {
|
|
200393
|
-
logger.info(
|
|
200394
|
-
"Audit tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable audit_* and annotation_* tools."
|
|
200395
|
-
);
|
|
200396
|
-
return;
|
|
200397
|
-
}
|
|
200398
200621
|
registerAuditStoreFindingsTool(server);
|
|
200399
200622
|
registerAuditListFindingsTool(server);
|
|
200400
200623
|
registerAuditAddNotesTool(server);
|
|
@@ -200562,13 +200785,6 @@ function registerAuditClearRepoTool(server) {
|
|
|
200562
200785
|
// src/tools/cache-tools.ts
|
|
200563
200786
|
init_logger();
|
|
200564
200787
|
function registerCacheTools(server) {
|
|
200565
|
-
const config2 = sessionDataManager.getConfig();
|
|
200566
|
-
if (!config2.enableAnnotationTools) {
|
|
200567
|
-
logger.info(
|
|
200568
|
-
"Cache tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable query_results_cache_* tools."
|
|
200569
|
-
);
|
|
200570
|
-
return;
|
|
200571
|
-
}
|
|
200572
200788
|
registerQueryResultsCacheLookupTool(server);
|
|
200573
200789
|
registerQueryResultsCacheRetrieveTool(server);
|
|
200574
200790
|
registerQueryResultsCacheClearTool(server);
|
|
@@ -200615,8 +200831,14 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200615
200831
|
"Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV) and SARIF result indices and file filtering to return only the relevant portion.",
|
|
200616
200832
|
{
|
|
200617
200833
|
cacheKey: external_exports.string().describe("The cache key of the result to retrieve."),
|
|
200618
|
-
lineRange: external_exports.
|
|
200619
|
-
|
|
200834
|
+
lineRange: external_exports.object({
|
|
200835
|
+
start: external_exports.number().int().min(1).describe("First line to include (1-indexed, inclusive)."),
|
|
200836
|
+
end: external_exports.number().int().min(1).describe("Last line to include (1-indexed, inclusive).")
|
|
200837
|
+
}).refine(({ start, end }) => start <= end, { message: "lineRange.start must be <= lineRange.end" }).optional().describe("Line range {start, end} (1-indexed, inclusive). For graphtext/CSV output only."),
|
|
200838
|
+
resultIndices: external_exports.object({
|
|
200839
|
+
start: external_exports.number().int().min(0).describe("First SARIF result index to include (0-indexed, inclusive)."),
|
|
200840
|
+
end: external_exports.number().int().min(0).describe("Last SARIF result index to include (0-indexed, inclusive).")
|
|
200841
|
+
}).refine(({ start, end }) => start <= end, { message: "resultIndices.start must be <= resultIndices.end" }).optional().describe("SARIF result index range {start, end} (0-indexed, inclusive). For SARIF output only."),
|
|
200620
200842
|
fileFilter: external_exports.string().optional().describe("For SARIF: only include results whose file path contains this string."),
|
|
200621
200843
|
maxLines: external_exports.number().int().positive().optional().describe("Maximum number of lines to return for line-based formats (default: 500)."),
|
|
200622
200844
|
maxResults: external_exports.number().int().positive().optional().describe("Maximum number of SARIF results to return (default: 100).")
|
|
@@ -200630,7 +200852,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200630
200852
|
const isSarif = meta.outputFormat.includes("sarif");
|
|
200631
200853
|
if (isSarif) {
|
|
200632
200854
|
const subset2 = store.getCacheSarifSubset(cacheKey2, {
|
|
200633
|
-
resultIndices,
|
|
200855
|
+
resultIndices: resultIndices ? [resultIndices.start, resultIndices.end] : void 0,
|
|
200634
200856
|
fileFilter,
|
|
200635
200857
|
maxResults
|
|
200636
200858
|
});
|
|
@@ -200661,7 +200883,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200661
200883
|
};
|
|
200662
200884
|
}
|
|
200663
200885
|
const subset = store.getCacheContentSubset(cacheKey2, {
|
|
200664
|
-
lineRange,
|
|
200886
|
+
lineRange: lineRange ? [lineRange.start, lineRange.end] : void 0,
|
|
200665
200887
|
maxLines: maxLines ?? 500
|
|
200666
200888
|
});
|
|
200667
200889
|
if (!subset) {
|
|
@@ -200758,26 +200980,25 @@ function registerQueryResultsCacheCompareTool(server) {
|
|
|
200758
200980
|
import { readFileSync as readFileSync13 } from "fs";
|
|
200759
200981
|
init_logger();
|
|
200760
200982
|
function registerSarifTools(server) {
|
|
200761
|
-
|
|
200762
|
-
|
|
200763
|
-
|
|
200764
|
-
|
|
200765
|
-
);
|
|
200766
|
-
return;
|
|
200767
|
-
}
|
|
200983
|
+
registerSarifCompareAlertsTool(server);
|
|
200984
|
+
registerSarifDeduplicateRulesTool(server);
|
|
200985
|
+
registerSarifDiffByCommitsTool(server);
|
|
200986
|
+
registerSarifDiffRunsTool(server);
|
|
200768
200987
|
registerSarifExtractRuleTool(server);
|
|
200769
200988
|
registerSarifListRulesTool(server);
|
|
200770
200989
|
registerSarifRuleToMarkdownTool(server);
|
|
200771
|
-
|
|
200772
|
-
registerSarifDiffRunsTool(server);
|
|
200990
|
+
registerSarifStoreTool(server);
|
|
200773
200991
|
logger.info("Registered SARIF analysis tools");
|
|
200774
200992
|
}
|
|
200775
|
-
function loadSarif(
|
|
200776
|
-
|
|
200777
|
-
|
|
200993
|
+
function loadSarif(opts) {
|
|
200994
|
+
const { cacheKey: cacheKey2, inlineContent, sarifPath } = opts;
|
|
200995
|
+
if (!sarifPath && !cacheKey2 && !inlineContent) {
|
|
200996
|
+
return { error: "No SARIF source provided." };
|
|
200778
200997
|
}
|
|
200779
200998
|
let content;
|
|
200780
|
-
if (
|
|
200999
|
+
if (inlineContent) {
|
|
201000
|
+
content = inlineContent;
|
|
201001
|
+
} else if (cacheKey2) {
|
|
200781
201002
|
const store = sessionDataManager.getStore();
|
|
200782
201003
|
const cached2 = store.getCacheContent(cacheKey2);
|
|
200783
201004
|
if (!cached2) {
|
|
@@ -200821,7 +201042,7 @@ function registerSarifExtractRuleTool(server) {
|
|
|
200821
201042
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200822
201043
|
},
|
|
200823
201044
|
async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
|
|
200824
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201045
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200825
201046
|
if (loaded.error) {
|
|
200826
201047
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200827
201048
|
}
|
|
@@ -200858,7 +201079,7 @@ function registerSarifListRulesTool(server) {
|
|
|
200858
201079
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200859
201080
|
},
|
|
200860
201081
|
async ({ sarifPath, cacheKey: cacheKey2 }) => {
|
|
200861
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201082
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200862
201083
|
if (loaded.error) {
|
|
200863
201084
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200864
201085
|
}
|
|
@@ -200886,7 +201107,7 @@ function registerSarifRuleToMarkdownTool(server) {
|
|
|
200886
201107
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200887
201108
|
},
|
|
200888
201109
|
async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
|
|
200889
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201110
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200890
201111
|
if (loaded.error) {
|
|
200891
201112
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200892
201113
|
}
|
|
@@ -200917,18 +201138,18 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200917
201138
|
});
|
|
200918
201139
|
server.tool(
|
|
200919
201140
|
"sarif_compare_alerts",
|
|
200920
|
-
"Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location,
|
|
201141
|
+
"Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location, full-path, and fingerprint comparison modes.",
|
|
200921
201142
|
{
|
|
200922
201143
|
alertA: alertSpecSchema.describe("First alert to compare."),
|
|
200923
201144
|
alertB: alertSpecSchema.describe("Second alert to compare."),
|
|
200924
|
-
overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity).')
|
|
201145
|
+
overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path", "fingerprint"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity), "fingerprint" (partialFingerprints match, falls back to full-path).')
|
|
200925
201146
|
},
|
|
200926
201147
|
async ({ alertA, alertB, overlapMode }) => {
|
|
200927
|
-
const loadedA = loadSarif(alertA.sarifPath, alertA.cacheKey);
|
|
201148
|
+
const loadedA = loadSarif({ sarifPath: alertA.sarifPath, cacheKey: alertA.cacheKey });
|
|
200928
201149
|
if (loadedA.error) {
|
|
200929
201150
|
return { content: [{ type: "text", text: `Alert A: ${loadedA.error}` }] };
|
|
200930
201151
|
}
|
|
200931
|
-
const loadedB = loadSarif(alertB.sarifPath, alertB.cacheKey);
|
|
201152
|
+
const loadedB = loadSarif({ sarifPath: alertB.sarifPath, cacheKey: alertB.cacheKey });
|
|
200932
201153
|
if (loadedB.error) {
|
|
200933
201154
|
return { content: [{ type: "text", text: `Alert B: ${loadedB.error}` }] };
|
|
200934
201155
|
}
|
|
@@ -200967,6 +201188,12 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200967
201188
|
if (overlap.pathSimilarity !== void 0) {
|
|
200968
201189
|
response.pathSimilarity = overlap.pathSimilarity;
|
|
200969
201190
|
}
|
|
201191
|
+
if (overlap.fingerprintMatch !== void 0) {
|
|
201192
|
+
response.fingerprintMatch = overlap.fingerprintMatch;
|
|
201193
|
+
}
|
|
201194
|
+
if (overlap.matchedFingerprints !== void 0) {
|
|
201195
|
+
response.matchedFingerprints = overlap.matchedFingerprints;
|
|
201196
|
+
}
|
|
200970
201197
|
return {
|
|
200971
201198
|
content: [{
|
|
200972
201199
|
type: "text",
|
|
@@ -200976,6 +201203,81 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200976
201203
|
}
|
|
200977
201204
|
);
|
|
200978
201205
|
}
|
|
201206
|
+
function parseGitDiffOutput(diffOutput) {
|
|
201207
|
+
const files = [];
|
|
201208
|
+
let currentFile = null;
|
|
201209
|
+
for (const line of diffOutput.split(/\r?\n/)) {
|
|
201210
|
+
if (line.startsWith("+++ b/")) {
|
|
201211
|
+
if (currentFile) files.push(currentFile);
|
|
201212
|
+
currentFile = { hunks: [], path: line.substring(6) };
|
|
201213
|
+
continue;
|
|
201214
|
+
}
|
|
201215
|
+
if (currentFile && line.startsWith("@@")) {
|
|
201216
|
+
const match = line.match(/@@ [^ ]+ \+(\d+)(?:,(\d+))? @@/);
|
|
201217
|
+
if (match) {
|
|
201218
|
+
currentFile.hunksParsed = true;
|
|
201219
|
+
const startLine = parseInt(match[1], 10);
|
|
201220
|
+
const lineCount = match[2] !== void 0 ? parseInt(match[2], 10) : 1;
|
|
201221
|
+
if (lineCount > 0) {
|
|
201222
|
+
currentFile.hunks.push({ startLine, lineCount });
|
|
201223
|
+
}
|
|
201224
|
+
}
|
|
201225
|
+
}
|
|
201226
|
+
}
|
|
201227
|
+
if (currentFile) files.push(currentFile);
|
|
201228
|
+
return files;
|
|
201229
|
+
}
|
|
201230
|
+
function registerSarifDiffByCommitsTool(server) {
|
|
201231
|
+
server.tool(
|
|
201232
|
+
"sarif_diff_by_commits",
|
|
201233
|
+
'Correlate SARIF results with a git diff to classify findings as "new" (introduced in the diff) or "pre-existing". Accepts a SARIF file and a git ref range (e.g. "main..HEAD"). Supports file-level or line-level granularity.',
|
|
201234
|
+
{
|
|
201235
|
+
cacheKey: external_exports.string().optional().describe("Cache key to read SARIF from (alternative to sarifPath)."),
|
|
201236
|
+
granularity: external_exports.enum(["file", "line"]).optional().default("file").describe('Matching granularity: "file" classifies any result in a changed file as new; "line" additionally checks that the result line falls within a changed hunk. Default: "file".'),
|
|
201237
|
+
refRange: external_exports.string().describe('Git ref range for the diff (e.g. "main..HEAD", "abc123..def456"). Passed directly to `git diff`.'),
|
|
201238
|
+
repoPath: external_exports.string().optional().describe("Path to the git repository. Defaults to the current working directory."),
|
|
201239
|
+
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
201240
|
+
},
|
|
201241
|
+
async ({ sarifPath, cacheKey: cacheKey2, refRange, repoPath, granularity }) => {
|
|
201242
|
+
if (/^\s*-/.test(refRange) || /\s/.test(refRange)) {
|
|
201243
|
+
return {
|
|
201244
|
+
content: [{
|
|
201245
|
+
type: "text",
|
|
201246
|
+
text: 'Invalid refRange: must not start with "-" or contain whitespace.'
|
|
201247
|
+
}]
|
|
201248
|
+
};
|
|
201249
|
+
}
|
|
201250
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
201251
|
+
if (loaded.error) {
|
|
201252
|
+
return { content: [{ type: "text", text: loaded.error }] };
|
|
201253
|
+
}
|
|
201254
|
+
const { executeCLICommand: executeCLICommand2 } = await Promise.resolve().then(() => (init_cli_executor(), cli_executor_exports));
|
|
201255
|
+
const gitArgs = ["diff", "--unified=0", "--diff-filter=ACMR", "--no-color", refRange];
|
|
201256
|
+
const gitResult = await executeCLICommand2({
|
|
201257
|
+
args: gitArgs,
|
|
201258
|
+
command: "git",
|
|
201259
|
+
cwd: repoPath
|
|
201260
|
+
});
|
|
201261
|
+
if (!gitResult.success) {
|
|
201262
|
+
return {
|
|
201263
|
+
content: [{
|
|
201264
|
+
type: "text",
|
|
201265
|
+
text: `git diff failed: ${gitResult.error ?? gitResult.stderr}`
|
|
201266
|
+
}]
|
|
201267
|
+
};
|
|
201268
|
+
}
|
|
201269
|
+
const diffFiles = parseGitDiffOutput(gitResult.stdout);
|
|
201270
|
+
const g = granularity;
|
|
201271
|
+
const result = diffSarifByCommits(loaded.sarif, diffFiles, refRange, g);
|
|
201272
|
+
return {
|
|
201273
|
+
content: [{
|
|
201274
|
+
type: "text",
|
|
201275
|
+
text: JSON.stringify(result, null, 2)
|
|
201276
|
+
}]
|
|
201277
|
+
};
|
|
201278
|
+
}
|
|
201279
|
+
);
|
|
201280
|
+
}
|
|
200979
201281
|
function registerSarifDiffRunsTool(server) {
|
|
200980
201282
|
server.tool(
|
|
200981
201283
|
"sarif_diff_runs",
|
|
@@ -200989,11 +201291,11 @@ function registerSarifDiffRunsTool(server) {
|
|
|
200989
201291
|
sarifPathB: external_exports.string().optional().describe("Path to the second (comparison) SARIF file.")
|
|
200990
201292
|
},
|
|
200991
201293
|
async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, labelA, labelB }) => {
|
|
200992
|
-
const loadedA = loadSarif(sarifPathA, cacheKeyA);
|
|
201294
|
+
const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
|
|
200993
201295
|
if (loadedA.error) {
|
|
200994
201296
|
return { content: [{ type: "text", text: `Run A: ${loadedA.error}` }] };
|
|
200995
201297
|
}
|
|
200996
|
-
const loadedB = loadSarif(sarifPathB, cacheKeyB);
|
|
201298
|
+
const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
|
|
200997
201299
|
if (loadedB.error) {
|
|
200998
201300
|
return { content: [{ type: "text", text: `Run B: ${loadedB.error}` }] };
|
|
200999
201301
|
}
|
|
@@ -201011,6 +201313,165 @@ function registerSarifDiffRunsTool(server) {
|
|
|
201011
201313
|
}
|
|
201012
201314
|
);
|
|
201013
201315
|
}
|
|
201316
|
+
function registerSarifStoreTool(server) {
|
|
201317
|
+
server.tool(
|
|
201318
|
+
"sarif_store",
|
|
201319
|
+
"Store SARIF content in the session cache for use by other sarif_* tools. Returns a cache key that can be passed to sarifPath/cacheKey parameters of other tools.",
|
|
201320
|
+
{
|
|
201321
|
+
label: external_exports.string().optional().describe('Human-readable label for this SARIF (e.g. "dubbo-java-2025-03").'),
|
|
201322
|
+
sarifContent: external_exports.string().optional().describe("SARIF JSON content as a string (alternative to sarifPath)."),
|
|
201323
|
+
sarifPath: external_exports.string().optional().describe("Path to a SARIF file on disk.")
|
|
201324
|
+
},
|
|
201325
|
+
async ({ sarifContent, sarifPath, label }) => {
|
|
201326
|
+
if (!sarifContent && !sarifPath) {
|
|
201327
|
+
return { content: [{ type: "text", text: "Either sarifContent or sarifPath is required." }] };
|
|
201328
|
+
}
|
|
201329
|
+
let content;
|
|
201330
|
+
if (sarifPath) {
|
|
201331
|
+
try {
|
|
201332
|
+
content = readFileSync13(sarifPath, "utf8");
|
|
201333
|
+
} catch {
|
|
201334
|
+
return { content: [{ type: "text", text: `Failed to read SARIF file: ${sarifPath}` }] };
|
|
201335
|
+
}
|
|
201336
|
+
} else {
|
|
201337
|
+
content = sarifContent;
|
|
201338
|
+
}
|
|
201339
|
+
const loaded = loadSarif({ inlineContent: content });
|
|
201340
|
+
if (loaded.error) {
|
|
201341
|
+
return { content: [{ type: "text", text: loaded.error }] };
|
|
201342
|
+
}
|
|
201343
|
+
const { createHash: createHash3 } = await import("crypto");
|
|
201344
|
+
const hash = createHash3("sha256").update(content).digest("hex").slice(0, 16);
|
|
201345
|
+
const cacheKey2 = `sarif-store-${hash}`;
|
|
201346
|
+
const sarif = loaded.sarif;
|
|
201347
|
+
const resultCount = sarif.runs[0]?.results?.length ?? 0;
|
|
201348
|
+
const ruleCount = sarif.runs[0]?.tool.driver.rules?.length ?? 0;
|
|
201349
|
+
const toolName = sarif.runs[0]?.tool.driver.name ?? "unknown";
|
|
201350
|
+
const store = sessionDataManager.getStore();
|
|
201351
|
+
store.putCacheEntry({
|
|
201352
|
+
cacheKey: cacheKey2,
|
|
201353
|
+
codeqlVersion: sarif.runs[0]?.tool.driver.version ?? "unknown",
|
|
201354
|
+
databasePath: sarifPath ?? "inline",
|
|
201355
|
+
language: "sarif",
|
|
201356
|
+
outputFormat: "sarif",
|
|
201357
|
+
queryName: "sarif_store",
|
|
201358
|
+
queryPath: sarifPath ?? "inline",
|
|
201359
|
+
resultContent: content,
|
|
201360
|
+
resultCount
|
|
201361
|
+
});
|
|
201362
|
+
return {
|
|
201363
|
+
content: [{
|
|
201364
|
+
type: "text",
|
|
201365
|
+
text: JSON.stringify({
|
|
201366
|
+
cacheKey: cacheKey2,
|
|
201367
|
+
label: label ?? null,
|
|
201368
|
+
resultCount,
|
|
201369
|
+
ruleCount,
|
|
201370
|
+
source: sarifPath ? "file" : "inline",
|
|
201371
|
+
toolName
|
|
201372
|
+
}, null, 2)
|
|
201373
|
+
}]
|
|
201374
|
+
};
|
|
201375
|
+
}
|
|
201376
|
+
);
|
|
201377
|
+
}
|
|
201378
|
+
function registerSarifDeduplicateRulesTool(server) {
|
|
201379
|
+
server.tool(
|
|
201380
|
+
"sarif_deduplicate_rules",
|
|
201381
|
+
"Identify duplicate alerts across two SARIF files by comparing rules pairwise. Uses fingerprint matching first, then full-path location overlap as fallback. Useful for cleanup after query changes or pack upgrades.",
|
|
201382
|
+
{
|
|
201383
|
+
cacheKeyA: external_exports.string().optional().describe("Cache key for the first SARIF."),
|
|
201384
|
+
cacheKeyB: external_exports.string().optional().describe("Cache key for the second SARIF."),
|
|
201385
|
+
overlapThreshold: external_exports.number().min(0).max(1).optional().default(0.8).describe("Minimum overlap score (0-1) to consider a rule pair as duplicates. Default: 0.8."),
|
|
201386
|
+
sarifPathA: external_exports.string().optional().describe("Path to the first SARIF file."),
|
|
201387
|
+
sarifPathB: external_exports.string().optional().describe("Path to the second SARIF file.")
|
|
201388
|
+
},
|
|
201389
|
+
async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, overlapThreshold }) => {
|
|
201390
|
+
const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
|
|
201391
|
+
if (loadedA.error) {
|
|
201392
|
+
return { content: [{ type: "text", text: `SARIF A: ${loadedA.error}` }] };
|
|
201393
|
+
}
|
|
201394
|
+
const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
|
|
201395
|
+
if (loadedB.error) {
|
|
201396
|
+
return { content: [{ type: "text", text: `SARIF B: ${loadedB.error}` }] };
|
|
201397
|
+
}
|
|
201398
|
+
const rulesA = listSarifRules(loadedA.sarif);
|
|
201399
|
+
const rulesB = listSarifRules(loadedB.sarif);
|
|
201400
|
+
const duplicateGroups = [];
|
|
201401
|
+
const ruleDataA = /* @__PURE__ */ new Map();
|
|
201402
|
+
for (const rA of rulesA) {
|
|
201403
|
+
if (rA.resultCount === 0) continue;
|
|
201404
|
+
const extracted = extractRuleFromSarif(loadedA.sarif, rA.ruleId);
|
|
201405
|
+
ruleDataA.set(rA.ruleId, {
|
|
201406
|
+
results: extracted.runs[0]?.results ?? [],
|
|
201407
|
+
ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rA.ruleId }
|
|
201408
|
+
});
|
|
201409
|
+
}
|
|
201410
|
+
const ruleDataB = /* @__PURE__ */ new Map();
|
|
201411
|
+
for (const rB of rulesB) {
|
|
201412
|
+
if (rB.resultCount === 0) continue;
|
|
201413
|
+
const extracted = extractRuleFromSarif(loadedB.sarif, rB.ruleId);
|
|
201414
|
+
ruleDataB.set(rB.ruleId, {
|
|
201415
|
+
results: extracted.runs[0]?.results ?? [],
|
|
201416
|
+
ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rB.ruleId }
|
|
201417
|
+
});
|
|
201418
|
+
}
|
|
201419
|
+
for (const rA of rulesA) {
|
|
201420
|
+
const dataA = ruleDataA.get(rA.ruleId);
|
|
201421
|
+
if (!dataA) continue;
|
|
201422
|
+
for (const rB of rulesB) {
|
|
201423
|
+
const dataB = ruleDataB.get(rB.ruleId);
|
|
201424
|
+
if (!dataB) continue;
|
|
201425
|
+
const { results: resultsA, ruleObj: ruleObjA } = dataA;
|
|
201426
|
+
const { results: resultsB, ruleObj: ruleObjB } = dataB;
|
|
201427
|
+
const overlaps = findOverlappingAlerts(resultsA, ruleObjA, resultsB, ruleObjB, "full-path");
|
|
201428
|
+
const matchedAIndices = /* @__PURE__ */ new Set();
|
|
201429
|
+
for (let ai = 0; ai < resultsA.length; ai++) {
|
|
201430
|
+
for (const rResultB of resultsB) {
|
|
201431
|
+
const fpResult = computeFingerprintOverlap(resultsA[ai], rResultB);
|
|
201432
|
+
if (fpResult.fingerprintMatch) {
|
|
201433
|
+
matchedAIndices.add(ai);
|
|
201434
|
+
break;
|
|
201435
|
+
}
|
|
201436
|
+
}
|
|
201437
|
+
}
|
|
201438
|
+
const matchedAlerts = Math.max(overlaps.length, matchedAIndices.size);
|
|
201439
|
+
const minResults = Math.min(resultsA.length, resultsB.length);
|
|
201440
|
+
const cappedMatched = Math.min(matchedAlerts, minResults);
|
|
201441
|
+
const totalUnique = resultsA.length + resultsB.length - cappedMatched;
|
|
201442
|
+
const overlapScore = totalUnique > 0 ? cappedMatched / totalUnique : 0;
|
|
201443
|
+
if (overlapScore >= (overlapThreshold ?? 0.8)) {
|
|
201444
|
+
duplicateGroups.push({
|
|
201445
|
+
matchedAlerts: cappedMatched,
|
|
201446
|
+
overlapScore: Math.round(overlapScore * 1e3) / 1e3,
|
|
201447
|
+
ruleIdA: rA.ruleId,
|
|
201448
|
+
ruleIdB: rB.ruleId,
|
|
201449
|
+
totalA: resultsA.length,
|
|
201450
|
+
totalB: resultsB.length,
|
|
201451
|
+
unmatchedA: Math.max(0, resultsA.length - cappedMatched),
|
|
201452
|
+
unmatchedB: Math.max(0, resultsB.length - cappedMatched)
|
|
201453
|
+
});
|
|
201454
|
+
}
|
|
201455
|
+
}
|
|
201456
|
+
}
|
|
201457
|
+
duplicateGroups.sort((a, b) => b.overlapScore - a.overlapScore);
|
|
201458
|
+
return {
|
|
201459
|
+
content: [{
|
|
201460
|
+
type: "text",
|
|
201461
|
+
text: JSON.stringify({
|
|
201462
|
+
duplicateGroups,
|
|
201463
|
+
summary: {
|
|
201464
|
+
duplicatePairsFound: duplicateGroups.length,
|
|
201465
|
+
overlapThreshold: overlapThreshold ?? 0.8,
|
|
201466
|
+
totalRulesA: rulesA.length,
|
|
201467
|
+
totalRulesB: rulesB.length
|
|
201468
|
+
}
|
|
201469
|
+
}, null, 2)
|
|
201470
|
+
}]
|
|
201471
|
+
};
|
|
201472
|
+
}
|
|
201473
|
+
);
|
|
201474
|
+
}
|
|
201014
201475
|
|
|
201015
201476
|
// src/lib/tool-validation.ts
|
|
201016
201477
|
function formatAllValidationErrors(error2) {
|
|
@@ -201079,7 +201540,7 @@ init_package_paths();
|
|
|
201079
201540
|
init_logger();
|
|
201080
201541
|
import_dotenv.default.config({ path: resolve14(packageRootDir, ".env"), quiet: true });
|
|
201081
201542
|
var PACKAGE_NAME = "codeql-development-mcp-server";
|
|
201082
|
-
var VERSION = "2.25.
|
|
201543
|
+
var VERSION = "2.25.3";
|
|
201083
201544
|
async function startServer(mode = "stdio") {
|
|
201084
201545
|
logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
|
|
201085
201546
|
const codeqlBinary = resolveCodeQLBinary();
|