codeql-development-mcp-server 2.24.2 → 2.24.3-rc2
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 +6 -4
- package/dist/codeql-development-mcp-server.js +1439 -622
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +5 -5
- package/ql/actions/tools/src/codeql-pack.yml +1 -1
- package/ql/cpp/tools/src/codeql-pack.yml +1 -1
- package/ql/csharp/tools/src/codeql-pack.yml +1 -1
- package/ql/go/tools/src/codeql-pack.yml +1 -1
- package/ql/java/tools/src/codeql-pack.yml +1 -1
- package/ql/javascript/tools/src/codeql-pack.yml +1 -1
- package/ql/python/tools/src/codeql-pack.yml +1 -1
- package/ql/ruby/tools/src/codeql-pack.yml +1 -1
- package/ql/swift/tools/src/codeql-pack.yml +1 -1
|
@@ -2991,7 +2991,7 @@ var require_compile = __commonJS({
|
|
|
2991
2991
|
const schOrFunc = root.refs[ref];
|
|
2992
2992
|
if (schOrFunc)
|
|
2993
2993
|
return schOrFunc;
|
|
2994
|
-
let _sch =
|
|
2994
|
+
let _sch = resolve14.call(this, root, ref);
|
|
2995
2995
|
if (_sch === void 0) {
|
|
2996
2996
|
const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
2997
2997
|
const { schemaId } = this.opts;
|
|
@@ -3018,7 +3018,7 @@ var require_compile = __commonJS({
|
|
|
3018
3018
|
function sameSchemaEnv(s1, s2) {
|
|
3019
3019
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3020
3020
|
}
|
|
3021
|
-
function
|
|
3021
|
+
function resolve14(root, ref) {
|
|
3022
3022
|
let sch;
|
|
3023
3023
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3024
3024
|
ref = sch;
|
|
@@ -3593,7 +3593,7 @@ var require_fast_uri = __commonJS({
|
|
|
3593
3593
|
}
|
|
3594
3594
|
return uri;
|
|
3595
3595
|
}
|
|
3596
|
-
function
|
|
3596
|
+
function resolve14(baseURI, relativeURI, options) {
|
|
3597
3597
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3598
3598
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3599
3599
|
schemelessOptions.skipEscape = true;
|
|
@@ -3820,7 +3820,7 @@ var require_fast_uri = __commonJS({
|
|
|
3820
3820
|
var fastUri = {
|
|
3821
3821
|
SCHEMES,
|
|
3822
3822
|
normalize,
|
|
3823
|
-
resolve:
|
|
3823
|
+
resolve: resolve14,
|
|
3824
3824
|
resolveComponent,
|
|
3825
3825
|
equal,
|
|
3826
3826
|
serialize,
|
|
@@ -9611,7 +9611,7 @@ var require_compile2 = __commonJS({
|
|
|
9611
9611
|
const schOrFunc = root.refs[ref];
|
|
9612
9612
|
if (schOrFunc)
|
|
9613
9613
|
return schOrFunc;
|
|
9614
|
-
let _sch =
|
|
9614
|
+
let _sch = resolve14.call(this, root, ref);
|
|
9615
9615
|
if (_sch === void 0) {
|
|
9616
9616
|
const schema2 = (_a = root.localRefs) === null || _a === void 0 ? void 0 : _a[ref];
|
|
9617
9617
|
const { schemaId } = this.opts;
|
|
@@ -9638,7 +9638,7 @@ var require_compile2 = __commonJS({
|
|
|
9638
9638
|
function sameSchemaEnv(s1, s2) {
|
|
9639
9639
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
9640
9640
|
}
|
|
9641
|
-
function
|
|
9641
|
+
function resolve14(root, ref) {
|
|
9642
9642
|
let sch;
|
|
9643
9643
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
9644
9644
|
ref = sch;
|
|
@@ -12713,8 +12713,8 @@ var require_common = __commonJS({
|
|
|
12713
12713
|
}
|
|
12714
12714
|
return debug;
|
|
12715
12715
|
}
|
|
12716
|
-
function extend4(namespace,
|
|
12717
|
-
const newDebug = createDebug(this.namespace + (typeof
|
|
12716
|
+
function extend4(namespace, delimiter6) {
|
|
12717
|
+
const newDebug = createDebug(this.namespace + (typeof delimiter6 === "undefined" ? ":" : delimiter6) + namespace);
|
|
12718
12718
|
newDebug.log = this.log;
|
|
12719
12719
|
return newDebug;
|
|
12720
12720
|
}
|
|
@@ -17919,10 +17919,10 @@ var require_raw_body = __commonJS({
|
|
|
17919
17919
|
if (done) {
|
|
17920
17920
|
return readStream(stream, encoding, length, limit, wrap(done));
|
|
17921
17921
|
}
|
|
17922
|
-
return new Promise(function executor(
|
|
17922
|
+
return new Promise(function executor(resolve14, reject) {
|
|
17923
17923
|
readStream(stream, encoding, length, limit, function onRead(err, buf) {
|
|
17924
17924
|
if (err) return reject(err);
|
|
17925
|
-
|
|
17925
|
+
resolve14(buf);
|
|
17926
17926
|
});
|
|
17927
17927
|
});
|
|
17928
17928
|
}
|
|
@@ -27724,7 +27724,7 @@ var require_mime_types = __commonJS({
|
|
|
27724
27724
|
"../node_modules/mime-types/index.js"(exports) {
|
|
27725
27725
|
"use strict";
|
|
27726
27726
|
var db = require_mime_db();
|
|
27727
|
-
var
|
|
27727
|
+
var extname3 = __require("path").extname;
|
|
27728
27728
|
var mimeScore = require_mimeScore();
|
|
27729
27729
|
var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
|
|
27730
27730
|
var TEXT_TYPE_REGEXP = /^text\//i;
|
|
@@ -27780,7 +27780,7 @@ var require_mime_types = __commonJS({
|
|
|
27780
27780
|
if (!path4 || typeof path4 !== "string") {
|
|
27781
27781
|
return false;
|
|
27782
27782
|
}
|
|
27783
|
-
var extension2 =
|
|
27783
|
+
var extension2 = extname3("x." + path4).toLowerCase().slice(1);
|
|
27784
27784
|
if (!extension2) {
|
|
27785
27785
|
return false;
|
|
27786
27786
|
}
|
|
@@ -31254,16 +31254,16 @@ var require_view = __commonJS({
|
|
|
31254
31254
|
var debug = require_src()("express:view");
|
|
31255
31255
|
var path4 = __require("node:path");
|
|
31256
31256
|
var fs3 = __require("node:fs");
|
|
31257
|
-
var
|
|
31258
|
-
var
|
|
31259
|
-
var
|
|
31257
|
+
var dirname8 = path4.dirname;
|
|
31258
|
+
var basename8 = path4.basename;
|
|
31259
|
+
var extname3 = path4.extname;
|
|
31260
31260
|
var join19 = path4.join;
|
|
31261
|
-
var
|
|
31261
|
+
var resolve14 = path4.resolve;
|
|
31262
31262
|
module.exports = View;
|
|
31263
31263
|
function View(name, options) {
|
|
31264
31264
|
var opts = options || {};
|
|
31265
31265
|
this.defaultEngine = opts.defaultEngine;
|
|
31266
|
-
this.ext =
|
|
31266
|
+
this.ext = extname3(name);
|
|
31267
31267
|
this.name = name;
|
|
31268
31268
|
this.root = opts.root;
|
|
31269
31269
|
if (!this.ext && !this.defaultEngine) {
|
|
@@ -31292,9 +31292,9 @@ var require_view = __commonJS({
|
|
|
31292
31292
|
debug('lookup "%s"', name);
|
|
31293
31293
|
for (var i = 0; i < roots.length && !path5; i++) {
|
|
31294
31294
|
var root = roots[i];
|
|
31295
|
-
var loc =
|
|
31296
|
-
var dir =
|
|
31297
|
-
var file =
|
|
31295
|
+
var loc = resolve14(root, name);
|
|
31296
|
+
var dir = dirname8(loc);
|
|
31297
|
+
var file = basename8(loc);
|
|
31298
31298
|
path5 = this.resolve(dir, file);
|
|
31299
31299
|
}
|
|
31300
31300
|
return path5;
|
|
@@ -31317,14 +31317,14 @@ var require_view = __commonJS({
|
|
|
31317
31317
|
});
|
|
31318
31318
|
sync = false;
|
|
31319
31319
|
};
|
|
31320
|
-
View.prototype.resolve = function
|
|
31320
|
+
View.prototype.resolve = function resolve15(dir, file) {
|
|
31321
31321
|
var ext = this.ext;
|
|
31322
31322
|
var path5 = join19(dir, file);
|
|
31323
31323
|
var stat = tryStat(path5);
|
|
31324
31324
|
if (stat && stat.isFile()) {
|
|
31325
31325
|
return path5;
|
|
31326
31326
|
}
|
|
31327
|
-
path5 = join19(dir,
|
|
31327
|
+
path5 = join19(dir, basename8(file, ext), "index" + ext);
|
|
31328
31328
|
stat = tryStat(path5);
|
|
31329
31329
|
if (stat && stat.isFile()) {
|
|
31330
31330
|
return path5;
|
|
@@ -32564,9 +32564,9 @@ var require_dist2 = __commonJS({
|
|
|
32564
32564
|
return new TokenData(consumeUntil("end"), str2);
|
|
32565
32565
|
}
|
|
32566
32566
|
function compile(path4, options = {}) {
|
|
32567
|
-
const { encode = encodeURIComponent, delimiter:
|
|
32567
|
+
const { encode = encodeURIComponent, delimiter: delimiter6 = DEFAULT_DELIMITER } = options;
|
|
32568
32568
|
const data = typeof path4 === "object" ? path4 : parse4(path4, options);
|
|
32569
|
-
const fn = tokensToFunction(data.tokens,
|
|
32569
|
+
const fn = tokensToFunction(data.tokens, delimiter6, encode);
|
|
32570
32570
|
return function path5(params = {}) {
|
|
32571
32571
|
const [path6, ...missing] = fn(params);
|
|
32572
32572
|
if (missing.length) {
|
|
@@ -32575,8 +32575,8 @@ var require_dist2 = __commonJS({
|
|
|
32575
32575
|
return path6;
|
|
32576
32576
|
};
|
|
32577
32577
|
}
|
|
32578
|
-
function tokensToFunction(tokens,
|
|
32579
|
-
const encoders = tokens.map((token) => tokenToFunction(token,
|
|
32578
|
+
function tokensToFunction(tokens, delimiter6, encode) {
|
|
32579
|
+
const encoders = tokens.map((token) => tokenToFunction(token, delimiter6, encode));
|
|
32580
32580
|
return (data) => {
|
|
32581
32581
|
const result = [""];
|
|
32582
32582
|
for (const encoder of encoders) {
|
|
@@ -32587,11 +32587,11 @@ var require_dist2 = __commonJS({
|
|
|
32587
32587
|
return result;
|
|
32588
32588
|
};
|
|
32589
32589
|
}
|
|
32590
|
-
function tokenToFunction(token,
|
|
32590
|
+
function tokenToFunction(token, delimiter6, encode) {
|
|
32591
32591
|
if (token.type === "text")
|
|
32592
32592
|
return () => [token.value];
|
|
32593
32593
|
if (token.type === "group") {
|
|
32594
|
-
const fn = tokensToFunction(token.tokens,
|
|
32594
|
+
const fn = tokensToFunction(token.tokens, delimiter6, encode);
|
|
32595
32595
|
return (data) => {
|
|
32596
32596
|
const [value, ...missing] = fn(data);
|
|
32597
32597
|
if (!missing.length)
|
|
@@ -32614,7 +32614,7 @@ var require_dist2 = __commonJS({
|
|
|
32614
32614
|
throw new TypeError(`Expected "${token.name}/${index}" to be a string`);
|
|
32615
32615
|
}
|
|
32616
32616
|
return encodeValue(value2);
|
|
32617
|
-
}).join(
|
|
32617
|
+
}).join(delimiter6)
|
|
32618
32618
|
];
|
|
32619
32619
|
};
|
|
32620
32620
|
}
|
|
@@ -32629,14 +32629,14 @@ var require_dist2 = __commonJS({
|
|
|
32629
32629
|
};
|
|
32630
32630
|
}
|
|
32631
32631
|
function match(path4, options = {}) {
|
|
32632
|
-
const { decode = decodeURIComponent, delimiter:
|
|
32632
|
+
const { decode = decodeURIComponent, delimiter: delimiter6 = DEFAULT_DELIMITER } = options;
|
|
32633
32633
|
const { regexp, keys } = pathToRegexp(path4, options);
|
|
32634
32634
|
const decoders = keys.map((key) => {
|
|
32635
32635
|
if (decode === false)
|
|
32636
32636
|
return NOOP_VALUE;
|
|
32637
32637
|
if (key.type === "param")
|
|
32638
32638
|
return decode;
|
|
32639
|
-
return (value) => value.split(
|
|
32639
|
+
return (value) => value.split(delimiter6).map(decode);
|
|
32640
32640
|
});
|
|
32641
32641
|
return function match2(input) {
|
|
32642
32642
|
const m = regexp.exec(input);
|
|
@@ -32655,20 +32655,20 @@ var require_dist2 = __commonJS({
|
|
|
32655
32655
|
};
|
|
32656
32656
|
}
|
|
32657
32657
|
function pathToRegexp(path4, options = {}) {
|
|
32658
|
-
const { delimiter:
|
|
32658
|
+
const { delimiter: delimiter6 = DEFAULT_DELIMITER, end = true, sensitive = false, trailing = true } = options;
|
|
32659
32659
|
const keys = [];
|
|
32660
32660
|
const flags = sensitive ? "" : "i";
|
|
32661
32661
|
const sources = [];
|
|
32662
32662
|
for (const input of pathsToArray(path4, [])) {
|
|
32663
32663
|
const data = typeof input === "object" ? input : parse4(input, options);
|
|
32664
32664
|
for (const tokens of flatten(data.tokens, 0, [])) {
|
|
32665
|
-
sources.push(toRegExpSource(tokens,
|
|
32665
|
+
sources.push(toRegExpSource(tokens, delimiter6, keys, data.originalPath));
|
|
32666
32666
|
}
|
|
32667
32667
|
}
|
|
32668
32668
|
let pattern = `^(?:${sources.join("|")})`;
|
|
32669
32669
|
if (trailing)
|
|
32670
|
-
pattern += `(?:${escape2(
|
|
32671
|
-
pattern += end ? "$" : `(?=${escape2(
|
|
32670
|
+
pattern += `(?:${escape2(delimiter6)}$)?`;
|
|
32671
|
+
pattern += end ? "$" : `(?=${escape2(delimiter6)}|$)`;
|
|
32672
32672
|
const regexp = new RegExp(pattern, flags);
|
|
32673
32673
|
return { regexp, keys };
|
|
32674
32674
|
}
|
|
@@ -32695,7 +32695,7 @@ var require_dist2 = __commonJS({
|
|
|
32695
32695
|
}
|
|
32696
32696
|
yield* flatten(tokens, index + 1, init);
|
|
32697
32697
|
}
|
|
32698
|
-
function toRegExpSource(tokens,
|
|
32698
|
+
function toRegExpSource(tokens, delimiter6, keys, originalPath) {
|
|
32699
32699
|
let result = "";
|
|
32700
32700
|
let backtrack = "";
|
|
32701
32701
|
let isSafeSegmentParam = true;
|
|
@@ -32703,7 +32703,7 @@ var require_dist2 = __commonJS({
|
|
|
32703
32703
|
if (token.type === "text") {
|
|
32704
32704
|
result += escape2(token.value);
|
|
32705
32705
|
backtrack += token.value;
|
|
32706
|
-
isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(
|
|
32706
|
+
isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(delimiter6));
|
|
32707
32707
|
continue;
|
|
32708
32708
|
}
|
|
32709
32709
|
if (token.type === "param" || token.type === "wildcard") {
|
|
@@ -32711,7 +32711,7 @@ var require_dist2 = __commonJS({
|
|
|
32711
32711
|
throw new PathError(`Missing text before "${token.name}" ${token.type}`, originalPath);
|
|
32712
32712
|
}
|
|
32713
32713
|
if (token.type === "param") {
|
|
32714
|
-
result += `(${negate(
|
|
32714
|
+
result += `(${negate(delimiter6, isSafeSegmentParam ? "" : backtrack)}+)`;
|
|
32715
32715
|
} else {
|
|
32716
32716
|
result += `([\\s\\S]+)`;
|
|
32717
32717
|
}
|
|
@@ -32723,16 +32723,16 @@ var require_dist2 = __commonJS({
|
|
|
32723
32723
|
}
|
|
32724
32724
|
return result;
|
|
32725
32725
|
}
|
|
32726
|
-
function negate(
|
|
32726
|
+
function negate(delimiter6, backtrack) {
|
|
32727
32727
|
if (backtrack.length < 2) {
|
|
32728
|
-
if (
|
|
32729
|
-
return `[^${escape2(
|
|
32730
|
-
return `(?:(?!${escape2(
|
|
32728
|
+
if (delimiter6.length < 2)
|
|
32729
|
+
return `[^${escape2(delimiter6 + backtrack)}]`;
|
|
32730
|
+
return `(?:(?!${escape2(delimiter6)})[^${escape2(backtrack)}])`;
|
|
32731
32731
|
}
|
|
32732
|
-
if (
|
|
32733
|
-
return `(?:(?!${escape2(backtrack)})[^${escape2(
|
|
32732
|
+
if (delimiter6.length < 2) {
|
|
32733
|
+
return `(?:(?!${escape2(backtrack)})[^${escape2(delimiter6)}])`;
|
|
32734
32734
|
}
|
|
32735
|
-
return `(?:(?!${escape2(backtrack)}|${escape2(
|
|
32735
|
+
return `(?:(?!${escape2(backtrack)}|${escape2(delimiter6)})[\\s\\S])`;
|
|
32736
32736
|
}
|
|
32737
32737
|
function stringifyTokens(tokens) {
|
|
32738
32738
|
let value = "";
|
|
@@ -33458,7 +33458,7 @@ var require_application = __commonJS({
|
|
|
33458
33458
|
var compileETag = require_utils4().compileETag;
|
|
33459
33459
|
var compileQueryParser = require_utils4().compileQueryParser;
|
|
33460
33460
|
var compileTrust = require_utils4().compileTrust;
|
|
33461
|
-
var
|
|
33461
|
+
var resolve14 = __require("node:path").resolve;
|
|
33462
33462
|
var once = require_once();
|
|
33463
33463
|
var Router = require_router();
|
|
33464
33464
|
var slice = Array.prototype.slice;
|
|
@@ -33512,7 +33512,7 @@ var require_application = __commonJS({
|
|
|
33512
33512
|
this.mountpath = "/";
|
|
33513
33513
|
this.locals.settings = this.settings;
|
|
33514
33514
|
this.set("view", View);
|
|
33515
|
-
this.set("views",
|
|
33515
|
+
this.set("views", resolve14("views"));
|
|
33516
33516
|
this.set("jsonp callback name", "callback");
|
|
33517
33517
|
if (env === "production") {
|
|
33518
33518
|
this.enable("view cache");
|
|
@@ -34608,7 +34608,7 @@ var require_content_disposition = __commonJS({
|
|
|
34608
34608
|
"use strict";
|
|
34609
34609
|
module.exports = contentDisposition;
|
|
34610
34610
|
module.exports.parse = parse4;
|
|
34611
|
-
var
|
|
34611
|
+
var basename8 = __require("path").basename;
|
|
34612
34612
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
34613
34613
|
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
34614
34614
|
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
@@ -34643,9 +34643,9 @@ var require_content_disposition = __commonJS({
|
|
|
34643
34643
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
34644
34644
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
34645
34645
|
}
|
|
34646
|
-
var name =
|
|
34646
|
+
var name = basename8(filename);
|
|
34647
34647
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
34648
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
34648
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename8(fallback);
|
|
34649
34649
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
34650
34650
|
if (hasFallback || !isQuotedString || HEX_ESCAPE_REGEXP.test(name)) {
|
|
34651
34651
|
params["filename*"] = name;
|
|
@@ -34968,10 +34968,10 @@ var require_send = __commonJS({
|
|
|
34968
34968
|
var statuses = require_statuses();
|
|
34969
34969
|
var Stream = __require("stream");
|
|
34970
34970
|
var util2 = __require("util");
|
|
34971
|
-
var
|
|
34971
|
+
var extname3 = path4.extname;
|
|
34972
34972
|
var join19 = path4.join;
|
|
34973
34973
|
var normalize = path4.normalize;
|
|
34974
|
-
var
|
|
34974
|
+
var resolve14 = path4.resolve;
|
|
34975
34975
|
var sep2 = path4.sep;
|
|
34976
34976
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
34977
34977
|
var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
|
|
@@ -35000,7 +35000,7 @@ var require_send = __commonJS({
|
|
|
35000
35000
|
this._maxage = opts.maxAge || opts.maxage;
|
|
35001
35001
|
this._maxage = typeof this._maxage === "string" ? ms(this._maxage) : Number(this._maxage);
|
|
35002
35002
|
this._maxage = !isNaN(this._maxage) ? Math.min(Math.max(0, this._maxage), MAX_MAXAGE) : 0;
|
|
35003
|
-
this._root = opts.root ?
|
|
35003
|
+
this._root = opts.root ? resolve14(opts.root) : null;
|
|
35004
35004
|
}
|
|
35005
35005
|
util2.inherits(SendStream, Stream);
|
|
35006
35006
|
SendStream.prototype.error = function error2(status, err) {
|
|
@@ -35149,7 +35149,7 @@ var require_send = __commonJS({
|
|
|
35149
35149
|
return res;
|
|
35150
35150
|
}
|
|
35151
35151
|
parts = normalize(path5).split(sep2);
|
|
35152
|
-
path5 =
|
|
35152
|
+
path5 = resolve14(path5);
|
|
35153
35153
|
}
|
|
35154
35154
|
if (containsDotFile(parts)) {
|
|
35155
35155
|
debug('%s dotfile "%s"', this._dotfiles, path5);
|
|
@@ -35243,7 +35243,7 @@ var require_send = __commonJS({
|
|
|
35243
35243
|
debug('stat "%s"', path5);
|
|
35244
35244
|
fs3.stat(path5, function onstat(err, stat) {
|
|
35245
35245
|
var pathEndsWithSep = path5[path5.length - 1] === sep2;
|
|
35246
|
-
if (err && err.code === "ENOENT" && !
|
|
35246
|
+
if (err && err.code === "ENOENT" && !extname3(path5) && !pathEndsWithSep) {
|
|
35247
35247
|
return next(err);
|
|
35248
35248
|
}
|
|
35249
35249
|
if (err) return self.onStatError(err);
|
|
@@ -35306,7 +35306,7 @@ var require_send = __commonJS({
|
|
|
35306
35306
|
SendStream.prototype.type = function type2(path5) {
|
|
35307
35307
|
var res = this.res;
|
|
35308
35308
|
if (res.getHeader("Content-Type")) return;
|
|
35309
|
-
var ext =
|
|
35309
|
+
var ext = extname3(path5);
|
|
35310
35310
|
var type3 = mime.contentType(ext) || "application/octet-stream";
|
|
35311
35311
|
debug("content-type %s", type3);
|
|
35312
35312
|
res.setHeader("Content-Type", type3);
|
|
@@ -35526,8 +35526,8 @@ var require_response = __commonJS({
|
|
|
35526
35526
|
var setCharset = require_utils4().setCharset;
|
|
35527
35527
|
var cookie = require_cookie();
|
|
35528
35528
|
var send = require_send();
|
|
35529
|
-
var
|
|
35530
|
-
var
|
|
35529
|
+
var extname3 = path4.extname;
|
|
35530
|
+
var resolve14 = path4.resolve;
|
|
35531
35531
|
var vary = require_vary();
|
|
35532
35532
|
var { Buffer: Buffer2 } = __require("node:buffer");
|
|
35533
35533
|
var res = Object.create(http.ServerResponse.prototype);
|
|
@@ -35733,7 +35733,7 @@ var require_response = __commonJS({
|
|
|
35733
35733
|
}
|
|
35734
35734
|
opts = Object.create(opts);
|
|
35735
35735
|
opts.headers = headers;
|
|
35736
|
-
var fullPath = !opts.root ?
|
|
35736
|
+
var fullPath = !opts.root ? resolve14(path5) : path5;
|
|
35737
35737
|
return this.sendFile(fullPath, opts, done);
|
|
35738
35738
|
};
|
|
35739
35739
|
res.contentType = res.type = function contentType(type2) {
|
|
@@ -35764,7 +35764,7 @@ var require_response = __commonJS({
|
|
|
35764
35764
|
};
|
|
35765
35765
|
res.attachment = function attachment(filename) {
|
|
35766
35766
|
if (filename) {
|
|
35767
|
-
this.type(
|
|
35767
|
+
this.type(extname3(filename));
|
|
35768
35768
|
}
|
|
35769
35769
|
this.set("Content-Disposition", contentDisposition(filename));
|
|
35770
35770
|
return this;
|
|
@@ -35982,7 +35982,7 @@ var require_serve_static = __commonJS({
|
|
|
35982
35982
|
var encodeUrl = require_encodeurl();
|
|
35983
35983
|
var escapeHtml = require_escape_html();
|
|
35984
35984
|
var parseUrl = require_parseurl();
|
|
35985
|
-
var
|
|
35985
|
+
var resolve14 = __require("path").resolve;
|
|
35986
35986
|
var send = require_send();
|
|
35987
35987
|
var url = __require("url");
|
|
35988
35988
|
module.exports = serveStatic;
|
|
@@ -36001,7 +36001,7 @@ var require_serve_static = __commonJS({
|
|
|
36001
36001
|
throw new TypeError("option setHeaders must be function");
|
|
36002
36002
|
}
|
|
36003
36003
|
opts.maxage = opts.maxage || opts.maxAge || 0;
|
|
36004
|
-
opts.root =
|
|
36004
|
+
opts.root = resolve14(root);
|
|
36005
36005
|
var onDirectory = redirect ? createRedirectDirectoryListener() : createNotFoundDirectoryListener();
|
|
36006
36006
|
return function serveStatic2(req, res, next) {
|
|
36007
36007
|
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
@@ -36992,7 +36992,7 @@ var init_temp_dir = __esm({
|
|
|
36992
36992
|
import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "timers";
|
|
36993
36993
|
function waitForProcessReady(child, name, opts) {
|
|
36994
36994
|
const timeoutMs = opts?.timeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
|
|
36995
|
-
return new Promise((
|
|
36995
|
+
return new Promise((resolve14, reject) => {
|
|
36996
36996
|
let settled = false;
|
|
36997
36997
|
const cleanup = () => {
|
|
36998
36998
|
settled = true;
|
|
@@ -37006,13 +37006,13 @@ function waitForProcessReady(child, name, opts) {
|
|
|
37006
37006
|
if (settled) return;
|
|
37007
37007
|
logger.debug(`${name}: ready (stderr output detected)`);
|
|
37008
37008
|
cleanup();
|
|
37009
|
-
|
|
37009
|
+
resolve14();
|
|
37010
37010
|
};
|
|
37011
37011
|
const onStdout = () => {
|
|
37012
37012
|
if (settled) return;
|
|
37013
37013
|
logger.debug(`${name}: ready (stdout output detected)`);
|
|
37014
37014
|
cleanup();
|
|
37015
|
-
|
|
37015
|
+
resolve14();
|
|
37016
37016
|
};
|
|
37017
37017
|
const onError = (error2) => {
|
|
37018
37018
|
if (settled) return;
|
|
@@ -37028,7 +37028,7 @@ function waitForProcessReady(child, name, opts) {
|
|
|
37028
37028
|
if (settled) return;
|
|
37029
37029
|
logger.warn(`${name}: readiness timeout (${timeoutMs} ms) \u2014 proceeding anyway`);
|
|
37030
37030
|
cleanup();
|
|
37031
|
-
|
|
37031
|
+
resolve14();
|
|
37032
37032
|
}, timeoutMs);
|
|
37033
37033
|
child.stderr?.on("data", onStderr);
|
|
37034
37034
|
child.stdout?.on("data", onStdout);
|
|
@@ -37196,7 +37196,7 @@ var init_language_server = __esm({
|
|
|
37196
37196
|
method,
|
|
37197
37197
|
params
|
|
37198
37198
|
};
|
|
37199
|
-
return new Promise((
|
|
37199
|
+
return new Promise((resolve14, reject) => {
|
|
37200
37200
|
const timer = setTimeout3(() => {
|
|
37201
37201
|
if (this.pendingResponses.has(id)) {
|
|
37202
37202
|
this.pendingResponses.delete(id);
|
|
@@ -37210,7 +37210,7 @@ var init_language_server = __esm({
|
|
|
37210
37210
|
},
|
|
37211
37211
|
resolve: (val) => {
|
|
37212
37212
|
clearTimeout3(timer);
|
|
37213
|
-
|
|
37213
|
+
resolve14(val);
|
|
37214
37214
|
}
|
|
37215
37215
|
});
|
|
37216
37216
|
this.sendMessage(message);
|
|
@@ -37299,7 +37299,7 @@ var init_language_server = __esm({
|
|
|
37299
37299
|
throw new Error("Language server is not initialized");
|
|
37300
37300
|
}
|
|
37301
37301
|
const documentUri = uri || pathToFileURL(join2(getProjectTmpDir("lsp-eval"), "eval.ql")).href;
|
|
37302
|
-
return new Promise((
|
|
37302
|
+
return new Promise((resolve14, reject) => {
|
|
37303
37303
|
let diagnosticsReceived = false;
|
|
37304
37304
|
const timeout = setTimeout3(() => {
|
|
37305
37305
|
if (!diagnosticsReceived) {
|
|
@@ -37315,7 +37315,7 @@ var init_language_server = __esm({
|
|
|
37315
37315
|
this.sendNotification("textDocument/didClose", {
|
|
37316
37316
|
textDocument: { uri: documentUri }
|
|
37317
37317
|
});
|
|
37318
|
-
|
|
37318
|
+
resolve14(params.diagnostics);
|
|
37319
37319
|
}
|
|
37320
37320
|
};
|
|
37321
37321
|
this.on("diagnostics", diagnosticsHandler);
|
|
@@ -37430,22 +37430,22 @@ var init_language_server = __esm({
|
|
|
37430
37430
|
} catch (error2) {
|
|
37431
37431
|
logger.warn("Error during graceful shutdown:", error2);
|
|
37432
37432
|
}
|
|
37433
|
-
await new Promise((
|
|
37433
|
+
await new Promise((resolve14) => {
|
|
37434
37434
|
const timer = setTimeout3(() => {
|
|
37435
37435
|
if (this.server) {
|
|
37436
37436
|
this.server.kill("SIGTERM");
|
|
37437
37437
|
}
|
|
37438
|
-
|
|
37438
|
+
resolve14();
|
|
37439
37439
|
}, 1e3);
|
|
37440
37440
|
if (this.server) {
|
|
37441
37441
|
this.server.once("exit", () => {
|
|
37442
37442
|
clearTimeout3(timer);
|
|
37443
37443
|
this.server = null;
|
|
37444
|
-
|
|
37444
|
+
resolve14();
|
|
37445
37445
|
});
|
|
37446
37446
|
} else {
|
|
37447
37447
|
clearTimeout3(timer);
|
|
37448
|
-
|
|
37448
|
+
resolve14();
|
|
37449
37449
|
}
|
|
37450
37450
|
});
|
|
37451
37451
|
this.isInitialized = false;
|
|
@@ -37535,8 +37535,8 @@ var init_query_server = __esm({
|
|
|
37535
37535
|
method,
|
|
37536
37536
|
params
|
|
37537
37537
|
};
|
|
37538
|
-
return new Promise((
|
|
37539
|
-
this.pendingRequests.set(id, { reject, resolve:
|
|
37538
|
+
return new Promise((resolve14, reject) => {
|
|
37539
|
+
this.pendingRequests.set(id, { reject, resolve: resolve14 });
|
|
37540
37540
|
try {
|
|
37541
37541
|
this.sendRaw(message);
|
|
37542
37542
|
} catch (error2) {
|
|
@@ -37550,7 +37550,7 @@ var init_query_server = __esm({
|
|
|
37550
37550
|
reject(new Error(`Query server request timeout for method: ${method}`));
|
|
37551
37551
|
}
|
|
37552
37552
|
}, timeoutMs);
|
|
37553
|
-
const originalResolve =
|
|
37553
|
+
const originalResolve = resolve14;
|
|
37554
37554
|
const originalReject = reject;
|
|
37555
37555
|
const wrapped = {
|
|
37556
37556
|
reject: (err) => {
|
|
@@ -37578,23 +37578,23 @@ var init_query_server = __esm({
|
|
|
37578
37578
|
} catch (error2) {
|
|
37579
37579
|
logger.warn("Error during query server graceful shutdown:", error2);
|
|
37580
37580
|
}
|
|
37581
|
-
await new Promise((
|
|
37581
|
+
await new Promise((resolve14) => {
|
|
37582
37582
|
const timer = setTimeout4(() => {
|
|
37583
37583
|
if (this.process) {
|
|
37584
37584
|
this.process.kill("SIGTERM");
|
|
37585
37585
|
this.process = null;
|
|
37586
37586
|
}
|
|
37587
|
-
|
|
37587
|
+
resolve14();
|
|
37588
37588
|
}, 2e3);
|
|
37589
37589
|
if (this.process) {
|
|
37590
37590
|
this.process.once("exit", () => {
|
|
37591
37591
|
clearTimeout4(timer);
|
|
37592
37592
|
this.process = null;
|
|
37593
|
-
|
|
37593
|
+
resolve14();
|
|
37594
37594
|
});
|
|
37595
37595
|
} else {
|
|
37596
37596
|
clearTimeout4(timer);
|
|
37597
|
-
|
|
37597
|
+
resolve14();
|
|
37598
37598
|
}
|
|
37599
37599
|
});
|
|
37600
37600
|
}
|
|
@@ -37755,9 +37755,9 @@ var init_cli_server = __esm({
|
|
|
37755
37755
|
* @returns The stdout output from the command.
|
|
37756
37756
|
*/
|
|
37757
37757
|
runCommand(args) {
|
|
37758
|
-
return new Promise((
|
|
37758
|
+
return new Promise((resolve14, reject) => {
|
|
37759
37759
|
const execute = () => {
|
|
37760
|
-
this.executeCommand({ args, reject, resolve:
|
|
37760
|
+
this.executeCommand({ args, reject, resolve: resolve14 });
|
|
37761
37761
|
};
|
|
37762
37762
|
if (this.commandInProgress) {
|
|
37763
37763
|
this.commandQueue.push(execute);
|
|
@@ -37780,23 +37780,23 @@ var init_cli_server = __esm({
|
|
|
37780
37780
|
} catch (error2) {
|
|
37781
37781
|
logger.warn("Error during CLI server shutdown request:", error2);
|
|
37782
37782
|
}
|
|
37783
|
-
await new Promise((
|
|
37783
|
+
await new Promise((resolve14) => {
|
|
37784
37784
|
const timer = setTimeout5(() => {
|
|
37785
37785
|
if (this.process) {
|
|
37786
37786
|
this.process.kill("SIGTERM");
|
|
37787
37787
|
this.process = null;
|
|
37788
37788
|
}
|
|
37789
|
-
|
|
37789
|
+
resolve14();
|
|
37790
37790
|
}, 2e3);
|
|
37791
37791
|
if (this.process) {
|
|
37792
37792
|
this.process.once("exit", () => {
|
|
37793
37793
|
clearTimeout5(timer);
|
|
37794
37794
|
this.process = null;
|
|
37795
|
-
|
|
37795
|
+
resolve14();
|
|
37796
37796
|
});
|
|
37797
37797
|
} else {
|
|
37798
37798
|
clearTimeout5(timer);
|
|
37799
|
-
|
|
37799
|
+
resolve14();
|
|
37800
37800
|
}
|
|
37801
37801
|
});
|
|
37802
37802
|
this.commandInProgress = false;
|
|
@@ -38041,11 +38041,11 @@ var init_server_manager = __esm({
|
|
|
38041
38041
|
async warmUpLanguageServer() {
|
|
38042
38042
|
try {
|
|
38043
38043
|
const { packageRootDir: packageRootDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
38044
|
-
const { resolve:
|
|
38044
|
+
const { resolve: resolve14 } = await import("path");
|
|
38045
38045
|
const config2 = {
|
|
38046
38046
|
checkErrors: "ON_CHANGE",
|
|
38047
38047
|
loglevel: "WARN",
|
|
38048
|
-
searchPath:
|
|
38048
|
+
searchPath: resolve14(packageRootDir2, "ql")
|
|
38049
38049
|
};
|
|
38050
38050
|
logger.info("Warming up language server (background JVM start)...");
|
|
38051
38051
|
await this.getLanguageServer(config2);
|
|
@@ -38159,12 +38159,14 @@ __export(cli_executor_exports, {
|
|
|
38159
38159
|
buildCodeQLArgs: () => buildCodeQLArgs,
|
|
38160
38160
|
buildQLTArgs: () => buildQLTArgs,
|
|
38161
38161
|
disableTestCommands: () => disableTestCommands,
|
|
38162
|
+
discoverVsCodeCodeQLDistribution: () => discoverVsCodeCodeQLDistribution,
|
|
38162
38163
|
enableTestCommands: () => enableTestCommands,
|
|
38163
38164
|
executeCLICommand: () => executeCLICommand,
|
|
38164
38165
|
executeCodeQLCommand: () => executeCodeQLCommand,
|
|
38165
38166
|
executeQLTCommand: () => executeQLTCommand,
|
|
38166
38167
|
getCommandHelp: () => getCommandHelp,
|
|
38167
38168
|
getResolvedCodeQLDir: () => getResolvedCodeQLDir,
|
|
38169
|
+
getVsCodeGlobalStorageCandidates: () => getVsCodeGlobalStorageCandidates,
|
|
38168
38170
|
resetResolvedCodeQLBinary: () => resetResolvedCodeQLBinary,
|
|
38169
38171
|
resolveCodeQLBinary: () => resolveCodeQLBinary,
|
|
38170
38172
|
sanitizeCLIArgument: () => sanitizeCLIArgument,
|
|
@@ -38173,8 +38175,9 @@ __export(cli_executor_exports, {
|
|
|
38173
38175
|
validateCommandExists: () => validateCommandExists
|
|
38174
38176
|
});
|
|
38175
38177
|
import { execFile } from "child_process";
|
|
38176
|
-
import { existsSync as existsSync2 } from "fs";
|
|
38177
|
-
import { basename, delimiter as delimiter4, dirname as dirname2, isAbsolute as isAbsolute2 } from "path";
|
|
38178
|
+
import { accessSync, constants as fsConstants, existsSync as existsSync2, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
|
|
38179
|
+
import { basename, delimiter as delimiter4, dirname as dirname2, isAbsolute as isAbsolute2, join as join4 } from "path";
|
|
38180
|
+
import { homedir } from "os";
|
|
38178
38181
|
import { promisify } from "util";
|
|
38179
38182
|
function enableTestCommands() {
|
|
38180
38183
|
testCommands = /* @__PURE__ */ new Set([
|
|
@@ -38191,12 +38194,103 @@ function disableTestCommands() {
|
|
|
38191
38194
|
function isCommandAllowed(command) {
|
|
38192
38195
|
return ALLOWED_COMMANDS.has(command) || testCommands !== null && testCommands.has(command);
|
|
38193
38196
|
}
|
|
38194
|
-
function
|
|
38197
|
+
function getVsCodeGlobalStorageCandidates() {
|
|
38198
|
+
const home = homedir();
|
|
38199
|
+
const candidates = [];
|
|
38200
|
+
for (const appName of VSCODE_APP_NAMES) {
|
|
38201
|
+
if (process.platform === "darwin") {
|
|
38202
|
+
candidates.push(join4(home, "Library", "Application Support", appName, "User", "globalStorage"));
|
|
38203
|
+
} else if (process.platform === "win32") {
|
|
38204
|
+
const appData = process.env.APPDATA ?? join4(home, "AppData", "Roaming");
|
|
38205
|
+
candidates.push(join4(appData, appName, "User", "globalStorage"));
|
|
38206
|
+
} else {
|
|
38207
|
+
candidates.push(join4(home, ".config", appName, "User", "globalStorage"));
|
|
38208
|
+
}
|
|
38209
|
+
}
|
|
38210
|
+
return candidates;
|
|
38211
|
+
}
|
|
38212
|
+
function discoverVsCodeCodeQLDistribution(candidateStorageRoots) {
|
|
38213
|
+
const globalStorageCandidates = candidateStorageRoots ?? getVsCodeGlobalStorageCandidates();
|
|
38214
|
+
for (const gsRoot of globalStorageCandidates) {
|
|
38215
|
+
for (const dirName of VSCODE_CODEQL_STORAGE_DIR_NAMES) {
|
|
38216
|
+
const codeqlStorage = join4(gsRoot, dirName);
|
|
38217
|
+
if (!existsSync2(codeqlStorage)) continue;
|
|
38218
|
+
const hintResult = discoverFromDistributionJson(codeqlStorage);
|
|
38219
|
+
if (hintResult) return hintResult;
|
|
38220
|
+
const scanResult = discoverFromDistributionScan(codeqlStorage);
|
|
38221
|
+
if (scanResult) return scanResult;
|
|
38222
|
+
}
|
|
38223
|
+
}
|
|
38224
|
+
return void 0;
|
|
38225
|
+
}
|
|
38226
|
+
function discoverFromDistributionJson(codeqlStorage) {
|
|
38227
|
+
try {
|
|
38228
|
+
const jsonPath = join4(codeqlStorage, "distribution.json");
|
|
38229
|
+
if (!existsSync2(jsonPath)) return void 0;
|
|
38230
|
+
const content = readFileSync2(jsonPath, "utf-8");
|
|
38231
|
+
const data = JSON.parse(content);
|
|
38232
|
+
if (typeof data.folderIndex !== "number") return void 0;
|
|
38233
|
+
const binaryPath = join4(
|
|
38234
|
+
codeqlStorage,
|
|
38235
|
+
`distribution${data.folderIndex}`,
|
|
38236
|
+
"codeql",
|
|
38237
|
+
CODEQL_BINARY_NAME
|
|
38238
|
+
);
|
|
38239
|
+
if (isExecutableBinary(binaryPath)) {
|
|
38240
|
+
logger.debug(`Discovered CLI via distribution.json (folderIndex=${data.folderIndex})`);
|
|
38241
|
+
return binaryPath;
|
|
38242
|
+
}
|
|
38243
|
+
logger.debug(`distribution.json hint (folderIndex=${data.folderIndex}) exists but is not a usable executable; falling through to scan`);
|
|
38244
|
+
} catch {
|
|
38245
|
+
}
|
|
38246
|
+
return void 0;
|
|
38247
|
+
}
|
|
38248
|
+
function discoverFromDistributionScan(codeqlStorage) {
|
|
38249
|
+
try {
|
|
38250
|
+
const entries = readdirSync(codeqlStorage, { withFileTypes: true });
|
|
38251
|
+
const distDirs = entries.filter((e) => e.isDirectory() && /^distribution\d+$/.test(e.name)).map((e) => ({
|
|
38252
|
+
name: e.name,
|
|
38253
|
+
num: parseInt(e.name.replace("distribution", ""), 10)
|
|
38254
|
+
})).sort((a, b) => b.num - a.num);
|
|
38255
|
+
for (const dir of distDirs) {
|
|
38256
|
+
const binaryPath = join4(
|
|
38257
|
+
codeqlStorage,
|
|
38258
|
+
dir.name,
|
|
38259
|
+
"codeql",
|
|
38260
|
+
CODEQL_BINARY_NAME
|
|
38261
|
+
);
|
|
38262
|
+
if (isExecutableBinary(binaryPath)) {
|
|
38263
|
+
logger.debug(`Discovered CLI via distribution scan: ${dir.name}`);
|
|
38264
|
+
return binaryPath;
|
|
38265
|
+
}
|
|
38266
|
+
}
|
|
38267
|
+
} catch {
|
|
38268
|
+
}
|
|
38269
|
+
return void 0;
|
|
38270
|
+
}
|
|
38271
|
+
function isExecutableBinary(binaryPath) {
|
|
38272
|
+
try {
|
|
38273
|
+
const stat = statSync(binaryPath);
|
|
38274
|
+
if (!stat.isFile()) return false;
|
|
38275
|
+
accessSync(binaryPath, fsConstants.X_OK);
|
|
38276
|
+
return true;
|
|
38277
|
+
} catch {
|
|
38278
|
+
return false;
|
|
38279
|
+
}
|
|
38280
|
+
}
|
|
38281
|
+
function resolveCodeQLBinary(candidateStorageRoots) {
|
|
38195
38282
|
if (resolvedBinaryResult !== void 0) {
|
|
38196
38283
|
return resolvedBinaryResult;
|
|
38197
38284
|
}
|
|
38198
38285
|
const envPath = process.env.CODEQL_PATH;
|
|
38199
38286
|
if (!envPath) {
|
|
38287
|
+
const discovered = discoverVsCodeCodeQLDistribution(candidateStorageRoots);
|
|
38288
|
+
if (discovered) {
|
|
38289
|
+
resolvedCodeQLDir = dirname2(discovered);
|
|
38290
|
+
resolvedBinaryResult = "codeql";
|
|
38291
|
+
logger.info(`CodeQL CLI auto-discovered via vscode-codeql distribution: ${discovered} (dir: ${resolvedCodeQLDir})`);
|
|
38292
|
+
return resolvedBinaryResult;
|
|
38293
|
+
}
|
|
38200
38294
|
resolvedCodeQLDir = null;
|
|
38201
38295
|
resolvedBinaryResult = "codeql";
|
|
38202
38296
|
return resolvedBinaryResult;
|
|
@@ -38443,7 +38537,7 @@ async function validateCommandExists(command) {
|
|
|
38443
38537
|
return false;
|
|
38444
38538
|
}
|
|
38445
38539
|
}
|
|
38446
|
-
var execFileAsync, ALLOWED_COMMANDS, testCommands, SAFE_ENV_VARS, SAFE_ENV_PREFIXES, DANGEROUS_CONTROL_CHARS, resolvedCodeQLDir, resolvedBinaryResult, FRESH_PROCESS_SUBCOMMANDS;
|
|
38540
|
+
var execFileAsync, ALLOWED_COMMANDS, testCommands, SAFE_ENV_VARS, SAFE_ENV_PREFIXES, DANGEROUS_CONTROL_CHARS, resolvedCodeQLDir, resolvedBinaryResult, CODEQL_BINARY_NAME, VSCODE_APP_NAMES, VSCODE_CODEQL_STORAGE_DIR_NAMES, FRESH_PROCESS_SUBCOMMANDS;
|
|
38447
38541
|
var init_cli_executor = __esm({
|
|
38448
38542
|
"src/lib/cli-executor.ts"() {
|
|
38449
38543
|
"use strict";
|
|
@@ -38492,6 +38586,9 @@ var init_cli_executor = __esm({
|
|
|
38492
38586
|
];
|
|
38493
38587
|
DANGEROUS_CONTROL_CHARS = /[\x01-\x08\x0B\x0C\x0E-\x1F]/;
|
|
38494
38588
|
resolvedCodeQLDir = null;
|
|
38589
|
+
CODEQL_BINARY_NAME = process.platform === "win32" ? "codeql.exe" : "codeql";
|
|
38590
|
+
VSCODE_APP_NAMES = ["Code", "Code - Insiders", "VSCodium"];
|
|
38591
|
+
VSCODE_CODEQL_STORAGE_DIR_NAMES = ["github.vscode-codeql", "GitHub.vscode-codeql"];
|
|
38495
38592
|
FRESH_PROCESS_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
38496
38593
|
"database analyze",
|
|
38497
38594
|
"database create",
|
|
@@ -40826,10 +40923,10 @@ var require_adm_zip = __commonJS({
|
|
|
40826
40923
|
* @param {function|string} [props.namefix] - optional function to help fix filename
|
|
40827
40924
|
*/
|
|
40828
40925
|
addLocalFolderPromise: function(localPath2, props) {
|
|
40829
|
-
return new Promise((
|
|
40926
|
+
return new Promise((resolve14, reject) => {
|
|
40830
40927
|
this.addLocalFolderAsync2(Object.assign({ localPath: localPath2 }, props), (err, done) => {
|
|
40831
40928
|
if (err) reject(err);
|
|
40832
|
-
if (done)
|
|
40929
|
+
if (done) resolve14(this);
|
|
40833
40930
|
});
|
|
40834
40931
|
});
|
|
40835
40932
|
},
|
|
@@ -41016,12 +41113,12 @@ var require_adm_zip = __commonJS({
|
|
|
41016
41113
|
keepOriginalPermission = get_Bool(false, keepOriginalPermission);
|
|
41017
41114
|
overwrite = get_Bool(false, overwrite);
|
|
41018
41115
|
if (!callback) {
|
|
41019
|
-
return new Promise((
|
|
41116
|
+
return new Promise((resolve14, reject) => {
|
|
41020
41117
|
this.extractAllToAsync(targetPath, overwrite, keepOriginalPermission, function(err) {
|
|
41021
41118
|
if (err) {
|
|
41022
41119
|
reject(err);
|
|
41023
41120
|
} else {
|
|
41024
|
-
|
|
41121
|
+
resolve14(this);
|
|
41025
41122
|
}
|
|
41026
41123
|
});
|
|
41027
41124
|
});
|
|
@@ -41119,11 +41216,11 @@ var require_adm_zip = __commonJS({
|
|
|
41119
41216
|
*/
|
|
41120
41217
|
writeZipPromise: function(targetFileName, props) {
|
|
41121
41218
|
const { overwrite, perm } = Object.assign({ overwrite: true }, props);
|
|
41122
|
-
return new Promise((
|
|
41219
|
+
return new Promise((resolve14, reject) => {
|
|
41123
41220
|
if (!targetFileName && opts.filename) targetFileName = opts.filename;
|
|
41124
41221
|
if (!targetFileName) reject("ADM-ZIP: ZIP File Name Missing");
|
|
41125
41222
|
this.toBufferPromise().then((zipData) => {
|
|
41126
|
-
const ret = (done) => done ?
|
|
41223
|
+
const ret = (done) => done ? resolve14(done) : reject("ADM-ZIP: Wasn't able to write zip file");
|
|
41127
41224
|
filetools.writeFileToAsync(targetFileName, zipData, overwrite, perm, ret);
|
|
41128
41225
|
}, reject);
|
|
41129
41226
|
});
|
|
@@ -41132,8 +41229,8 @@ var require_adm_zip = __commonJS({
|
|
|
41132
41229
|
* @returns {Promise<Buffer>} A promise to the Buffer.
|
|
41133
41230
|
*/
|
|
41134
41231
|
toBufferPromise: function() {
|
|
41135
|
-
return new Promise((
|
|
41136
|
-
_zip.toAsyncBuffer(
|
|
41232
|
+
return new Promise((resolve14, reject) => {
|
|
41233
|
+
_zip.toAsyncBuffer(resolve14, reject);
|
|
41137
41234
|
});
|
|
41138
41235
|
},
|
|
41139
41236
|
/**
|
|
@@ -53231,7 +53328,7 @@ var Protocol = class {
|
|
|
53231
53328
|
return;
|
|
53232
53329
|
}
|
|
53233
53330
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
53234
|
-
await new Promise((
|
|
53331
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
53235
53332
|
options?.signal?.throwIfAborted();
|
|
53236
53333
|
}
|
|
53237
53334
|
} catch (error2) {
|
|
@@ -53248,7 +53345,7 @@ var Protocol = class {
|
|
|
53248
53345
|
*/
|
|
53249
53346
|
request(request, resultSchema, options) {
|
|
53250
53347
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
53251
|
-
return new Promise((
|
|
53348
|
+
return new Promise((resolve14, reject) => {
|
|
53252
53349
|
const earlyReject = (error2) => {
|
|
53253
53350
|
reject(error2);
|
|
53254
53351
|
};
|
|
@@ -53326,7 +53423,7 @@ var Protocol = class {
|
|
|
53326
53423
|
if (!parseResult.success) {
|
|
53327
53424
|
reject(parseResult.error);
|
|
53328
53425
|
} else {
|
|
53329
|
-
|
|
53426
|
+
resolve14(parseResult.data);
|
|
53330
53427
|
}
|
|
53331
53428
|
} catch (error2) {
|
|
53332
53429
|
reject(error2);
|
|
@@ -53587,12 +53684,12 @@ var Protocol = class {
|
|
|
53587
53684
|
}
|
|
53588
53685
|
} catch {
|
|
53589
53686
|
}
|
|
53590
|
-
return new Promise((
|
|
53687
|
+
return new Promise((resolve14, reject) => {
|
|
53591
53688
|
if (signal.aborted) {
|
|
53592
53689
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
53593
53690
|
return;
|
|
53594
53691
|
}
|
|
53595
|
-
const timeoutId = setTimeout(
|
|
53692
|
+
const timeoutId = setTimeout(resolve14, interval);
|
|
53596
53693
|
signal.addEventListener("abort", () => {
|
|
53597
53694
|
clearTimeout(timeoutId);
|
|
53598
53695
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -53775,6 +53872,147 @@ var ExperimentalServerTasks = class {
|
|
|
53775
53872
|
requestStream(request, resultSchema, options) {
|
|
53776
53873
|
return this._server.requestStream(request, resultSchema, options);
|
|
53777
53874
|
}
|
|
53875
|
+
/**
|
|
53876
|
+
* Sends a sampling request and returns an AsyncGenerator that yields response messages.
|
|
53877
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
53878
|
+
*
|
|
53879
|
+
* For task-augmented requests, yields 'taskCreated' and 'taskStatus' messages
|
|
53880
|
+
* before the final result.
|
|
53881
|
+
*
|
|
53882
|
+
* @example
|
|
53883
|
+
* ```typescript
|
|
53884
|
+
* const stream = server.experimental.tasks.createMessageStream({
|
|
53885
|
+
* messages: [{ role: 'user', content: { type: 'text', text: 'Hello' } }],
|
|
53886
|
+
* maxTokens: 100
|
|
53887
|
+
* }, {
|
|
53888
|
+
* onprogress: (progress) => {
|
|
53889
|
+
* // Handle streaming tokens via progress notifications
|
|
53890
|
+
* console.log('Progress:', progress.message);
|
|
53891
|
+
* }
|
|
53892
|
+
* });
|
|
53893
|
+
*
|
|
53894
|
+
* for await (const message of stream) {
|
|
53895
|
+
* switch (message.type) {
|
|
53896
|
+
* case 'taskCreated':
|
|
53897
|
+
* console.log('Task created:', message.task.taskId);
|
|
53898
|
+
* break;
|
|
53899
|
+
* case 'taskStatus':
|
|
53900
|
+
* console.log('Task status:', message.task.status);
|
|
53901
|
+
* break;
|
|
53902
|
+
* case 'result':
|
|
53903
|
+
* console.log('Final result:', message.result);
|
|
53904
|
+
* break;
|
|
53905
|
+
* case 'error':
|
|
53906
|
+
* console.error('Error:', message.error);
|
|
53907
|
+
* break;
|
|
53908
|
+
* }
|
|
53909
|
+
* }
|
|
53910
|
+
* ```
|
|
53911
|
+
*
|
|
53912
|
+
* @param params - The sampling request parameters
|
|
53913
|
+
* @param options - Optional request options (timeout, signal, task creation params, onprogress, etc.)
|
|
53914
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
53915
|
+
*
|
|
53916
|
+
* @experimental
|
|
53917
|
+
*/
|
|
53918
|
+
createMessageStream(params, options) {
|
|
53919
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
53920
|
+
if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
|
|
53921
|
+
throw new Error("Client does not support sampling tools capability.");
|
|
53922
|
+
}
|
|
53923
|
+
if (params.messages.length > 0) {
|
|
53924
|
+
const lastMessage = params.messages[params.messages.length - 1];
|
|
53925
|
+
const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
|
|
53926
|
+
const hasToolResults = lastContent.some((c) => c.type === "tool_result");
|
|
53927
|
+
const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : void 0;
|
|
53928
|
+
const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
|
|
53929
|
+
const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
|
|
53930
|
+
if (hasToolResults) {
|
|
53931
|
+
if (lastContent.some((c) => c.type !== "tool_result")) {
|
|
53932
|
+
throw new Error("The last message must contain only tool_result content if any is present");
|
|
53933
|
+
}
|
|
53934
|
+
if (!hasPreviousToolUse) {
|
|
53935
|
+
throw new Error("tool_result blocks are not matching any tool_use from the previous message");
|
|
53936
|
+
}
|
|
53937
|
+
}
|
|
53938
|
+
if (hasPreviousToolUse) {
|
|
53939
|
+
const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
|
|
53940
|
+
const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
|
|
53941
|
+
if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
|
|
53942
|
+
throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
|
|
53943
|
+
}
|
|
53944
|
+
}
|
|
53945
|
+
}
|
|
53946
|
+
return this.requestStream({
|
|
53947
|
+
method: "sampling/createMessage",
|
|
53948
|
+
params
|
|
53949
|
+
}, CreateMessageResultSchema, options);
|
|
53950
|
+
}
|
|
53951
|
+
/**
|
|
53952
|
+
* Sends an elicitation request and returns an AsyncGenerator that yields response messages.
|
|
53953
|
+
* The generator is guaranteed to end with either a 'result' or 'error' message.
|
|
53954
|
+
*
|
|
53955
|
+
* For task-augmented requests (especially URL-based elicitation), yields 'taskCreated'
|
|
53956
|
+
* and 'taskStatus' messages before the final result.
|
|
53957
|
+
*
|
|
53958
|
+
* @example
|
|
53959
|
+
* ```typescript
|
|
53960
|
+
* const stream = server.experimental.tasks.elicitInputStream({
|
|
53961
|
+
* mode: 'url',
|
|
53962
|
+
* message: 'Please authenticate',
|
|
53963
|
+
* elicitationId: 'auth-123',
|
|
53964
|
+
* url: 'https://example.com/auth'
|
|
53965
|
+
* }, {
|
|
53966
|
+
* task: { ttl: 300000 } // Task-augmented for long-running auth flow
|
|
53967
|
+
* });
|
|
53968
|
+
*
|
|
53969
|
+
* for await (const message of stream) {
|
|
53970
|
+
* switch (message.type) {
|
|
53971
|
+
* case 'taskCreated':
|
|
53972
|
+
* console.log('Task created:', message.task.taskId);
|
|
53973
|
+
* break;
|
|
53974
|
+
* case 'taskStatus':
|
|
53975
|
+
* console.log('Task status:', message.task.status);
|
|
53976
|
+
* break;
|
|
53977
|
+
* case 'result':
|
|
53978
|
+
* console.log('User action:', message.result.action);
|
|
53979
|
+
* break;
|
|
53980
|
+
* case 'error':
|
|
53981
|
+
* console.error('Error:', message.error);
|
|
53982
|
+
* break;
|
|
53983
|
+
* }
|
|
53984
|
+
* }
|
|
53985
|
+
* ```
|
|
53986
|
+
*
|
|
53987
|
+
* @param params - The elicitation request parameters
|
|
53988
|
+
* @param options - Optional request options (timeout, signal, task creation params, etc.)
|
|
53989
|
+
* @returns AsyncGenerator that yields ResponseMessage objects
|
|
53990
|
+
*
|
|
53991
|
+
* @experimental
|
|
53992
|
+
*/
|
|
53993
|
+
elicitInputStream(params, options) {
|
|
53994
|
+
const clientCapabilities = this._server.getClientCapabilities();
|
|
53995
|
+
const mode = params.mode ?? "form";
|
|
53996
|
+
switch (mode) {
|
|
53997
|
+
case "url": {
|
|
53998
|
+
if (!clientCapabilities?.elicitation?.url) {
|
|
53999
|
+
throw new Error("Client does not support url elicitation.");
|
|
54000
|
+
}
|
|
54001
|
+
break;
|
|
54002
|
+
}
|
|
54003
|
+
case "form": {
|
|
54004
|
+
if (!clientCapabilities?.elicitation?.form) {
|
|
54005
|
+
throw new Error("Client does not support form elicitation.");
|
|
54006
|
+
}
|
|
54007
|
+
break;
|
|
54008
|
+
}
|
|
54009
|
+
}
|
|
54010
|
+
const normalizedParams = mode === "form" && params.mode === void 0 ? { ...params, mode: "form" } : params;
|
|
54011
|
+
return this.requestStream({
|
|
54012
|
+
method: "elicitation/create",
|
|
54013
|
+
params: normalizedParams
|
|
54014
|
+
}, ElicitResultSchema, options);
|
|
54015
|
+
}
|
|
53778
54016
|
/**
|
|
53779
54017
|
* Gets the current status of a task.
|
|
53780
54018
|
*
|
|
@@ -54551,7 +54789,7 @@ var McpServer = class {
|
|
|
54551
54789
|
let task = createTaskResult.task;
|
|
54552
54790
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
54553
54791
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
54554
|
-
await new Promise((
|
|
54792
|
+
await new Promise((resolve14) => setTimeout(resolve14, pollInterval));
|
|
54555
54793
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
54556
54794
|
if (!updatedTask) {
|
|
54557
54795
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -55194,12 +55432,12 @@ var StdioServerTransport = class {
|
|
|
55194
55432
|
this.onclose?.();
|
|
55195
55433
|
}
|
|
55196
55434
|
send(message) {
|
|
55197
|
-
return new Promise((
|
|
55435
|
+
return new Promise((resolve14) => {
|
|
55198
55436
|
const json2 = serializeMessage(message);
|
|
55199
55437
|
if (this._stdout.write(json2)) {
|
|
55200
|
-
|
|
55438
|
+
resolve14();
|
|
55201
55439
|
} else {
|
|
55202
|
-
this._stdout.once("drain",
|
|
55440
|
+
this._stdout.once("drain", resolve14);
|
|
55203
55441
|
}
|
|
55204
55442
|
});
|
|
55205
55443
|
}
|
|
@@ -55420,15 +55658,17 @@ var Response2 = class _Response {
|
|
|
55420
55658
|
this.#init = init;
|
|
55421
55659
|
}
|
|
55422
55660
|
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
|
55423
|
-
|
|
55424
|
-
this[cacheKey] = [init?.status || 200, body, headers];
|
|
55661
|
+
;
|
|
55662
|
+
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
|
55425
55663
|
}
|
|
55426
55664
|
}
|
|
55427
55665
|
get headers() {
|
|
55428
55666
|
const cache = this[cacheKey];
|
|
55429
55667
|
if (cache) {
|
|
55430
55668
|
if (!(cache[2] instanceof Headers)) {
|
|
55431
|
-
cache[2] = new Headers(
|
|
55669
|
+
cache[2] = new Headers(
|
|
55670
|
+
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
|
55671
|
+
);
|
|
55432
55672
|
}
|
|
55433
55673
|
return cache[2];
|
|
55434
55674
|
}
|
|
@@ -55553,15 +55793,32 @@ var flushHeaders = (outgoing) => {
|
|
|
55553
55793
|
};
|
|
55554
55794
|
var responseViaCache = async (res, outgoing) => {
|
|
55555
55795
|
let [status, body, header] = res[cacheKey];
|
|
55556
|
-
|
|
55796
|
+
let hasContentLength = false;
|
|
55797
|
+
if (!header) {
|
|
55798
|
+
header = { "content-type": "text/plain; charset=UTF-8" };
|
|
55799
|
+
} else if (header instanceof Headers) {
|
|
55800
|
+
hasContentLength = header.has("content-length");
|
|
55557
55801
|
header = buildOutgoingHttpHeaders(header);
|
|
55802
|
+
} else if (Array.isArray(header)) {
|
|
55803
|
+
const headerObj = new Headers(header);
|
|
55804
|
+
hasContentLength = headerObj.has("content-length");
|
|
55805
|
+
header = buildOutgoingHttpHeaders(headerObj);
|
|
55806
|
+
} else {
|
|
55807
|
+
for (const key in header) {
|
|
55808
|
+
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
|
55809
|
+
hasContentLength = true;
|
|
55810
|
+
break;
|
|
55811
|
+
}
|
|
55812
|
+
}
|
|
55558
55813
|
}
|
|
55559
|
-
if (
|
|
55560
|
-
|
|
55561
|
-
|
|
55562
|
-
|
|
55563
|
-
|
|
55564
|
-
|
|
55814
|
+
if (!hasContentLength) {
|
|
55815
|
+
if (typeof body === "string") {
|
|
55816
|
+
header["Content-Length"] = Buffer.byteLength(body);
|
|
55817
|
+
} else if (body instanceof Uint8Array) {
|
|
55818
|
+
header["Content-Length"] = body.byteLength;
|
|
55819
|
+
} else if (body instanceof Blob) {
|
|
55820
|
+
header["Content-Length"] = body.size;
|
|
55821
|
+
}
|
|
55565
55822
|
}
|
|
55566
55823
|
outgoing.writeHead(status, header);
|
|
55567
55824
|
if (typeof body === "string" || body instanceof Uint8Array) {
|
|
@@ -55613,7 +55870,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
|
55613
55870
|
});
|
|
55614
55871
|
if (!chunk) {
|
|
55615
55872
|
if (i === 1) {
|
|
55616
|
-
await new Promise((
|
|
55873
|
+
await new Promise((resolve14) => setTimeout(resolve14));
|
|
55617
55874
|
maxReadCount = 3;
|
|
55618
55875
|
continue;
|
|
55619
55876
|
}
|
|
@@ -55870,6 +56127,7 @@ data:
|
|
|
55870
56127
|
async handleGetRequest(req) {
|
|
55871
56128
|
const acceptHeader = req.headers.get("accept");
|
|
55872
56129
|
if (!acceptHeader?.includes("text/event-stream")) {
|
|
56130
|
+
this.onerror?.(new Error("Not Acceptable: Client must accept text/event-stream"));
|
|
55873
56131
|
return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept text/event-stream");
|
|
55874
56132
|
}
|
|
55875
56133
|
const sessionError = this.validateSession(req);
|
|
@@ -55887,6 +56145,7 @@ data:
|
|
|
55887
56145
|
}
|
|
55888
56146
|
}
|
|
55889
56147
|
if (this._streamMapping.get(this._standaloneSseStreamId) !== void 0) {
|
|
56148
|
+
this.onerror?.(new Error("Conflict: Only one SSE stream is allowed per session"));
|
|
55890
56149
|
return this.createJsonErrorResponse(409, -32e3, "Conflict: Only one SSE stream is allowed per session");
|
|
55891
56150
|
}
|
|
55892
56151
|
const encoder = new TextEncoder();
|
|
@@ -55926,6 +56185,7 @@ data:
|
|
|
55926
56185
|
*/
|
|
55927
56186
|
async replayEvents(lastEventId) {
|
|
55928
56187
|
if (!this._eventStore) {
|
|
56188
|
+
this.onerror?.(new Error("Event store not configured"));
|
|
55929
56189
|
return this.createJsonErrorResponse(400, -32e3, "Event store not configured");
|
|
55930
56190
|
}
|
|
55931
56191
|
try {
|
|
@@ -55933,9 +56193,11 @@ data:
|
|
|
55933
56193
|
if (this._eventStore.getStreamIdForEventId) {
|
|
55934
56194
|
streamId = await this._eventStore.getStreamIdForEventId(lastEventId);
|
|
55935
56195
|
if (!streamId) {
|
|
56196
|
+
this.onerror?.(new Error("Invalid event ID format"));
|
|
55936
56197
|
return this.createJsonErrorResponse(400, -32e3, "Invalid event ID format");
|
|
55937
56198
|
}
|
|
55938
56199
|
if (this._streamMapping.get(streamId) !== void 0) {
|
|
56200
|
+
this.onerror?.(new Error("Conflict: Stream already has an active connection"));
|
|
55939
56201
|
return this.createJsonErrorResponse(409, -32e3, "Conflict: Stream already has an active connection");
|
|
55940
56202
|
}
|
|
55941
56203
|
}
|
|
@@ -56001,7 +56263,8 @@ data:
|
|
|
56001
56263
|
`;
|
|
56002
56264
|
controller.enqueue(encoder.encode(eventData));
|
|
56003
56265
|
return true;
|
|
56004
|
-
} catch {
|
|
56266
|
+
} catch (error2) {
|
|
56267
|
+
this.onerror?.(error2);
|
|
56005
56268
|
return false;
|
|
56006
56269
|
}
|
|
56007
56270
|
}
|
|
@@ -56009,6 +56272,7 @@ data:
|
|
|
56009
56272
|
* Handles unsupported requests (PUT, PATCH, etc.)
|
|
56010
56273
|
*/
|
|
56011
56274
|
handleUnsupportedRequest() {
|
|
56275
|
+
this.onerror?.(new Error("Method not allowed."));
|
|
56012
56276
|
return new Response(JSON.stringify({
|
|
56013
56277
|
jsonrpc: "2.0",
|
|
56014
56278
|
error: {
|
|
@@ -56031,14 +56295,17 @@ data:
|
|
|
56031
56295
|
try {
|
|
56032
56296
|
const acceptHeader = req.headers.get("accept");
|
|
56033
56297
|
if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
|
|
56298
|
+
this.onerror?.(new Error("Not Acceptable: Client must accept both application/json and text/event-stream"));
|
|
56034
56299
|
return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept both application/json and text/event-stream");
|
|
56035
56300
|
}
|
|
56036
56301
|
const ct = req.headers.get("content-type");
|
|
56037
56302
|
if (!ct || !ct.includes("application/json")) {
|
|
56303
|
+
this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json"));
|
|
56038
56304
|
return this.createJsonErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json");
|
|
56039
56305
|
}
|
|
56040
56306
|
const requestInfo = {
|
|
56041
|
-
headers: Object.fromEntries(req.headers.entries())
|
|
56307
|
+
headers: Object.fromEntries(req.headers.entries()),
|
|
56308
|
+
url: new URL(req.url)
|
|
56042
56309
|
};
|
|
56043
56310
|
let rawMessage;
|
|
56044
56311
|
if (options?.parsedBody !== void 0) {
|
|
@@ -56047,6 +56314,7 @@ data:
|
|
|
56047
56314
|
try {
|
|
56048
56315
|
rawMessage = await req.json();
|
|
56049
56316
|
} catch {
|
|
56317
|
+
this.onerror?.(new Error("Parse error: Invalid JSON"));
|
|
56050
56318
|
return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON");
|
|
56051
56319
|
}
|
|
56052
56320
|
}
|
|
@@ -56058,14 +56326,17 @@ data:
|
|
|
56058
56326
|
messages = [JSONRPCMessageSchema.parse(rawMessage)];
|
|
56059
56327
|
}
|
|
56060
56328
|
} catch {
|
|
56329
|
+
this.onerror?.(new Error("Parse error: Invalid JSON-RPC message"));
|
|
56061
56330
|
return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
|
|
56062
56331
|
}
|
|
56063
56332
|
const isInitializationRequest = messages.some(isInitializeRequest);
|
|
56064
56333
|
if (isInitializationRequest) {
|
|
56065
56334
|
if (this._initialized && this.sessionId !== void 0) {
|
|
56335
|
+
this.onerror?.(new Error("Invalid Request: Server already initialized"));
|
|
56066
56336
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized");
|
|
56067
56337
|
}
|
|
56068
56338
|
if (messages.length > 1) {
|
|
56339
|
+
this.onerror?.(new Error("Invalid Request: Only one initialization request is allowed"));
|
|
56069
56340
|
return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed");
|
|
56070
56341
|
}
|
|
56071
56342
|
this.sessionId = this.sessionIdGenerator?.();
|
|
@@ -56095,9 +56366,9 @@ data:
|
|
|
56095
56366
|
const initRequest = messages.find((m) => isInitializeRequest(m));
|
|
56096
56367
|
const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
|
|
56097
56368
|
if (this._enableJsonResponse) {
|
|
56098
|
-
return new Promise((
|
|
56369
|
+
return new Promise((resolve14) => {
|
|
56099
56370
|
this._streamMapping.set(streamId, {
|
|
56100
|
-
resolveJson:
|
|
56371
|
+
resolveJson: resolve14,
|
|
56101
56372
|
cleanup: () => {
|
|
56102
56373
|
this._streamMapping.delete(streamId);
|
|
56103
56374
|
}
|
|
@@ -56191,13 +56462,16 @@ data:
|
|
|
56191
56462
|
return void 0;
|
|
56192
56463
|
}
|
|
56193
56464
|
if (!this._initialized) {
|
|
56465
|
+
this.onerror?.(new Error("Bad Request: Server not initialized"));
|
|
56194
56466
|
return this.createJsonErrorResponse(400, -32e3, "Bad Request: Server not initialized");
|
|
56195
56467
|
}
|
|
56196
56468
|
const sessionId = req.headers.get("mcp-session-id");
|
|
56197
56469
|
if (!sessionId) {
|
|
56470
|
+
this.onerror?.(new Error("Bad Request: Mcp-Session-Id header is required"));
|
|
56198
56471
|
return this.createJsonErrorResponse(400, -32e3, "Bad Request: Mcp-Session-Id header is required");
|
|
56199
56472
|
}
|
|
56200
56473
|
if (sessionId !== this.sessionId) {
|
|
56474
|
+
this.onerror?.(new Error("Session not found"));
|
|
56201
56475
|
return this.createJsonErrorResponse(404, -32001, "Session not found");
|
|
56202
56476
|
}
|
|
56203
56477
|
return void 0;
|
|
@@ -56218,6 +56492,7 @@ data:
|
|
|
56218
56492
|
validateProtocolVersion(req) {
|
|
56219
56493
|
const protocolVersion = req.headers.get("mcp-protocol-version");
|
|
56220
56494
|
if (protocolVersion !== null && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
|
|
56495
|
+
this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`));
|
|
56221
56496
|
return this.createJsonErrorResponse(400, -32e3, `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`);
|
|
56222
56497
|
}
|
|
56223
56498
|
return void 0;
|
|
@@ -56427,8 +56702,8 @@ var StreamableHTTPServerTransport = class {
|
|
|
56427
56702
|
var import_express = __toESM(require_express2(), 1);
|
|
56428
56703
|
var import_cors = __toESM(require_lib3(), 1);
|
|
56429
56704
|
var import_dotenv = __toESM(require_main(), 1);
|
|
56430
|
-
import { realpathSync } from "fs";
|
|
56431
|
-
import { resolve as
|
|
56705
|
+
import { realpathSync as realpathSync2 } from "fs";
|
|
56706
|
+
import { resolve as resolve13 } from "path";
|
|
56432
56707
|
import { pathToFileURL as pathToFileURL5 } from "url";
|
|
56433
56708
|
|
|
56434
56709
|
// src/lib/cli-tool-registry.ts
|
|
@@ -56438,7 +56713,7 @@ init_logger();
|
|
|
56438
56713
|
// src/lib/query-results-evaluator.ts
|
|
56439
56714
|
init_cli_executor();
|
|
56440
56715
|
init_logger();
|
|
56441
|
-
import { writeFileSync, readFileSync as
|
|
56716
|
+
import { writeFileSync, readFileSync as readFileSync3 } from "fs";
|
|
56442
56717
|
import { dirname as dirname3, isAbsolute as isAbsolute3 } from "path";
|
|
56443
56718
|
import { mkdirSync as mkdirSync3 } from "fs";
|
|
56444
56719
|
var BUILT_IN_EVALUATORS = {
|
|
@@ -56448,7 +56723,7 @@ var BUILT_IN_EVALUATORS = {
|
|
|
56448
56723
|
};
|
|
56449
56724
|
async function extractQueryMetadata(queryPath) {
|
|
56450
56725
|
try {
|
|
56451
|
-
const queryContent =
|
|
56726
|
+
const queryContent = readFileSync3(queryPath, "utf-8");
|
|
56452
56727
|
const metadata = {};
|
|
56453
56728
|
const kindMatch = queryContent.match(/@kind\s+([^\s]+)/);
|
|
56454
56729
|
if (kindMatch) metadata.kind = kindMatch[1];
|
|
@@ -56698,7 +56973,7 @@ async function evaluateWithCustomScript(_bqrsPath, _queryPath, _scriptPath, _out
|
|
|
56698
56973
|
// src/lib/log-directory-manager.ts
|
|
56699
56974
|
init_temp_dir();
|
|
56700
56975
|
import { mkdirSync as mkdirSync4, existsSync as existsSync3 } from "fs";
|
|
56701
|
-
import { join as
|
|
56976
|
+
import { join as join5, resolve as resolve3 } from "path";
|
|
56702
56977
|
import { randomBytes } from "crypto";
|
|
56703
56978
|
function ensurePathWithinBase(baseDir, targetPath) {
|
|
56704
56979
|
const absBase = resolve3(baseDir);
|
|
@@ -56722,7 +56997,7 @@ function getOrCreateLogDirectory(logDir) {
|
|
|
56722
56997
|
}
|
|
56723
56998
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
56724
56999
|
const uniqueId = randomBytes(4).toString("hex");
|
|
56725
|
-
const uniqueLogDir =
|
|
57000
|
+
const uniqueLogDir = join5(baseLogDir, `query-run-${timestamp2}-${uniqueId}`);
|
|
56726
57001
|
mkdirSync4(uniqueLogDir, { recursive: true });
|
|
56727
57002
|
return uniqueLogDir;
|
|
56728
57003
|
}
|
|
@@ -56730,8 +57005,41 @@ function getOrCreateLogDirectory(logDir) {
|
|
|
56730
57005
|
// src/lib/cli-tool-registry.ts
|
|
56731
57006
|
init_package_paths();
|
|
56732
57007
|
init_temp_dir();
|
|
56733
|
-
import { writeFileSync as writeFileSync2, rmSync, existsSync as existsSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
56734
|
-
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as
|
|
57008
|
+
import { writeFileSync as writeFileSync2, rmSync, existsSync as existsSync4, mkdirSync as mkdirSync5, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
57009
|
+
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join6, resolve as resolve4 } from "path";
|
|
57010
|
+
function resolveDatabasePath(dbPath) {
|
|
57011
|
+
if (existsSync4(join6(dbPath, "codeql-database.yml"))) {
|
|
57012
|
+
return dbPath;
|
|
57013
|
+
}
|
|
57014
|
+
try {
|
|
57015
|
+
const entries = readdirSync2(dbPath);
|
|
57016
|
+
const candidates = [];
|
|
57017
|
+
for (const entry of entries) {
|
|
57018
|
+
const candidate = join6(dbPath, entry);
|
|
57019
|
+
try {
|
|
57020
|
+
if (statSync2(candidate).isDirectory() && existsSync4(join6(candidate, "codeql-database.yml"))) {
|
|
57021
|
+
candidates.push(candidate);
|
|
57022
|
+
}
|
|
57023
|
+
} catch {
|
|
57024
|
+
}
|
|
57025
|
+
}
|
|
57026
|
+
if (candidates.length === 1) {
|
|
57027
|
+
logger.info(`Resolved database directory: ${dbPath} -> ${candidates[0]}`);
|
|
57028
|
+
return candidates[0];
|
|
57029
|
+
}
|
|
57030
|
+
if (candidates.length > 1) {
|
|
57031
|
+
const names = candidates.map((c) => basename2(c)).join(", ");
|
|
57032
|
+
throw new Error(
|
|
57033
|
+
`Ambiguous database path: ${dbPath} contains multiple databases (${names}). Specify the full path to the desired database subfolder.`
|
|
57034
|
+
);
|
|
57035
|
+
}
|
|
57036
|
+
} catch (err) {
|
|
57037
|
+
if (err instanceof Error && err.message.startsWith("Ambiguous database path")) {
|
|
57038
|
+
throw err;
|
|
57039
|
+
}
|
|
57040
|
+
}
|
|
57041
|
+
return dbPath;
|
|
57042
|
+
}
|
|
56735
57043
|
var defaultCLIResultProcessor = (result, _params) => {
|
|
56736
57044
|
if (!result.success) {
|
|
56737
57045
|
return `Command failed (exit code ${result.exitCode || "unknown"}):
|
|
@@ -56769,7 +57077,7 @@ function registerCLITool(server, definition) {
|
|
|
56769
57077
|
const tempDirsToCleanup = [];
|
|
56770
57078
|
try {
|
|
56771
57079
|
logger.info(`Executing CLI tool: ${name}`, { command, subcommand, params });
|
|
56772
|
-
const formatShouldBePassedToCLI = name === "codeql_bqrs_interpret" || name === "codeql_bqrs_decode" || name === "codeql_bqrs_info" || name === "codeql_generate_query-help" || name === "codeql_database_analyze";
|
|
57080
|
+
const formatShouldBePassedToCLI = name === "codeql_bqrs_interpret" || name === "codeql_bqrs_decode" || name === "codeql_bqrs_info" || name === "codeql_generate_query-help" || name === "codeql_database_analyze" || name === "codeql_resolve_files";
|
|
56773
57081
|
const extractedParams = formatShouldBePassedToCLI ? {
|
|
56774
57082
|
_positional: params._positional || [],
|
|
56775
57083
|
files: params.files,
|
|
@@ -56847,7 +57155,7 @@ function registerCLITool(server, definition) {
|
|
|
56847
57155
|
positionalArgs = [...positionalArgs, qlref];
|
|
56848
57156
|
}
|
|
56849
57157
|
if (options.database && name === "codeql_resolve_database") {
|
|
56850
|
-
positionalArgs = [...positionalArgs, options.database];
|
|
57158
|
+
positionalArgs = [...positionalArgs, resolveDatabasePath(options.database)];
|
|
56851
57159
|
delete options.database;
|
|
56852
57160
|
}
|
|
56853
57161
|
if (options.database && name === "codeql_database_create") {
|
|
@@ -56856,7 +57164,7 @@ function registerCLITool(server, definition) {
|
|
|
56856
57164
|
}
|
|
56857
57165
|
if (name === "codeql_database_analyze") {
|
|
56858
57166
|
if (options.database) {
|
|
56859
|
-
positionalArgs = [...positionalArgs, options.database];
|
|
57167
|
+
positionalArgs = [...positionalArgs, resolveDatabasePath(options.database)];
|
|
56860
57168
|
delete options.database;
|
|
56861
57169
|
}
|
|
56862
57170
|
if (options.queries) {
|
|
@@ -56887,6 +57195,9 @@ function registerCLITool(server, definition) {
|
|
|
56887
57195
|
options.database = resolve4(getUserWorkspaceDir(), options.database);
|
|
56888
57196
|
logger.info(`Resolved database path to: ${options.database}`);
|
|
56889
57197
|
}
|
|
57198
|
+
if (options.database && typeof options.database === "string") {
|
|
57199
|
+
options.database = resolveDatabasePath(options.database);
|
|
57200
|
+
}
|
|
56890
57201
|
const resolvedQuery = await resolveQueryPath(params, logger);
|
|
56891
57202
|
if (resolvedQuery) {
|
|
56892
57203
|
positionalArgs = [...positionalArgs, resolvedQuery];
|
|
@@ -56900,7 +57211,7 @@ function registerCLITool(server, definition) {
|
|
|
56900
57211
|
try {
|
|
56901
57212
|
tempDir = createProjectTempDir("codeql-external-");
|
|
56902
57213
|
tempDirsToCleanup.push(tempDir);
|
|
56903
|
-
csvPath =
|
|
57214
|
+
csvPath = join6(tempDir, "selectedSourceFiles.csv");
|
|
56904
57215
|
const csvContent = filePaths.join("\n") + "\n";
|
|
56905
57216
|
writeFileSync2(csvPath, csvContent, "utf8");
|
|
56906
57217
|
} catch (err) {
|
|
@@ -56920,7 +57231,7 @@ function registerCLITool(server, definition) {
|
|
|
56920
57231
|
try {
|
|
56921
57232
|
tempDir = createProjectTempDir("codeql-external-");
|
|
56922
57233
|
tempDirsToCleanup.push(tempDir);
|
|
56923
|
-
csvPath =
|
|
57234
|
+
csvPath = join6(tempDir, "sourceFunction.csv");
|
|
56924
57235
|
const csvContent = functionNames.join("\n") + "\n";
|
|
56925
57236
|
writeFileSync2(csvPath, csvContent, "utf8");
|
|
56926
57237
|
} catch (err) {
|
|
@@ -56940,7 +57251,7 @@ function registerCLITool(server, definition) {
|
|
|
56940
57251
|
try {
|
|
56941
57252
|
tempDir = createProjectTempDir("codeql-external-");
|
|
56942
57253
|
tempDirsToCleanup.push(tempDir);
|
|
56943
|
-
csvPath =
|
|
57254
|
+
csvPath = join6(tempDir, "targetFunction.csv");
|
|
56944
57255
|
const csvContent = functionNames.join("\n") + "\n";
|
|
56945
57256
|
writeFileSync2(csvPath, csvContent, "utf8");
|
|
56946
57257
|
} catch (err) {
|
|
@@ -56966,6 +57277,11 @@ function registerCLITool(server, definition) {
|
|
|
56966
57277
|
positionalArgs = [...positionalArgs, directory];
|
|
56967
57278
|
}
|
|
56968
57279
|
break;
|
|
57280
|
+
case "codeql_resolve_files":
|
|
57281
|
+
if (dir) {
|
|
57282
|
+
positionalArgs = [...positionalArgs, dir];
|
|
57283
|
+
}
|
|
57284
|
+
break;
|
|
56969
57285
|
default:
|
|
56970
57286
|
break;
|
|
56971
57287
|
}
|
|
@@ -56973,21 +57289,21 @@ function registerCLITool(server, definition) {
|
|
|
56973
57289
|
if (name === "codeql_query_run" || name === "codeql_test_run" || name === "codeql_database_analyze") {
|
|
56974
57290
|
queryLogDir = getOrCreateLogDirectory(customLogDir);
|
|
56975
57291
|
logger.info(`Using log directory for ${name}: ${queryLogDir}`);
|
|
56976
|
-
const timestampPath =
|
|
57292
|
+
const timestampPath = join6(queryLogDir, "timestamp");
|
|
56977
57293
|
writeFileSync2(timestampPath, Date.now().toString(), "utf8");
|
|
56978
57294
|
options.logdir = queryLogDir;
|
|
56979
57295
|
if (!options.verbosity) {
|
|
56980
57296
|
options.verbosity = "progress+";
|
|
56981
57297
|
}
|
|
56982
57298
|
if (!options["evaluator-log"]) {
|
|
56983
|
-
options["evaluator-log"] =
|
|
57299
|
+
options["evaluator-log"] = join6(queryLogDir, "evaluator-log.jsonl");
|
|
56984
57300
|
}
|
|
56985
57301
|
if (options["tuple-counting"] === void 0) {
|
|
56986
57302
|
options["tuple-counting"] = true;
|
|
56987
57303
|
}
|
|
56988
57304
|
if (name === "codeql_query_run") {
|
|
56989
57305
|
if (!options.output) {
|
|
56990
|
-
options.output =
|
|
57306
|
+
options.output = join6(queryLogDir, "results.bqrs");
|
|
56991
57307
|
}
|
|
56992
57308
|
}
|
|
56993
57309
|
if (options.output && typeof options.output === "string") {
|
|
@@ -57018,7 +57334,7 @@ function registerCLITool(server, definition) {
|
|
|
57018
57334
|
}
|
|
57019
57335
|
if (name === "codeql_query_run" && result.success && queryLogDir) {
|
|
57020
57336
|
const bqrsPath = options.output;
|
|
57021
|
-
const sarifPath =
|
|
57337
|
+
const sarifPath = join6(queryLogDir, "results-interpreted.sarif");
|
|
57022
57338
|
const queryFilePath = positionalArgs.length > 0 ? positionalArgs[positionalArgs.length - 1] : void 0;
|
|
57023
57339
|
if (existsSync4(bqrsPath) && queryFilePath) {
|
|
57024
57340
|
try {
|
|
@@ -60439,6 +60755,18 @@ async function findCodeQLQueryFiles(queryFilePath, language, resolveMetadata = t
|
|
|
60439
60755
|
}
|
|
60440
60756
|
const testPackPath = findNearestQlpack(testDir);
|
|
60441
60757
|
const testPackDir = testPackPath ? path.dirname(testPackPath) : testDir;
|
|
60758
|
+
const hints = [];
|
|
60759
|
+
if (!testDirectory.exists) {
|
|
60760
|
+
hints.push("No test directory found. To run this query you will need a user-provided database (databasePath). Test-driven profiling is not available without tests.");
|
|
60761
|
+
} else if (testCodePaths.length === 0) {
|
|
60762
|
+
hints.push("Test directory exists but contains no test source code files. Consider creating test code to enable test-driven workflows.");
|
|
60763
|
+
}
|
|
60764
|
+
if (!expectedResultsPath.exists && testDirectory.exists) {
|
|
60765
|
+
hints.push("No .expected file found. Run codeql_test_run to generate initial expected results, then verify them.");
|
|
60766
|
+
}
|
|
60767
|
+
if (!documentationPath.exists) {
|
|
60768
|
+
hints.push("No query documentation (.md) file found. Use the document_codeql_query prompt to generate one.");
|
|
60769
|
+
}
|
|
60442
60770
|
return {
|
|
60443
60771
|
queryName,
|
|
60444
60772
|
language: detectedLanguage,
|
|
@@ -60461,6 +60789,7 @@ async function findCodeQLQueryFiles(queryFilePath, language, resolveMetadata = t
|
|
|
60461
60789
|
testDatabaseDir: testDatabasePath.path
|
|
60462
60790
|
}
|
|
60463
60791
|
},
|
|
60792
|
+
hints,
|
|
60464
60793
|
metadata,
|
|
60465
60794
|
missingFiles,
|
|
60466
60795
|
packMetadata,
|
|
@@ -60562,15 +60891,16 @@ var codeqlGenerateQueryHelpTool = {
|
|
|
60562
60891
|
};
|
|
60563
60892
|
|
|
60564
60893
|
// src/tools/codeql/list-databases.ts
|
|
60565
|
-
import { existsSync as existsSync6, readdirSync as
|
|
60566
|
-
import { join as
|
|
60894
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
60895
|
+
import { join as join8 } from "path";
|
|
60567
60896
|
|
|
60568
60897
|
// src/lib/discovery-config.ts
|
|
60898
|
+
import { delimiter as delimiter5 } from "path";
|
|
60569
60899
|
function parsePathList(envValue) {
|
|
60570
60900
|
if (!envValue) {
|
|
60571
60901
|
return [];
|
|
60572
60902
|
}
|
|
60573
|
-
return envValue.split(
|
|
60903
|
+
return envValue.split(delimiter5).map((p) => p.trim()).filter((p) => p.length > 0);
|
|
60574
60904
|
}
|
|
60575
60905
|
function getDatabaseBaseDirs() {
|
|
60576
60906
|
return parsePathList(process.env.CODEQL_DATABASES_BASE_DIRS);
|
|
@@ -60586,7 +60916,7 @@ function getQueryRunResultsDirs() {
|
|
|
60586
60916
|
init_logger();
|
|
60587
60917
|
function parseDatabaseYml(ymlPath) {
|
|
60588
60918
|
try {
|
|
60589
|
-
const content =
|
|
60919
|
+
const content = readFileSync5(ymlPath, "utf-8");
|
|
60590
60920
|
const info = {};
|
|
60591
60921
|
for (const line of content.split("\n")) {
|
|
60592
60922
|
const trimmed = line.trim();
|
|
@@ -60619,20 +60949,20 @@ async function discoverDatabases(baseDirs, language) {
|
|
|
60619
60949
|
}
|
|
60620
60950
|
let entries;
|
|
60621
60951
|
try {
|
|
60622
|
-
entries =
|
|
60952
|
+
entries = readdirSync4(baseDir);
|
|
60623
60953
|
} catch {
|
|
60624
60954
|
continue;
|
|
60625
60955
|
}
|
|
60626
60956
|
for (const entry of entries) {
|
|
60627
|
-
const entryPath =
|
|
60957
|
+
const entryPath = join8(baseDir, entry);
|
|
60628
60958
|
try {
|
|
60629
|
-
if (!
|
|
60959
|
+
if (!statSync4(entryPath).isDirectory()) {
|
|
60630
60960
|
continue;
|
|
60631
60961
|
}
|
|
60632
60962
|
} catch {
|
|
60633
60963
|
continue;
|
|
60634
60964
|
}
|
|
60635
|
-
const ymlPath =
|
|
60965
|
+
const ymlPath = join8(entryPath, "codeql-database.yml");
|
|
60636
60966
|
if (!existsSync6(ymlPath)) {
|
|
60637
60967
|
continue;
|
|
60638
60968
|
}
|
|
@@ -60715,8 +61045,8 @@ function registerListDatabasesTool(server) {
|
|
|
60715
61045
|
}
|
|
60716
61046
|
|
|
60717
61047
|
// src/tools/codeql/list-mrva-run-results.ts
|
|
60718
|
-
import { existsSync as existsSync7, readdirSync as
|
|
60719
|
-
import { join as
|
|
61048
|
+
import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync6, statSync as statSync5 } from "fs";
|
|
61049
|
+
import { join as join9 } from "path";
|
|
60720
61050
|
init_logger();
|
|
60721
61051
|
var NUMERIC_DIR_PATTERN = /^\d+$/;
|
|
60722
61052
|
var SKIP_DIRS = /* @__PURE__ */ new Set([".DS_Store", "exported-results"]);
|
|
@@ -60728,14 +61058,14 @@ async function discoverMrvaRunResults(resultsDirs, runId) {
|
|
|
60728
61058
|
}
|
|
60729
61059
|
let entries;
|
|
60730
61060
|
try {
|
|
60731
|
-
entries =
|
|
61061
|
+
entries = readdirSync5(dir);
|
|
60732
61062
|
} catch {
|
|
60733
61063
|
continue;
|
|
60734
61064
|
}
|
|
60735
61065
|
for (const entry of entries) {
|
|
60736
|
-
const entryPath =
|
|
61066
|
+
const entryPath = join9(dir, entry);
|
|
60737
61067
|
try {
|
|
60738
|
-
if (!
|
|
61068
|
+
if (!statSync5(entryPath).isDirectory()) {
|
|
60739
61069
|
continue;
|
|
60740
61070
|
}
|
|
60741
61071
|
} catch {
|
|
@@ -60748,10 +61078,10 @@ async function discoverMrvaRunResults(resultsDirs, runId) {
|
|
|
60748
61078
|
continue;
|
|
60749
61079
|
}
|
|
60750
61080
|
let timestamp2;
|
|
60751
|
-
const timestampPath =
|
|
61081
|
+
const timestampPath = join9(entryPath, "timestamp");
|
|
60752
61082
|
if (existsSync7(timestampPath)) {
|
|
60753
61083
|
try {
|
|
60754
|
-
timestamp2 =
|
|
61084
|
+
timestamp2 = readFileSync6(timestampPath, "utf-8").trim();
|
|
60755
61085
|
} catch {
|
|
60756
61086
|
}
|
|
60757
61087
|
}
|
|
@@ -60770,7 +61100,7 @@ function discoverRepoResults(runPath) {
|
|
|
60770
61100
|
const repos = [];
|
|
60771
61101
|
let ownerEntries;
|
|
60772
61102
|
try {
|
|
60773
|
-
ownerEntries =
|
|
61103
|
+
ownerEntries = readdirSync5(runPath);
|
|
60774
61104
|
} catch {
|
|
60775
61105
|
return repos;
|
|
60776
61106
|
}
|
|
@@ -60778,9 +61108,9 @@ function discoverRepoResults(runPath) {
|
|
|
60778
61108
|
if (SKIP_DIRS.has(ownerEntry)) {
|
|
60779
61109
|
continue;
|
|
60780
61110
|
}
|
|
60781
|
-
const ownerPath =
|
|
61111
|
+
const ownerPath = join9(runPath, ownerEntry);
|
|
60782
61112
|
try {
|
|
60783
|
-
if (!
|
|
61113
|
+
if (!statSync5(ownerPath).isDirectory()) {
|
|
60784
61114
|
continue;
|
|
60785
61115
|
}
|
|
60786
61116
|
} catch {
|
|
@@ -60788,14 +61118,14 @@ function discoverRepoResults(runPath) {
|
|
|
60788
61118
|
}
|
|
60789
61119
|
let repoEntries;
|
|
60790
61120
|
try {
|
|
60791
|
-
repoEntries =
|
|
61121
|
+
repoEntries = readdirSync5(ownerPath);
|
|
60792
61122
|
} catch {
|
|
60793
61123
|
continue;
|
|
60794
61124
|
}
|
|
60795
61125
|
for (const repoEntry of repoEntries) {
|
|
60796
|
-
const repoPath =
|
|
61126
|
+
const repoPath = join9(ownerPath, repoEntry);
|
|
60797
61127
|
try {
|
|
60798
|
-
if (!
|
|
61128
|
+
if (!statSync5(repoPath).isDirectory()) {
|
|
60799
61129
|
continue;
|
|
60800
61130
|
}
|
|
60801
61131
|
} catch {
|
|
@@ -60804,10 +61134,10 @@ function discoverRepoResults(runPath) {
|
|
|
60804
61134
|
const fullName = `${ownerEntry}/${repoEntry}`;
|
|
60805
61135
|
let analysisStatus;
|
|
60806
61136
|
let resultCount;
|
|
60807
|
-
const repoTaskPath =
|
|
61137
|
+
const repoTaskPath = join9(repoPath, "repo_task.json");
|
|
60808
61138
|
if (existsSync7(repoTaskPath)) {
|
|
60809
61139
|
try {
|
|
60810
|
-
const raw =
|
|
61140
|
+
const raw = readFileSync6(repoTaskPath, "utf-8");
|
|
60811
61141
|
const task = JSON.parse(raw);
|
|
60812
61142
|
if (typeof task.analysisStatus === "string") {
|
|
60813
61143
|
analysisStatus = task.analysisStatus;
|
|
@@ -60818,8 +61148,8 @@ function discoverRepoResults(runPath) {
|
|
|
60818
61148
|
} catch {
|
|
60819
61149
|
}
|
|
60820
61150
|
}
|
|
60821
|
-
const hasSarif = existsSync7(
|
|
60822
|
-
const hasBqrs = existsSync7(
|
|
61151
|
+
const hasSarif = existsSync7(join9(repoPath, "results", "results.sarif"));
|
|
61152
|
+
const hasBqrs = existsSync7(join9(repoPath, "results", "results.bqrs"));
|
|
60823
61153
|
repos.push({
|
|
60824
61154
|
analysisStatus,
|
|
60825
61155
|
fullName,
|
|
@@ -60902,8 +61232,8 @@ function registerListMrvaRunResultsTool(server) {
|
|
|
60902
61232
|
}
|
|
60903
61233
|
|
|
60904
61234
|
// src/tools/codeql/list-query-run-results.ts
|
|
60905
|
-
import { existsSync as existsSync8, readdirSync as
|
|
60906
|
-
import { join as
|
|
61235
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
61236
|
+
import { join as join10 } from "path";
|
|
60907
61237
|
init_logger();
|
|
60908
61238
|
var QUERY_RUN_DIR_PATTERN = /^(.+\.ql)-(.+)$/;
|
|
60909
61239
|
var RUN_QUERY_PATTERN = /runQuery called with\s+(\S+)/;
|
|
@@ -60944,14 +61274,14 @@ async function discoverQueryRunResults(resultsDirs, filter) {
|
|
|
60944
61274
|
}
|
|
60945
61275
|
let entries;
|
|
60946
61276
|
try {
|
|
60947
|
-
entries =
|
|
61277
|
+
entries = readdirSync6(dir);
|
|
60948
61278
|
} catch {
|
|
60949
61279
|
continue;
|
|
60950
61280
|
}
|
|
60951
61281
|
for (const entry of entries) {
|
|
60952
|
-
const entryPath =
|
|
61282
|
+
const entryPath = join10(dir, entry);
|
|
60953
61283
|
try {
|
|
60954
|
-
if (!
|
|
61284
|
+
if (!statSync6(entryPath).isDirectory()) {
|
|
60955
61285
|
continue;
|
|
60956
61286
|
}
|
|
60957
61287
|
} catch {
|
|
@@ -60965,23 +61295,23 @@ async function discoverQueryRunResults(resultsDirs, filter) {
|
|
|
60965
61295
|
if (normalizedFilter?.queryName && name !== normalizedFilter.queryName) {
|
|
60966
61296
|
continue;
|
|
60967
61297
|
}
|
|
60968
|
-
const hasEvaluatorLog = existsSync8(
|
|
60969
|
-
const hasBqrs = existsSync8(
|
|
60970
|
-
const hasSarif = existsSync8(
|
|
60971
|
-
const hasQueryLog = existsSync8(
|
|
60972
|
-
const hasSummaryLog = existsSync8(
|
|
61298
|
+
const hasEvaluatorLog = existsSync8(join10(entryPath, "evaluator-log.jsonl"));
|
|
61299
|
+
const hasBqrs = existsSync8(join10(entryPath, "results.bqrs"));
|
|
61300
|
+
const hasSarif = existsSync8(join10(entryPath, "results-interpreted.sarif"));
|
|
61301
|
+
const hasQueryLog = existsSync8(join10(entryPath, "query.log"));
|
|
61302
|
+
const hasSummaryLog = existsSync8(join10(entryPath, "evaluator-log.summary.jsonl"));
|
|
60973
61303
|
let timestamp2;
|
|
60974
|
-
const timestampPath =
|
|
61304
|
+
const timestampPath = join10(entryPath, "timestamp");
|
|
60975
61305
|
if (existsSync8(timestampPath)) {
|
|
60976
61306
|
try {
|
|
60977
|
-
timestamp2 =
|
|
61307
|
+
timestamp2 = readFileSync7(timestampPath, "utf-8").trim();
|
|
60978
61308
|
} catch {
|
|
60979
61309
|
}
|
|
60980
61310
|
}
|
|
60981
61311
|
let metadata = {};
|
|
60982
61312
|
if (hasQueryLog) {
|
|
60983
61313
|
try {
|
|
60984
|
-
const logContent =
|
|
61314
|
+
const logContent = readFileSync7(join10(entryPath, "query.log"), "utf-8");
|
|
60985
61315
|
metadata = parseQueryLogMetadata(logContent);
|
|
60986
61316
|
} catch {
|
|
60987
61317
|
}
|
|
@@ -61089,7 +61419,7 @@ function registerListQueryRunResultsTool(server) {
|
|
|
61089
61419
|
if (run.queryPath) parts.push(` Query: ${run.queryPath}`);
|
|
61090
61420
|
if (run.databasePath) parts.push(` Database: ${run.databasePath}`);
|
|
61091
61421
|
parts.push(` Artifacts: ${artifacts.length > 0 ? artifacts.join(", ") : "none"}`);
|
|
61092
|
-
if (run.hasBqrs) parts.push(` BQRS: ${
|
|
61422
|
+
if (run.hasBqrs) parts.push(` BQRS: ${join10(run.path, "results.bqrs")}`);
|
|
61093
61423
|
return parts.join("\n");
|
|
61094
61424
|
})
|
|
61095
61425
|
];
|
|
@@ -61155,61 +61485,91 @@ var codeqlPackLsTool = {
|
|
|
61155
61485
|
|
|
61156
61486
|
// src/tools/codeql/profile-codeql-query-from-logs.ts
|
|
61157
61487
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
61158
|
-
import { basename as basename4, dirname as dirname6, join as
|
|
61488
|
+
import { basename as basename4, dirname as dirname6, join as join11 } from "path";
|
|
61159
61489
|
|
|
61160
61490
|
// src/lib/evaluator-log-parser.ts
|
|
61161
61491
|
init_logger();
|
|
61162
|
-
import {
|
|
61492
|
+
import { createReadStream } from "fs";
|
|
61493
|
+
import { createInterface } from "readline";
|
|
61163
61494
|
function detectLogFormat(firstEvent) {
|
|
61164
61495
|
if (typeof firstEvent.type === "string") {
|
|
61165
61496
|
return "raw";
|
|
61166
61497
|
}
|
|
61167
61498
|
return "summary";
|
|
61168
61499
|
}
|
|
61169
|
-
function
|
|
61170
|
-
const
|
|
61171
|
-
|
|
61172
|
-
|
|
61173
|
-
}
|
|
61174
|
-
const parts = trimmed.split(/\n\}\s*\n\s*\{/);
|
|
61175
|
-
if (parts.length === 1) {
|
|
61176
|
-
return [trimmed];
|
|
61177
|
-
}
|
|
61178
|
-
return parts.map((part, idx) => {
|
|
61179
|
-
if (idx === 0) {
|
|
61180
|
-
return part + "\n}";
|
|
61181
|
-
}
|
|
61182
|
-
if (idx === parts.length - 1) {
|
|
61183
|
-
return "{\n" + part;
|
|
61184
|
-
}
|
|
61185
|
-
return "{\n" + part + "\n}";
|
|
61500
|
+
async function* streamJsonObjects(logPath) {
|
|
61501
|
+
const rl = createInterface({
|
|
61502
|
+
input: createReadStream(logPath, { encoding: "utf-8" }),
|
|
61503
|
+
crlfDelay: Infinity
|
|
61186
61504
|
});
|
|
61187
|
-
|
|
61188
|
-
|
|
61189
|
-
|
|
61190
|
-
const
|
|
61191
|
-
const
|
|
61192
|
-
|
|
61193
|
-
|
|
61194
|
-
|
|
61195
|
-
|
|
61196
|
-
|
|
61197
|
-
|
|
61198
|
-
|
|
61505
|
+
let depth = 0;
|
|
61506
|
+
let inString = false;
|
|
61507
|
+
let escape2 = false;
|
|
61508
|
+
const lines = [];
|
|
61509
|
+
for await (const line of rl) {
|
|
61510
|
+
for (const ch of line) {
|
|
61511
|
+
if (escape2) {
|
|
61512
|
+
escape2 = false;
|
|
61513
|
+
continue;
|
|
61514
|
+
}
|
|
61515
|
+
if (ch === "\\" && inString) {
|
|
61516
|
+
escape2 = true;
|
|
61517
|
+
continue;
|
|
61518
|
+
}
|
|
61519
|
+
if (ch === '"') {
|
|
61520
|
+
inString = !inString;
|
|
61521
|
+
continue;
|
|
61522
|
+
}
|
|
61523
|
+
if (inString) continue;
|
|
61524
|
+
if (ch === "{") depth++;
|
|
61525
|
+
if (ch === "}") depth--;
|
|
61526
|
+
}
|
|
61527
|
+
if (depth > 0 || depth === 0 && line.trim().length > 0 && lines.length > 0) {
|
|
61528
|
+
lines.push(line);
|
|
61529
|
+
} else if (depth === 0 && lines.length === 0 && line.trim().length > 0) {
|
|
61530
|
+
lines.push(line);
|
|
61531
|
+
}
|
|
61532
|
+
if (depth === 0 && lines.length > 0) {
|
|
61533
|
+
const objStr = lines.join("\n");
|
|
61534
|
+
lines.length = 0;
|
|
61535
|
+
inString = false;
|
|
61536
|
+
escape2 = false;
|
|
61537
|
+
if (objStr.trim().length === 0) continue;
|
|
61538
|
+
try {
|
|
61539
|
+
yield JSON.parse(objStr);
|
|
61540
|
+
} catch {
|
|
61541
|
+
logger.warn(
|
|
61542
|
+
`Failed to parse evaluator log object: ${objStr.substring(0, 120)}...`
|
|
61543
|
+
);
|
|
61544
|
+
}
|
|
61545
|
+
}
|
|
61546
|
+
}
|
|
61547
|
+
if (lines.length > 0) {
|
|
61548
|
+
const objStr = lines.join("\n");
|
|
61549
|
+
if (objStr.trim().length > 0) {
|
|
61550
|
+
try {
|
|
61551
|
+
yield JSON.parse(objStr);
|
|
61552
|
+
} catch {
|
|
61553
|
+
logger.warn(
|
|
61554
|
+
`Failed to parse trailing evaluator log object: ${objStr.substring(0, 120)}...`
|
|
61555
|
+
);
|
|
61556
|
+
}
|
|
61199
61557
|
}
|
|
61200
61558
|
}
|
|
61201
|
-
return results;
|
|
61202
61559
|
}
|
|
61203
|
-
function
|
|
61204
|
-
const events = parseJsonObjects(logPath);
|
|
61560
|
+
async function processRawEvents(events) {
|
|
61205
61561
|
let codeqlVersion;
|
|
61206
61562
|
const queryStartEvents = /* @__PURE__ */ new Map();
|
|
61207
61563
|
const predicateStartEvents = /* @__PURE__ */ new Map();
|
|
61564
|
+
const pipelineStartNanoTimes = /* @__PURE__ */ new Map();
|
|
61565
|
+
const pipelineToPredicateMap = /* @__PURE__ */ new Map();
|
|
61208
61566
|
const queryPredicates = /* @__PURE__ */ new Map();
|
|
61209
61567
|
const queryEndNanoTimes = /* @__PURE__ */ new Map();
|
|
61210
61568
|
const queryCacheHits = /* @__PURE__ */ new Map();
|
|
61211
61569
|
let firstQueryEventId;
|
|
61212
|
-
|
|
61570
|
+
let totalEvents = 0;
|
|
61571
|
+
for await (const event of events) {
|
|
61572
|
+
totalEvents++;
|
|
61213
61573
|
const eventType = event.type;
|
|
61214
61574
|
switch (eventType) {
|
|
61215
61575
|
case "LOG_HEADER": {
|
|
@@ -61238,6 +61598,11 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61238
61598
|
case "PREDICATE_STARTED": {
|
|
61239
61599
|
const eid = event.eventId;
|
|
61240
61600
|
const deps = event.dependencies;
|
|
61601
|
+
const raObj = event.ra;
|
|
61602
|
+
let raSteps;
|
|
61603
|
+
if (raObj && Array.isArray(raObj.pipeline)) {
|
|
61604
|
+
raSteps = raObj.pipeline.map((s) => s.trim());
|
|
61605
|
+
}
|
|
61241
61606
|
predicateStartEvents.set(eid, {
|
|
61242
61607
|
predicateName: event.predicateName || "unknown",
|
|
61243
61608
|
position: event.position,
|
|
@@ -61245,20 +61610,34 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61245
61610
|
dependencies: deps ? Object.keys(deps) : [],
|
|
61246
61611
|
queryCausingWork: event.queryCausingWork,
|
|
61247
61612
|
nanoTime: event.nanoTime,
|
|
61248
|
-
pipelineCount: 0
|
|
61613
|
+
pipelineCount: 0,
|
|
61614
|
+
raSteps,
|
|
61615
|
+
pipelineStages: []
|
|
61249
61616
|
});
|
|
61250
61617
|
break;
|
|
61251
61618
|
}
|
|
61619
|
+
case "PIPELINE_STARTED": {
|
|
61620
|
+
const eid = event.eventId;
|
|
61621
|
+
pipelineStartNanoTimes.set(eid, event.nanoTime);
|
|
61622
|
+
const predEid = event.predicateStartEvent;
|
|
61623
|
+
pipelineToPredicateMap.set(eid, predEid);
|
|
61624
|
+
break;
|
|
61625
|
+
}
|
|
61252
61626
|
case "PIPELINE_COMPLETED": {
|
|
61253
61627
|
const pipelineStartEid = event.startEvent;
|
|
61254
|
-
const
|
|
61255
|
-
|
|
61256
|
-
)
|
|
61257
|
-
if (pipelineStartEvt) {
|
|
61258
|
-
const predEid = pipelineStartEvt.predicateStartEvent;
|
|
61628
|
+
const predEid = pipelineToPredicateMap.get(pipelineStartEid);
|
|
61629
|
+
const startNano = pipelineStartNanoTimes.get(pipelineStartEid);
|
|
61630
|
+
if (predEid !== void 0) {
|
|
61259
61631
|
const predStart = predicateStartEvents.get(predEid);
|
|
61260
61632
|
if (predStart) {
|
|
61261
61633
|
predStart.pipelineCount += 1;
|
|
61634
|
+
const pipelineDurationMs = startNano !== void 0 ? (event.nanoTime - startNano) / 1e6 : 0;
|
|
61635
|
+
predStart.pipelineStages.push({
|
|
61636
|
+
durationMs: pipelineDurationMs,
|
|
61637
|
+
resultSize: event.resultSize ?? 0,
|
|
61638
|
+
counts: event.counts ?? [],
|
|
61639
|
+
duplicationPercentages: event.duplicationPercentages
|
|
61640
|
+
});
|
|
61262
61641
|
}
|
|
61263
61642
|
}
|
|
61264
61643
|
break;
|
|
@@ -61276,7 +61655,9 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61276
61655
|
resultSize: event.resultSize,
|
|
61277
61656
|
pipelineCount: predStart.pipelineCount > 0 ? predStart.pipelineCount : void 0,
|
|
61278
61657
|
evaluationStrategy: predStart.predicateType,
|
|
61279
|
-
dependencies: predStart.dependencies
|
|
61658
|
+
dependencies: predStart.dependencies,
|
|
61659
|
+
raSteps: predStart.raSteps,
|
|
61660
|
+
pipelineStages: predStart.pipelineStages.length > 0 ? predStart.pipelineStages : void 0
|
|
61280
61661
|
};
|
|
61281
61662
|
const qEid = predStart.queryCausingWork ?? firstQueryEventId;
|
|
61282
61663
|
if (qEid !== void 0) {
|
|
@@ -61316,16 +61697,17 @@ function parseRawEvaluatorLog(logPath) {
|
|
|
61316
61697
|
codeqlVersion,
|
|
61317
61698
|
logFormat: "raw",
|
|
61318
61699
|
queries,
|
|
61319
|
-
totalEvents
|
|
61700
|
+
totalEvents
|
|
61320
61701
|
};
|
|
61321
61702
|
}
|
|
61322
|
-
function
|
|
61323
|
-
const events = parseJsonObjects(logPath);
|
|
61703
|
+
async function processSummaryEvents(events) {
|
|
61324
61704
|
let codeqlVersion;
|
|
61325
61705
|
const queryPredicatesMap = /* @__PURE__ */ new Map();
|
|
61326
61706
|
const queryTotalMs = /* @__PURE__ */ new Map();
|
|
61327
61707
|
const queryCacheHits = /* @__PURE__ */ new Map();
|
|
61328
|
-
|
|
61708
|
+
let totalEvents = 0;
|
|
61709
|
+
for await (const event of events) {
|
|
61710
|
+
totalEvents++;
|
|
61329
61711
|
if (event.summaryLogVersion !== void 0) {
|
|
61330
61712
|
codeqlVersion = event.codeqlVersion;
|
|
61331
61713
|
continue;
|
|
@@ -61342,6 +61724,11 @@ function parseSummaryLog(logPath) {
|
|
|
61342
61724
|
const queryName = event.queryCausingWork || "unknown";
|
|
61343
61725
|
const deps = event.dependencies;
|
|
61344
61726
|
const pipelineRuns = event.pipelineRuns;
|
|
61727
|
+
const raObj = event.ra;
|
|
61728
|
+
let raSteps;
|
|
61729
|
+
if (typeof raObj === "string" && raObj.length > 0) {
|
|
61730
|
+
raSteps = raObj.replace(/\r\n/g, "\n").split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
61731
|
+
}
|
|
61345
61732
|
const profile = {
|
|
61346
61733
|
predicateName,
|
|
61347
61734
|
position: event.position,
|
|
@@ -61349,7 +61736,8 @@ function parseSummaryLog(logPath) {
|
|
|
61349
61736
|
resultSize: event.resultSize,
|
|
61350
61737
|
pipelineCount: pipelineRuns,
|
|
61351
61738
|
evaluationStrategy: strategy,
|
|
61352
|
-
dependencies: deps ? Object.keys(deps) : []
|
|
61739
|
+
dependencies: deps ? Object.keys(deps) : [],
|
|
61740
|
+
raSteps
|
|
61353
61741
|
};
|
|
61354
61742
|
if (event.isCached === true || strategy === "CACHEHIT") {
|
|
61355
61743
|
queryCacheHits.set(
|
|
@@ -61382,143 +61770,142 @@ function parseSummaryLog(logPath) {
|
|
|
61382
61770
|
codeqlVersion,
|
|
61383
61771
|
logFormat: "summary",
|
|
61384
61772
|
queries,
|
|
61385
|
-
totalEvents
|
|
61773
|
+
totalEvents
|
|
61386
61774
|
};
|
|
61387
61775
|
}
|
|
61388
|
-
function parseEvaluatorLog(logPath) {
|
|
61389
|
-
const
|
|
61390
|
-
|
|
61776
|
+
async function parseEvaluatorLog(logPath) {
|
|
61777
|
+
const stream = streamJsonObjects(logPath);
|
|
61778
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
61779
|
+
const first = await iterator.next();
|
|
61780
|
+
if (first.done) {
|
|
61391
61781
|
return {
|
|
61392
61782
|
logFormat: "raw",
|
|
61393
61783
|
queries: [],
|
|
61394
61784
|
totalEvents: 0
|
|
61395
61785
|
};
|
|
61396
61786
|
}
|
|
61397
|
-
const
|
|
61787
|
+
const firstEvent = first.value;
|
|
61788
|
+
const format = detectLogFormat(firstEvent);
|
|
61789
|
+
async function* prependFirst() {
|
|
61790
|
+
yield firstEvent;
|
|
61791
|
+
for (; ; ) {
|
|
61792
|
+
const next = await iterator.next();
|
|
61793
|
+
if (next.done) break;
|
|
61794
|
+
yield next.value;
|
|
61795
|
+
}
|
|
61796
|
+
}
|
|
61398
61797
|
if (format === "raw") {
|
|
61399
|
-
return
|
|
61798
|
+
return processRawEvents(prependFirst());
|
|
61400
61799
|
}
|
|
61401
|
-
return
|
|
61800
|
+
return processSummaryEvents(prependFirst());
|
|
61402
61801
|
}
|
|
61403
61802
|
|
|
61404
61803
|
// src/tools/codeql/profile-codeql-query-from-logs.ts
|
|
61405
61804
|
init_logger();
|
|
61406
|
-
function
|
|
61407
|
-
return
|
|
61805
|
+
function getTopPredicates(predicates, topN) {
|
|
61806
|
+
return [...predicates].sort((a, b) => b.durationMs - a.durationMs).slice(0, topN);
|
|
61408
61807
|
}
|
|
61409
|
-
function
|
|
61808
|
+
function buildDetailFile(profile, topN) {
|
|
61410
61809
|
const lines = [];
|
|
61411
|
-
|
|
61412
|
-
lines.push("
|
|
61810
|
+
const lineIndex = /* @__PURE__ */ new Map();
|
|
61811
|
+
lines.push("# CodeQL Evaluator Profile \u2014 Predicate Detail");
|
|
61812
|
+
lines.push(`# Log format: ${profile.logFormat}`);
|
|
61813
|
+
if (profile.codeqlVersion) {
|
|
61814
|
+
lines.push(`# CodeQL version: ${profile.codeqlVersion}`);
|
|
61815
|
+
}
|
|
61816
|
+
lines.push(`# Use read_file with line ranges from the JSON response to access individual predicates.`);
|
|
61413
61817
|
lines.push("");
|
|
61414
|
-
|
|
61415
|
-
const query = profile.queries[
|
|
61416
|
-
|
|
61417
|
-
|
|
61418
|
-
|
|
61419
|
-
predicateCount: 0,
|
|
61420
|
-
cacheHits: 0
|
|
61421
|
-
};
|
|
61422
|
-
const qLabel = sanitizeMermaid(basename4(query.queryName));
|
|
61423
|
-
lines.push(
|
|
61424
|
-
` QUERY["${qLabel}<br/>Total: ${query.totalDurationMs.toFixed(2)}ms<br/>Predicates: ${query.predicateCount}"]`
|
|
61425
|
-
);
|
|
61426
|
-
lines.push("");
|
|
61427
|
-
const topPredicates = getTopPredicates(query.predicates, topN);
|
|
61428
|
-
topPredicates.forEach((pred, idx) => {
|
|
61429
|
-
const nodeId = `P${idx}`;
|
|
61430
|
-
const name = sanitizeMermaid(pred.predicateName).substring(0, 50);
|
|
61431
|
-
const dur = pred.durationMs.toFixed(2);
|
|
61432
|
-
const size = pred.resultSize !== void 0 ? String(pred.resultSize) : "?";
|
|
61433
|
-
lines.push(
|
|
61434
|
-
` ${nodeId}["${name}<br/>${dur}ms | ${size} results"]`
|
|
61435
|
-
);
|
|
61436
|
-
});
|
|
61818
|
+
for (let qIdx = 0; qIdx < profile.queries.length; qIdx++) {
|
|
61819
|
+
const query = profile.queries[qIdx];
|
|
61820
|
+
const qName = basename4(query.queryName);
|
|
61821
|
+
lines.push(`== Query: ${qName} ==`);
|
|
61822
|
+
lines.push(` Total: ${query.totalDurationMs.toFixed(2)}ms | Predicates evaluated: ${query.predicateCount} | Cache hits: ${query.cacheHits}`);
|
|
61437
61823
|
lines.push("");
|
|
61438
|
-
|
|
61439
|
-
|
|
61824
|
+
const evalOrderMap = /* @__PURE__ */ new Map();
|
|
61825
|
+
query.predicates.forEach((pred, idx) => {
|
|
61826
|
+
evalOrderMap.set(pred, idx + 1);
|
|
61440
61827
|
});
|
|
61441
|
-
|
|
61442
|
-
|
|
61443
|
-
|
|
61444
|
-
|
|
61445
|
-
|
|
61446
|
-
|
|
61447
|
-
|
|
61448
|
-
|
|
61449
|
-
|
|
61450
|
-
|
|
61451
|
-
|
|
61452
|
-
|
|
61453
|
-
|
|
61454
|
-
|
|
61455
|
-
|
|
61456
|
-
|
|
61457
|
-
|
|
61458
|
-
|
|
61459
|
-
lines.push(
|
|
61460
|
-
|
|
61461
|
-
|
|
61462
|
-
|
|
61463
|
-
}
|
|
61828
|
+
const top = getTopPredicates(query.predicates, topN);
|
|
61829
|
+
for (const pred of top) {
|
|
61830
|
+
const startLine = lines.length + 1;
|
|
61831
|
+
lines.push(`--- ${pred.predicateName} ---`);
|
|
61832
|
+
lines.push(` Eval order: ${evalOrderMap.get(pred) ?? "?"} of ${query.predicateCount}`);
|
|
61833
|
+
lines.push(` Duration: ${pred.durationMs.toFixed(2)} ms`);
|
|
61834
|
+
lines.push(` Result: ${pred.resultSize ?? "?"} tuples`);
|
|
61835
|
+
lines.push(` Strategy: ${pred.evaluationStrategy ?? "unknown"}`);
|
|
61836
|
+
if (pred.position) {
|
|
61837
|
+
lines.push(` Position: ${pred.position}`);
|
|
61838
|
+
}
|
|
61839
|
+
if (pred.dependencies.length > 0) {
|
|
61840
|
+
lines.push(` Dependencies (${pred.dependencies.length}):`);
|
|
61841
|
+
for (const dep of pred.dependencies) {
|
|
61842
|
+
lines.push(` - ${dep}`);
|
|
61843
|
+
}
|
|
61844
|
+
}
|
|
61845
|
+
if (pred.raSteps && pred.raSteps.length > 0) {
|
|
61846
|
+
lines.push(` RA operations (${pred.raSteps.length} steps):`);
|
|
61847
|
+
for (const step of pred.raSteps) {
|
|
61848
|
+
lines.push(` ${step}`);
|
|
61849
|
+
}
|
|
61850
|
+
}
|
|
61851
|
+
if (pred.pipelineStages && pred.pipelineStages.length > 0) {
|
|
61852
|
+
lines.push(` Pipeline stages (${pred.pipelineStages.length}):`);
|
|
61853
|
+
for (let pIdx = 0; pIdx < pred.pipelineStages.length; pIdx++) {
|
|
61854
|
+
const stage = pred.pipelineStages[pIdx];
|
|
61855
|
+
const countsStr = stage.counts.length > 0 ? `counts=[${stage.counts.join(", ")}]` : "counts=[]";
|
|
61856
|
+
lines.push(` [${pIdx + 1}] ${stage.durationMs.toFixed(2)}ms -> ${stage.resultSize} tuples (${countsStr})`);
|
|
61857
|
+
}
|
|
61858
|
+
}
|
|
61464
61859
|
lines.push("");
|
|
61465
|
-
|
|
61860
|
+
const endLine = lines.length;
|
|
61861
|
+
const key = `${qIdx}:${pred.predicateName}`;
|
|
61862
|
+
lineIndex.set(key, { start: startLine, end: endLine });
|
|
61863
|
+
}
|
|
61466
61864
|
}
|
|
61467
|
-
lines.
|
|
61468
|
-
lines.push(
|
|
61469
|
-
" classDef default fill:#e1f5ff,stroke:#333,stroke-width:2px"
|
|
61470
|
-
);
|
|
61471
|
-
lines.push(
|
|
61472
|
-
" classDef query fill:#ffe1e1,stroke:#333,stroke-width:3px"
|
|
61473
|
-
);
|
|
61474
|
-
lines.push(" class QUERY query");
|
|
61475
|
-
lines.push("```");
|
|
61476
|
-
return lines.join("\n");
|
|
61477
|
-
}
|
|
61478
|
-
function sanitizeMermaid(text) {
|
|
61479
|
-
return text.replace(/[<>"]/g, "");
|
|
61480
|
-
}
|
|
61481
|
-
function getTopPredicates(predicates, topN) {
|
|
61482
|
-
return [...predicates].sort((a, b) => b.durationMs - a.durationMs).slice(0, topN);
|
|
61865
|
+
return { content: lines.join("\n"), lineIndex };
|
|
61483
61866
|
}
|
|
61484
|
-
function
|
|
61485
|
-
const
|
|
61486
|
-
|
|
61487
|
-
|
|
61488
|
-
|
|
61489
|
-
|
|
61490
|
-
sections.push(` - ${f}`);
|
|
61491
|
-
}
|
|
61492
|
-
sections.push("");
|
|
61493
|
-
sections.push(`Log Format: ${profile.logFormat}`);
|
|
61494
|
-
if (profile.codeqlVersion) {
|
|
61495
|
-
sections.push(`CodeQL Version: ${profile.codeqlVersion}`);
|
|
61496
|
-
}
|
|
61497
|
-
sections.push(`Total Events: ${profile.totalEvents}`);
|
|
61498
|
-
sections.push(`Queries: ${profile.queries.length}`);
|
|
61499
|
-
for (const query of profile.queries) {
|
|
61500
|
-
sections.push("");
|
|
61501
|
-
sections.push(`--- ${basename4(query.queryName)} ---`);
|
|
61502
|
-
sections.push(` Total Duration: ${query.totalDurationMs.toFixed(2)} ms`);
|
|
61503
|
-
sections.push(` Predicates Evaluated: ${query.predicateCount}`);
|
|
61504
|
-
sections.push(` Cache Hits: ${query.cacheHits}`);
|
|
61867
|
+
function buildInlineResponse(profile, topN, detailLineIndex, files) {
|
|
61868
|
+
const queries = profile.queries.map((query, qIdx) => {
|
|
61869
|
+
const evalOrderMap = /* @__PURE__ */ new Map();
|
|
61870
|
+
query.predicates.forEach((pred, idx) => {
|
|
61871
|
+
evalOrderMap.set(pred, idx + 1);
|
|
61872
|
+
});
|
|
61505
61873
|
const top = getTopPredicates(query.predicates, topN);
|
|
61506
|
-
|
|
61507
|
-
|
|
61508
|
-
|
|
61509
|
-
|
|
61510
|
-
|
|
61511
|
-
|
|
61512
|
-
|
|
61513
|
-
|
|
61514
|
-
|
|
61515
|
-
|
|
61516
|
-
|
|
61874
|
+
return {
|
|
61875
|
+
queryName: query.queryName,
|
|
61876
|
+
totalDurationMs: query.totalDurationMs,
|
|
61877
|
+
predicateCount: query.predicateCount,
|
|
61878
|
+
cacheHits: query.cacheHits,
|
|
61879
|
+
slowestPredicates: top.map((pred) => {
|
|
61880
|
+
const key = `${qIdx}:${pred.predicateName}`;
|
|
61881
|
+
const detailLines = detailLineIndex.get(key) ?? { start: 0, end: 0 };
|
|
61882
|
+
return {
|
|
61883
|
+
evalOrder: evalOrderMap.get(pred) ?? 0,
|
|
61884
|
+
name: pred.predicateName,
|
|
61885
|
+
durationMs: pred.durationMs,
|
|
61886
|
+
resultSize: pred.resultSize,
|
|
61887
|
+
strategy: pred.evaluationStrategy,
|
|
61888
|
+
dependencyCount: pred.dependencies.length,
|
|
61889
|
+
pipelineCount: pred.pipelineCount,
|
|
61890
|
+
detailLines
|
|
61891
|
+
};
|
|
61892
|
+
})
|
|
61893
|
+
};
|
|
61894
|
+
});
|
|
61895
|
+
return {
|
|
61896
|
+
logFormat: profile.logFormat,
|
|
61897
|
+
codeqlVersion: profile.codeqlVersion,
|
|
61898
|
+
totalEvents: profile.totalEvents,
|
|
61899
|
+
queries,
|
|
61900
|
+
detailFile: files.detailFile,
|
|
61901
|
+
fullProfileJson: files.fullProfileJson,
|
|
61902
|
+
evaluatorLog: files.evaluatorLog
|
|
61903
|
+
};
|
|
61517
61904
|
}
|
|
61518
61905
|
function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
61519
61906
|
server.tool(
|
|
61520
61907
|
"profile_codeql_query_from_logs",
|
|
61521
|
-
"Parse CodeQL
|
|
61908
|
+
"Parse CodeQL evaluator logs into a structured performance profile. Returns compact JSON with per-query summaries and top-N slowest predicates (name, duration, result size, eval order, dependency count). Full RA operations, pipeline-stage tuple progressions, and dependency lists are written to a line-indexed detail file \u2014 each predicate includes detailLines: {start, end} for targeted read_file access to its full analysis. Works with logs from codeql query run, codeql database analyze, or vscode-codeql.",
|
|
61522
61909
|
{
|
|
61523
61910
|
evaluatorLog: external_exports.string().describe(
|
|
61524
61911
|
"Path to evaluator-log.jsonl or evaluator-log.summary.jsonl"
|
|
@@ -61527,7 +61914,7 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61527
61914
|
"Directory to write profile output files (defaults to same directory as log)"
|
|
61528
61915
|
),
|
|
61529
61916
|
topN: external_exports.number().optional().describe(
|
|
61530
|
-
"Number of
|
|
61917
|
+
"Number of slowest predicates to include per query (default: 20)"
|
|
61531
61918
|
)
|
|
61532
61919
|
},
|
|
61533
61920
|
async (params) => {
|
|
@@ -61539,51 +61926,42 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61539
61926
|
content: [
|
|
61540
61927
|
{
|
|
61541
61928
|
type: "text",
|
|
61542
|
-
text: `Evaluator log not found at: ${evaluatorLog}`
|
|
61929
|
+
text: JSON.stringify({ error: `Evaluator log not found at: ${evaluatorLog}` })
|
|
61543
61930
|
}
|
|
61544
61931
|
],
|
|
61545
61932
|
isError: true
|
|
61546
61933
|
};
|
|
61547
61934
|
}
|
|
61548
61935
|
logger.info(`Parsing evaluator log from: ${evaluatorLog}`);
|
|
61549
|
-
const profile = parseEvaluatorLog(evaluatorLog);
|
|
61936
|
+
const profile = await parseEvaluatorLog(evaluatorLog);
|
|
61550
61937
|
const profileOutputDir = outputDir ?? dirname6(evaluatorLog);
|
|
61551
61938
|
mkdirSync6(profileOutputDir, { recursive: true });
|
|
61552
|
-
const jsonPath =
|
|
61553
|
-
|
|
61554
|
-
|
|
61555
|
-
);
|
|
61556
|
-
|
|
61557
|
-
|
|
61558
|
-
|
|
61559
|
-
|
|
61560
|
-
|
|
61561
|
-
|
|
61562
|
-
|
|
61563
|
-
|
|
61564
|
-
const outputFilesList = [
|
|
61565
|
-
`Profile JSON: ${jsonPath}`,
|
|
61566
|
-
`Profile Mermaid: ${mdPath}`,
|
|
61567
|
-
`Evaluator Log: ${evaluatorLog}`
|
|
61568
|
-
];
|
|
61569
|
-
const responseText = buildTextSummary(
|
|
61570
|
-
profile,
|
|
61571
|
-
effectiveTopN,
|
|
61572
|
-
outputFilesList
|
|
61573
|
-
);
|
|
61939
|
+
const jsonPath = join11(profileOutputDir, "query-evaluation-profile.json");
|
|
61940
|
+
writeFileSync3(jsonPath, JSON.stringify(profile, null, 2));
|
|
61941
|
+
logger.info(`Full profile JSON written to: ${jsonPath}`);
|
|
61942
|
+
const { content: detailContent, lineIndex } = buildDetailFile(profile, effectiveTopN);
|
|
61943
|
+
const detailPath = join11(profileOutputDir, "query-evaluation-detail.txt");
|
|
61944
|
+
writeFileSync3(detailPath, detailContent);
|
|
61945
|
+
logger.info(`Detail file written to: ${detailPath}`);
|
|
61946
|
+
const response = buildInlineResponse(profile, effectiveTopN, lineIndex, {
|
|
61947
|
+
detailFile: detailPath,
|
|
61948
|
+
fullProfileJson: jsonPath,
|
|
61949
|
+
evaluatorLog
|
|
61950
|
+
});
|
|
61574
61951
|
return {
|
|
61575
|
-
content: [
|
|
61952
|
+
content: [
|
|
61953
|
+
{ type: "text", text: JSON.stringify(response) }
|
|
61954
|
+
]
|
|
61576
61955
|
};
|
|
61577
61956
|
} catch (error2) {
|
|
61578
|
-
logger.error(
|
|
61579
|
-
"Error profiling CodeQL query from logs:",
|
|
61580
|
-
error2
|
|
61581
|
-
);
|
|
61957
|
+
logger.error("Error profiling CodeQL query from logs:", error2);
|
|
61582
61958
|
return {
|
|
61583
61959
|
content: [
|
|
61584
61960
|
{
|
|
61585
61961
|
type: "text",
|
|
61586
|
-
text:
|
|
61962
|
+
text: JSON.stringify({
|
|
61963
|
+
error: `Failed to profile query from logs: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
61964
|
+
})
|
|
61587
61965
|
}
|
|
61588
61966
|
],
|
|
61589
61967
|
isError: true
|
|
@@ -61596,76 +61974,114 @@ function registerProfileCodeQLQueryFromLogsTool(server) {
|
|
|
61596
61974
|
// src/tools/codeql/profile-codeql-query.ts
|
|
61597
61975
|
init_cli_executor();
|
|
61598
61976
|
init_logger();
|
|
61599
|
-
import { writeFileSync as writeFileSync4,
|
|
61600
|
-
import {
|
|
61977
|
+
import { writeFileSync as writeFileSync4, existsSync as existsSync10 } from "fs";
|
|
61978
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
61979
|
+
import { join as join12, dirname as dirname7, basename as basename5 } from "path";
|
|
61601
61980
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
61602
|
-
|
|
61603
|
-
|
|
61604
|
-
const jsonObjects = logContent.split("\n\n").filter((s) => s.trim());
|
|
61605
|
-
const events = jsonObjects.map((obj) => {
|
|
61606
|
-
try {
|
|
61607
|
-
return JSON.parse(obj);
|
|
61608
|
-
} catch (_error) {
|
|
61609
|
-
logger.warn(`Failed to parse evaluator log object: ${obj.substring(0, 100)}...`);
|
|
61610
|
-
return null;
|
|
61611
|
-
}
|
|
61612
|
-
}).filter((event) => event !== null);
|
|
61981
|
+
import { createInterface as createInterface2 } from "readline";
|
|
61982
|
+
async function parseEvaluatorLog2(logPath) {
|
|
61613
61983
|
const pipelineMap = /* @__PURE__ */ new Map();
|
|
61614
61984
|
const predicateNameToEventId = /* @__PURE__ */ new Map();
|
|
61985
|
+
const predicateStartNanoTimes = /* @__PURE__ */ new Map();
|
|
61615
61986
|
let queryName = "";
|
|
61616
61987
|
let queryStartTime = 0;
|
|
61617
61988
|
let queryEndTime = 0;
|
|
61618
|
-
|
|
61619
|
-
|
|
61620
|
-
|
|
61621
|
-
|
|
61622
|
-
|
|
61623
|
-
|
|
61624
|
-
|
|
61625
|
-
|
|
61626
|
-
|
|
61627
|
-
|
|
61628
|
-
|
|
61629
|
-
|
|
61630
|
-
|
|
61631
|
-
|
|
61632
|
-
|
|
61633
|
-
|
|
61634
|
-
|
|
61635
|
-
|
|
61636
|
-
|
|
61637
|
-
|
|
61638
|
-
|
|
61639
|
-
|
|
61640
|
-
|
|
61989
|
+
let totalEvents = 0;
|
|
61990
|
+
const rl = createInterface2({
|
|
61991
|
+
input: createReadStream2(logPath, { encoding: "utf-8" }),
|
|
61992
|
+
crlfDelay: Infinity
|
|
61993
|
+
});
|
|
61994
|
+
let depth = 0;
|
|
61995
|
+
let inString = false;
|
|
61996
|
+
let escape2 = false;
|
|
61997
|
+
const lines = [];
|
|
61998
|
+
for await (const line of rl) {
|
|
61999
|
+
for (const ch of line) {
|
|
62000
|
+
if (escape2) {
|
|
62001
|
+
escape2 = false;
|
|
62002
|
+
continue;
|
|
62003
|
+
}
|
|
62004
|
+
if (ch === "\\" && inString) {
|
|
62005
|
+
escape2 = true;
|
|
62006
|
+
continue;
|
|
62007
|
+
}
|
|
62008
|
+
if (ch === '"') {
|
|
62009
|
+
inString = !inString;
|
|
62010
|
+
continue;
|
|
62011
|
+
}
|
|
62012
|
+
if (inString) continue;
|
|
62013
|
+
if (ch === "{") depth++;
|
|
62014
|
+
if (ch === "}") depth--;
|
|
62015
|
+
}
|
|
62016
|
+
if (depth > 0 || depth === 0 && line.trim().length > 0 && lines.length > 0) {
|
|
62017
|
+
lines.push(line);
|
|
62018
|
+
} else if (depth === 0 && lines.length === 0 && line.trim().length > 0) {
|
|
62019
|
+
lines.push(line);
|
|
62020
|
+
}
|
|
62021
|
+
if (depth === 0 && lines.length > 0) {
|
|
62022
|
+
const objStr = lines.join("\n");
|
|
62023
|
+
lines.length = 0;
|
|
62024
|
+
inString = false;
|
|
62025
|
+
escape2 = false;
|
|
62026
|
+
if (objStr.trim().length === 0) continue;
|
|
62027
|
+
let event;
|
|
62028
|
+
try {
|
|
62029
|
+
event = JSON.parse(objStr);
|
|
62030
|
+
} catch {
|
|
62031
|
+
logger.warn(`Failed to parse evaluator log object: ${objStr.substring(0, 100)}...`);
|
|
62032
|
+
continue;
|
|
62033
|
+
}
|
|
62034
|
+
totalEvents++;
|
|
62035
|
+
switch (event.type) {
|
|
62036
|
+
case "QUERY_STARTED":
|
|
62037
|
+
queryName = event.queryName || "";
|
|
62038
|
+
queryStartTime = event.nanoTime;
|
|
62039
|
+
break;
|
|
62040
|
+
case "QUERY_COMPLETED":
|
|
62041
|
+
queryEndTime = event.nanoTime;
|
|
62042
|
+
break;
|
|
62043
|
+
case "PREDICATE_STARTED": {
|
|
62044
|
+
const predicateName = event.predicateName;
|
|
62045
|
+
const position = event.position;
|
|
62046
|
+
const predicateType = event.predicateType;
|
|
62047
|
+
const dependencies = event.dependencies;
|
|
62048
|
+
predicateNameToEventId.set(predicateName, event.eventId);
|
|
62049
|
+
predicateStartNanoTimes.set(event.eventId, event.nanoTime);
|
|
62050
|
+
const dependencyEventIds = [];
|
|
62051
|
+
const dependencyNames = [];
|
|
62052
|
+
if (dependencies) {
|
|
62053
|
+
for (const depName of Object.keys(dependencies)) {
|
|
62054
|
+
dependencyNames.push(depName);
|
|
62055
|
+
const depEventId = predicateNameToEventId.get(depName);
|
|
62056
|
+
if (depEventId !== void 0) {
|
|
62057
|
+
dependencyEventIds.push(depEventId);
|
|
62058
|
+
}
|
|
61641
62059
|
}
|
|
61642
62060
|
}
|
|
62061
|
+
pipelineMap.set(event.eventId, {
|
|
62062
|
+
eventId: event.eventId,
|
|
62063
|
+
name: predicateName,
|
|
62064
|
+
position,
|
|
62065
|
+
type: predicateType,
|
|
62066
|
+
startTime: event.nanoTime,
|
|
62067
|
+
dependencies: dependencyNames,
|
|
62068
|
+
dependencyEventIds
|
|
62069
|
+
});
|
|
62070
|
+
break;
|
|
61643
62071
|
}
|
|
61644
|
-
|
|
61645
|
-
|
|
61646
|
-
|
|
61647
|
-
|
|
61648
|
-
|
|
61649
|
-
|
|
61650
|
-
dependencies: dependencyNames,
|
|
61651
|
-
dependencyEventIds
|
|
61652
|
-
});
|
|
61653
|
-
break;
|
|
61654
|
-
}
|
|
61655
|
-
case "PREDICATE_COMPLETED": {
|
|
61656
|
-
const startEventId = event.startEvent;
|
|
61657
|
-
const pipelineInfo = pipelineMap.get(startEventId);
|
|
61658
|
-
if (pipelineInfo) {
|
|
61659
|
-
const startEvent = events.find((e) => e.eventId === startEventId);
|
|
61660
|
-
if (startEvent) {
|
|
61661
|
-
const duration3 = (event.nanoTime - startEvent.nanoTime) / 1e6;
|
|
62072
|
+
case "PREDICATE_COMPLETED": {
|
|
62073
|
+
const startEventId = event.startEvent;
|
|
62074
|
+
const pipelineInfo = pipelineMap.get(startEventId);
|
|
62075
|
+
const startNano = predicateStartNanoTimes.get(startEventId);
|
|
62076
|
+
if (pipelineInfo && startNano !== void 0) {
|
|
62077
|
+
const duration3 = (event.nanoTime - startNano) / 1e6;
|
|
61662
62078
|
pipelineInfo.endTime = event.nanoTime;
|
|
61663
62079
|
pipelineInfo.duration = duration3;
|
|
61664
62080
|
pipelineInfo.resultSize = event.resultSize;
|
|
61665
62081
|
pipelineInfo.tupleCount = event.tupleCount;
|
|
61666
62082
|
}
|
|
62083
|
+
break;
|
|
61667
62084
|
}
|
|
61668
|
-
break;
|
|
61669
62085
|
}
|
|
61670
62086
|
}
|
|
61671
62087
|
}
|
|
@@ -61674,14 +62090,14 @@ function parseEvaluatorLog2(logPath) {
|
|
|
61674
62090
|
return {
|
|
61675
62091
|
queryName,
|
|
61676
62092
|
totalDuration,
|
|
61677
|
-
totalEvents
|
|
62093
|
+
totalEvents,
|
|
61678
62094
|
pipelines
|
|
61679
62095
|
};
|
|
61680
62096
|
}
|
|
61681
|
-
function
|
|
62097
|
+
function formatAsJson(profile) {
|
|
61682
62098
|
return JSON.stringify(profile, null, 2);
|
|
61683
62099
|
}
|
|
61684
|
-
function
|
|
62100
|
+
function formatAsMermaid(profile) {
|
|
61685
62101
|
const lines = [];
|
|
61686
62102
|
lines.push("```mermaid");
|
|
61687
62103
|
lines.push("graph TD");
|
|
@@ -61734,11 +62150,11 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
61734
62150
|
let sarifPath;
|
|
61735
62151
|
if (!logPath) {
|
|
61736
62152
|
logger.info("No evaluator log provided, running query to generate one");
|
|
61737
|
-
const defaultOutputDir = outputDir ||
|
|
62153
|
+
const defaultOutputDir = outputDir || join12(dirname7(query), "profile-output");
|
|
61738
62154
|
mkdirSync7(defaultOutputDir, { recursive: true });
|
|
61739
|
-
logPath =
|
|
61740
|
-
bqrsPath =
|
|
61741
|
-
sarifPath =
|
|
62155
|
+
logPath = join12(defaultOutputDir, "evaluator-log.jsonl");
|
|
62156
|
+
bqrsPath = join12(defaultOutputDir, "query-results.bqrs");
|
|
62157
|
+
sarifPath = join12(defaultOutputDir, "query-results.sarif");
|
|
61742
62158
|
const queryResult = await executeCodeQLCommand(
|
|
61743
62159
|
"query run",
|
|
61744
62160
|
{
|
|
@@ -61788,15 +62204,15 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
61788
62204
|
};
|
|
61789
62205
|
}
|
|
61790
62206
|
logger.info(`Parsing evaluator log from: ${logPath}`);
|
|
61791
|
-
const profile = parseEvaluatorLog2(logPath);
|
|
62207
|
+
const profile = await parseEvaluatorLog2(logPath);
|
|
61792
62208
|
const profileOutputDir = outputDir || dirname7(logPath);
|
|
61793
62209
|
mkdirSync7(profileOutputDir, { recursive: true });
|
|
61794
|
-
const jsonPath =
|
|
61795
|
-
const jsonContent =
|
|
62210
|
+
const jsonPath = join12(profileOutputDir, "query-evaluation-profile.json");
|
|
62211
|
+
const jsonContent = formatAsJson(profile);
|
|
61796
62212
|
writeFileSync4(jsonPath, jsonContent);
|
|
61797
62213
|
logger.info(`Profile JSON written to: ${jsonPath}`);
|
|
61798
|
-
const mdPath =
|
|
61799
|
-
const mdContent =
|
|
62214
|
+
const mdPath = join12(profileOutputDir, "query-evaluation-profile.md");
|
|
62215
|
+
const mdContent = formatAsMermaid(profile);
|
|
61800
62216
|
writeFileSync4(mdPath, mdContent);
|
|
61801
62217
|
logger.info(`Profile Mermaid diagram written to: ${mdPath}`);
|
|
61802
62218
|
const outputFiles = [
|
|
@@ -61946,7 +62362,7 @@ var codeqlQueryRunTool = {
|
|
|
61946
62362
|
};
|
|
61947
62363
|
|
|
61948
62364
|
// src/tools/codeql/quick-evaluate.ts
|
|
61949
|
-
import { join as
|
|
62365
|
+
import { join as join13, resolve as resolve6 } from "path";
|
|
61950
62366
|
init_logger();
|
|
61951
62367
|
init_temp_dir();
|
|
61952
62368
|
async function quickEvaluate({
|
|
@@ -61965,7 +62381,7 @@ async function quickEvaluate({
|
|
|
61965
62381
|
throw new Error(`Symbol '${symbol}' not found as class or predicate in file: ${file}`);
|
|
61966
62382
|
}
|
|
61967
62383
|
}
|
|
61968
|
-
const resolvedOutput = resolve6(output_path ||
|
|
62384
|
+
const resolvedOutput = resolve6(output_path || join13(getProjectTmpDir("quickeval"), "quickeval.bqrs"));
|
|
61969
62385
|
return resolvedOutput;
|
|
61970
62386
|
} catch (error2) {
|
|
61971
62387
|
throw new Error(`CodeQL evaluation failed: ${error2 instanceof Error ? error2.message : "Unknown error"}`, { cause: error2 });
|
|
@@ -62005,8 +62421,8 @@ function registerQuickEvaluateTool(server) {
|
|
|
62005
62421
|
|
|
62006
62422
|
// src/tools/codeql/read-database-source.ts
|
|
62007
62423
|
var import_adm_zip = __toESM(require_adm_zip(), 1);
|
|
62008
|
-
import { existsSync as existsSync11, readdirSync as
|
|
62009
|
-
import { join as
|
|
62424
|
+
import { existsSync as existsSync11, readdirSync as readdirSync7, readFileSync as readFileSync8, statSync as statSync7 } from "fs";
|
|
62425
|
+
import { join as join14, resolve as resolve7 } from "path";
|
|
62010
62426
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
62011
62427
|
init_logger();
|
|
62012
62428
|
var DEFAULT_MAX_LISTING_ENTRIES = 1e3;
|
|
@@ -62022,9 +62438,9 @@ function toFilesystemPath(uri) {
|
|
|
62022
62438
|
return uri;
|
|
62023
62439
|
}
|
|
62024
62440
|
function* walkDirectory(dir, base = dir) {
|
|
62025
|
-
for (const entry of
|
|
62026
|
-
const fullPath =
|
|
62027
|
-
if (
|
|
62441
|
+
for (const entry of readdirSync7(dir)) {
|
|
62442
|
+
const fullPath = join14(dir, entry);
|
|
62443
|
+
if (statSync7(fullPath).isDirectory()) {
|
|
62028
62444
|
yield* walkDirectory(fullPath, base);
|
|
62029
62445
|
} else {
|
|
62030
62446
|
yield fullPath.slice(base.length).replace(/\\/g, "/").replace(/^\//, "");
|
|
@@ -62090,8 +62506,8 @@ async function readDatabaseSource(params) {
|
|
|
62090
62506
|
if (!existsSync11(resolvedDbPath)) {
|
|
62091
62507
|
throw new Error(`Database path does not exist: ${databasePath}`);
|
|
62092
62508
|
}
|
|
62093
|
-
const srcZipPath =
|
|
62094
|
-
const srcDirPath =
|
|
62509
|
+
const srcZipPath = join14(resolvedDbPath, "src.zip");
|
|
62510
|
+
const srcDirPath = join14(resolvedDbPath, "src");
|
|
62095
62511
|
const hasSrcZip = existsSync11(srcZipPath);
|
|
62096
62512
|
const hasSrcDir = existsSync11(srcDirPath);
|
|
62097
62513
|
if (!hasSrcZip && !hasSrcDir) {
|
|
@@ -62166,8 +62582,8 @@ Archive contains ${availableEntries.length} entries. Use read_database_source wi
|
|
|
62166
62582
|
Directory contains ${availableEntries.length} entries. Use read_database_source without filePath to list available entries.`
|
|
62167
62583
|
);
|
|
62168
62584
|
}
|
|
62169
|
-
const fullPath =
|
|
62170
|
-
const rawContent =
|
|
62585
|
+
const fullPath = join14(srcDirPath, matchedRelative);
|
|
62586
|
+
const rawContent = readFileSync8(fullPath, "utf-8");
|
|
62171
62587
|
const { content, effectiveEnd, effectiveStart, totalLines } = applyLineRange(
|
|
62172
62588
|
rawContent,
|
|
62173
62589
|
startLine,
|
|
@@ -62326,6 +62742,32 @@ var codeqlResolveDatabaseTool = {
|
|
|
62326
62742
|
resultProcessor: defaultCLIResultProcessor
|
|
62327
62743
|
};
|
|
62328
62744
|
|
|
62745
|
+
// src/tools/codeql/resolve-files.ts
|
|
62746
|
+
var codeqlResolveFilesTool = {
|
|
62747
|
+
name: "codeql_resolve_files",
|
|
62748
|
+
description: "Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files, query files, and other CodeQL-related files within packs or workspaces.",
|
|
62749
|
+
command: "codeql",
|
|
62750
|
+
subcommand: "resolve files",
|
|
62751
|
+
inputSchema: {
|
|
62752
|
+
dir: external_exports.string().describe("The directory to search for files"),
|
|
62753
|
+
"include-extension": external_exports.array(external_exports.string()).optional().describe("Include files with given extensions (e.g., ['.qll', '.ql'])"),
|
|
62754
|
+
include: external_exports.array(external_exports.string()).optional().describe("Glob patterns to include (e.g., ['**/RemoteFlowSource*'])"),
|
|
62755
|
+
exclude: external_exports.array(external_exports.string()).optional().describe("Glob patterns to exclude"),
|
|
62756
|
+
prune: external_exports.array(external_exports.string()).optional().describe("Glob patterns for directories to prune from search"),
|
|
62757
|
+
"also-match": external_exports.array(external_exports.string()).optional().describe("Additional glob filter all results must match"),
|
|
62758
|
+
format: external_exports.enum(["text", "json"]).optional().describe("Output format (default: text)"),
|
|
62759
|
+
"follow-symlinks": external_exports.boolean().optional().describe("Follow symlinks when searching"),
|
|
62760
|
+
additionalArgs: createCodeQLSchemas.additionalArgs()
|
|
62761
|
+
},
|
|
62762
|
+
examples: [
|
|
62763
|
+
"codeql resolve files --include-extension=.qll --format=json -- /path/to/pack",
|
|
62764
|
+
"codeql resolve files --include=**/RemoteFlowSource* -- /path/to/pack",
|
|
62765
|
+
"codeql resolve files --include-extension=.ql --include-extension=.qll -- /path/to/pack",
|
|
62766
|
+
"codeql resolve files --include-extension=.qll --also-match=**/FlowSource* -- /path/to/pack"
|
|
62767
|
+
],
|
|
62768
|
+
resultProcessor: defaultCLIResultProcessor
|
|
62769
|
+
};
|
|
62770
|
+
|
|
62329
62771
|
// src/tools/codeql/resolve-languages.ts
|
|
62330
62772
|
var codeqlResolveLanguagesTool = {
|
|
62331
62773
|
name: "codeql_resolve_languages",
|
|
@@ -62470,6 +62912,255 @@ var codeqlResolveTestsTool = {
|
|
|
62470
62912
|
resultProcessor: defaultCLIResultProcessor
|
|
62471
62913
|
};
|
|
62472
62914
|
|
|
62915
|
+
// src/tools/codeql/search-ql-code.ts
|
|
62916
|
+
import { closeSync, createReadStream as createReadStream3, fstatSync, lstatSync, openSync, readdirSync as readdirSync8, readFileSync as readFileSync9, realpathSync } from "fs";
|
|
62917
|
+
import { basename as basename6, extname as extname2, join as join15, resolve as resolve9 } from "path";
|
|
62918
|
+
import { createInterface as createInterface3 } from "readline";
|
|
62919
|
+
init_logger();
|
|
62920
|
+
var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
62921
|
+
var MAX_FILES_TRAVERSED = 1e4;
|
|
62922
|
+
var MAX_CONTEXT_LINES = 50;
|
|
62923
|
+
var MAX_MAX_RESULTS = 1e4;
|
|
62924
|
+
var SKIP_DIRS2 = /* @__PURE__ */ new Set([".codeql", "node_modules", ".git"]);
|
|
62925
|
+
function collectFiles(paths, extensions, fileCount) {
|
|
62926
|
+
const files = [];
|
|
62927
|
+
const visitedDirs = /* @__PURE__ */ new Set();
|
|
62928
|
+
function walk(p) {
|
|
62929
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
62930
|
+
let stat;
|
|
62931
|
+
try {
|
|
62932
|
+
stat = lstatSync(p);
|
|
62933
|
+
} catch {
|
|
62934
|
+
return;
|
|
62935
|
+
}
|
|
62936
|
+
if (stat.isSymbolicLink()) return;
|
|
62937
|
+
if (stat.isFile()) {
|
|
62938
|
+
if (extensions.length === 0 || extensions.includes(extname2(p))) {
|
|
62939
|
+
files.push(p);
|
|
62940
|
+
}
|
|
62941
|
+
fileCount.value++;
|
|
62942
|
+
} else if (stat.isDirectory()) {
|
|
62943
|
+
if (SKIP_DIRS2.has(basename6(p))) return;
|
|
62944
|
+
let realPath;
|
|
62945
|
+
try {
|
|
62946
|
+
realPath = realpathSync(p);
|
|
62947
|
+
} catch {
|
|
62948
|
+
return;
|
|
62949
|
+
}
|
|
62950
|
+
if (visitedDirs.has(realPath)) return;
|
|
62951
|
+
visitedDirs.add(realPath);
|
|
62952
|
+
let entries;
|
|
62953
|
+
try {
|
|
62954
|
+
entries = readdirSync8(p);
|
|
62955
|
+
} catch {
|
|
62956
|
+
return;
|
|
62957
|
+
}
|
|
62958
|
+
for (const entry of entries) {
|
|
62959
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
62960
|
+
walk(join15(p, entry));
|
|
62961
|
+
}
|
|
62962
|
+
}
|
|
62963
|
+
}
|
|
62964
|
+
for (const p of paths) {
|
|
62965
|
+
if (fileCount.value >= MAX_FILES_TRAVERSED) break;
|
|
62966
|
+
walk(resolve9(p));
|
|
62967
|
+
}
|
|
62968
|
+
return files;
|
|
62969
|
+
}
|
|
62970
|
+
async function searchFile(filePath, regex, contextLines, maxCollect) {
|
|
62971
|
+
let fd;
|
|
62972
|
+
try {
|
|
62973
|
+
fd = openSync(filePath, "r");
|
|
62974
|
+
} catch {
|
|
62975
|
+
return { matches: [], totalCount: 0 };
|
|
62976
|
+
}
|
|
62977
|
+
let size;
|
|
62978
|
+
try {
|
|
62979
|
+
size = fstatSync(fd).size;
|
|
62980
|
+
} catch {
|
|
62981
|
+
try {
|
|
62982
|
+
closeSync(fd);
|
|
62983
|
+
} catch {
|
|
62984
|
+
}
|
|
62985
|
+
return { matches: [], totalCount: 0 };
|
|
62986
|
+
}
|
|
62987
|
+
if (size > MAX_FILE_SIZE_BYTES) {
|
|
62988
|
+
return searchFileStreaming(filePath, regex, contextLines, maxCollect, fd);
|
|
62989
|
+
}
|
|
62990
|
+
let content;
|
|
62991
|
+
try {
|
|
62992
|
+
content = readFileSync9(fd, "utf-8");
|
|
62993
|
+
} catch {
|
|
62994
|
+
try {
|
|
62995
|
+
closeSync(fd);
|
|
62996
|
+
} catch {
|
|
62997
|
+
}
|
|
62998
|
+
return { matches: [], totalCount: 0 };
|
|
62999
|
+
}
|
|
63000
|
+
try {
|
|
63001
|
+
closeSync(fd);
|
|
63002
|
+
} catch {
|
|
63003
|
+
}
|
|
63004
|
+
const lines = content.replace(/\r\n/g, "\n").split("\n");
|
|
63005
|
+
const matches = [];
|
|
63006
|
+
let totalCount = 0;
|
|
63007
|
+
for (let i = 0; i < lines.length; i++) {
|
|
63008
|
+
if (regex.test(lines[i])) {
|
|
63009
|
+
totalCount++;
|
|
63010
|
+
if (matches.length < maxCollect) {
|
|
63011
|
+
const match = {
|
|
63012
|
+
filePath,
|
|
63013
|
+
lineNumber: i + 1,
|
|
63014
|
+
lineContent: lines[i]
|
|
63015
|
+
};
|
|
63016
|
+
if (contextLines > 0) {
|
|
63017
|
+
const beforeStart = Math.max(0, i - contextLines);
|
|
63018
|
+
const afterEnd = Math.min(lines.length - 1, i + contextLines);
|
|
63019
|
+
match.contextBefore = lines.slice(beforeStart, i);
|
|
63020
|
+
match.contextAfter = lines.slice(i + 1, afterEnd + 1);
|
|
63021
|
+
}
|
|
63022
|
+
matches.push(match);
|
|
63023
|
+
}
|
|
63024
|
+
}
|
|
63025
|
+
}
|
|
63026
|
+
return { matches, totalCount };
|
|
63027
|
+
}
|
|
63028
|
+
async function searchFileStreaming(filePath, regex, contextLines, maxCollect, fd) {
|
|
63029
|
+
const matches = [];
|
|
63030
|
+
const recentLines = [];
|
|
63031
|
+
const pending = [];
|
|
63032
|
+
let lineNumber = 0;
|
|
63033
|
+
let totalCount = 0;
|
|
63034
|
+
let rl;
|
|
63035
|
+
try {
|
|
63036
|
+
const streamOpts = { encoding: "utf-8" };
|
|
63037
|
+
if (fd !== void 0) {
|
|
63038
|
+
streamOpts.fd = fd;
|
|
63039
|
+
streamOpts.autoClose = true;
|
|
63040
|
+
streamOpts.start = 0;
|
|
63041
|
+
}
|
|
63042
|
+
rl = createInterface3({
|
|
63043
|
+
input: createReadStream3(filePath, streamOpts),
|
|
63044
|
+
crlfDelay: Infinity
|
|
63045
|
+
});
|
|
63046
|
+
} catch {
|
|
63047
|
+
if (fd !== void 0) {
|
|
63048
|
+
try {
|
|
63049
|
+
closeSync(fd);
|
|
63050
|
+
} catch {
|
|
63051
|
+
}
|
|
63052
|
+
}
|
|
63053
|
+
return { matches: [], totalCount: 0 };
|
|
63054
|
+
}
|
|
63055
|
+
for await (const line of rl) {
|
|
63056
|
+
lineNumber++;
|
|
63057
|
+
for (const p of pending) {
|
|
63058
|
+
if (p.afterNeeded > 0) {
|
|
63059
|
+
p.match.contextAfter.push(line);
|
|
63060
|
+
p.afterNeeded--;
|
|
63061
|
+
}
|
|
63062
|
+
}
|
|
63063
|
+
while (pending.length > 0 && pending[0].afterNeeded === 0) {
|
|
63064
|
+
pending.shift();
|
|
63065
|
+
}
|
|
63066
|
+
if (regex.test(line)) {
|
|
63067
|
+
totalCount++;
|
|
63068
|
+
if (matches.length < maxCollect) {
|
|
63069
|
+
const match = {
|
|
63070
|
+
filePath,
|
|
63071
|
+
lineNumber,
|
|
63072
|
+
lineContent: line
|
|
63073
|
+
};
|
|
63074
|
+
if (contextLines > 0) {
|
|
63075
|
+
match.contextBefore = recentLines.slice(-contextLines);
|
|
63076
|
+
match.contextAfter = [];
|
|
63077
|
+
pending.push({ match, afterNeeded: contextLines });
|
|
63078
|
+
}
|
|
63079
|
+
matches.push(match);
|
|
63080
|
+
}
|
|
63081
|
+
}
|
|
63082
|
+
if (contextLines > 0) {
|
|
63083
|
+
recentLines.push(line);
|
|
63084
|
+
if (recentLines.length > contextLines) {
|
|
63085
|
+
recentLines.shift();
|
|
63086
|
+
}
|
|
63087
|
+
}
|
|
63088
|
+
}
|
|
63089
|
+
return { matches, totalCount };
|
|
63090
|
+
}
|
|
63091
|
+
async function searchQlCode(params) {
|
|
63092
|
+
const {
|
|
63093
|
+
pattern,
|
|
63094
|
+
paths,
|
|
63095
|
+
includeExtensions = [".ql", ".qll"],
|
|
63096
|
+
caseSensitive = true,
|
|
63097
|
+
contextLines: rawContextLines = 0,
|
|
63098
|
+
maxResults: rawMaxResults = 100
|
|
63099
|
+
} = params;
|
|
63100
|
+
const contextLines = Math.min(Math.max(0, Math.floor(rawContextLines)), MAX_CONTEXT_LINES);
|
|
63101
|
+
const maxResults = Math.min(Math.max(1, Math.floor(rawMaxResults)), MAX_MAX_RESULTS);
|
|
63102
|
+
const flags = caseSensitive ? "" : "i";
|
|
63103
|
+
const regex = new RegExp(pattern, flags);
|
|
63104
|
+
const fileCount = { value: 0 };
|
|
63105
|
+
const filesToSearch = collectFiles(paths, includeExtensions, fileCount);
|
|
63106
|
+
const allMatches = [];
|
|
63107
|
+
let totalMatches = 0;
|
|
63108
|
+
for (const file of filesToSearch) {
|
|
63109
|
+
const remainingSlots = Math.max(0, maxResults - allMatches.length);
|
|
63110
|
+
const { matches: fileMatches, totalCount } = await searchFile(
|
|
63111
|
+
file,
|
|
63112
|
+
regex,
|
|
63113
|
+
contextLines,
|
|
63114
|
+
remainingSlots
|
|
63115
|
+
);
|
|
63116
|
+
totalMatches += totalCount;
|
|
63117
|
+
allMatches.push(...fileMatches);
|
|
63118
|
+
}
|
|
63119
|
+
return {
|
|
63120
|
+
results: allMatches,
|
|
63121
|
+
totalMatches,
|
|
63122
|
+
returnedMatches: allMatches.length,
|
|
63123
|
+
truncated: totalMatches > maxResults,
|
|
63124
|
+
filesSearched: filesToSearch.length
|
|
63125
|
+
};
|
|
63126
|
+
}
|
|
63127
|
+
function registerSearchQlCodeTool(server) {
|
|
63128
|
+
server.tool(
|
|
63129
|
+
"search_ql_code",
|
|
63130
|
+
"Search QL source files (.ql/.qll) for text or regex patterns. Returns structured results with file paths, line numbers, and optional context lines. Use this instead of grep for searching CodeQL source code.",
|
|
63131
|
+
{
|
|
63132
|
+
pattern: external_exports.string().describe("Text or regex pattern to search for (JavaScript regex syntax)"),
|
|
63133
|
+
paths: external_exports.array(external_exports.string()).min(1).describe("Directories or files to search in"),
|
|
63134
|
+
includeExtensions: external_exports.array(external_exports.string()).optional().default([".ql", ".qll"]).describe("File extensions to search (default: ['.ql', '.qll'])"),
|
|
63135
|
+
caseSensitive: external_exports.boolean().optional().default(true).describe("Whether search is case sensitive (default: true)"),
|
|
63136
|
+
contextLines: external_exports.number().int().min(0).max(MAX_CONTEXT_LINES).optional().default(0).describe("Lines of context before and after each match (default: 0, max: 50)"),
|
|
63137
|
+
maxResults: external_exports.number().int().min(1).max(MAX_MAX_RESULTS).optional().default(100).describe("Maximum number of matching lines to return (default: 100, max: 10000)")
|
|
63138
|
+
},
|
|
63139
|
+
async ({ pattern, paths, includeExtensions, caseSensitive, contextLines, maxResults }) => {
|
|
63140
|
+
try {
|
|
63141
|
+
const result = await searchQlCode({
|
|
63142
|
+
pattern,
|
|
63143
|
+
paths,
|
|
63144
|
+
includeExtensions,
|
|
63145
|
+
caseSensitive,
|
|
63146
|
+
contextLines,
|
|
63147
|
+
maxResults
|
|
63148
|
+
});
|
|
63149
|
+
return {
|
|
63150
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
63151
|
+
};
|
|
63152
|
+
} catch (error2) {
|
|
63153
|
+
logger.error("Error in search_ql_code:", error2);
|
|
63154
|
+
const message = error2 instanceof SyntaxError || error2 instanceof Error && error2.message.includes("Invalid regular expression") ? `Invalid regex pattern: ${error2.message}` : `Error: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
63155
|
+
return {
|
|
63156
|
+
content: [{ type: "text", text: message }],
|
|
63157
|
+
isError: true
|
|
63158
|
+
};
|
|
63159
|
+
}
|
|
63160
|
+
}
|
|
63161
|
+
);
|
|
63162
|
+
}
|
|
63163
|
+
|
|
62473
63164
|
// src/tools/codeql/test-accept.ts
|
|
62474
63165
|
var codeqlTestAcceptTool = {
|
|
62475
63166
|
name: "codeql_test_accept",
|
|
@@ -62740,6 +63431,7 @@ function registerCodeQLTools(server) {
|
|
|
62740
63431
|
registerCLITool(server, codeqlQueryFormatTool);
|
|
62741
63432
|
registerCLITool(server, codeqlQueryRunTool);
|
|
62742
63433
|
registerCLITool(server, codeqlResolveDatabaseTool);
|
|
63434
|
+
registerCLITool(server, codeqlResolveFilesTool);
|
|
62743
63435
|
registerCLITool(server, codeqlResolveLanguagesTool);
|
|
62744
63436
|
registerCLITool(server, codeqlResolveLibraryPathTool);
|
|
62745
63437
|
registerCLITool(server, codeqlResolveMetadataTool);
|
|
@@ -62760,78 +63452,201 @@ function registerCodeQLTools(server) {
|
|
|
62760
63452
|
registerQuickEvaluateTool(server);
|
|
62761
63453
|
registerReadDatabaseSourceTool(server);
|
|
62762
63454
|
registerRegisterDatabaseTool(server);
|
|
63455
|
+
registerSearchQlCodeTool(server);
|
|
62763
63456
|
}
|
|
62764
63457
|
|
|
63458
|
+
// src/resources/dataflow-migration-v1-to-v2.md
|
|
63459
|
+
var dataflow_migration_v1_to_v2_default = '# Dataflow API Migration: v1 to v2\n\nGuide for migrating CodeQL queries from the legacy v1 (class-based) dataflow API to the modern v2 (module-based) shared dataflow API. This applies to all supported languages.\n\n## Why Migrate\n\nThe v1 `DataFlow::Configuration` class-based API is deprecated. The v2 `DataFlow::ConfigSig` module-based API is the current standard across all languages. Queries using v1 will eventually stop compiling as the legacy API is removed.\n\n## API Changes Summary\n\n| v1 (Legacy) | v2 (Modern) | Notes |\n| ------------------------------------------------ | ------------------------------------------------ | --------------------------------------- |\n| `class MyConfig extends DataFlow::Configuration` | `module MyConfig implements DataFlow::ConfigSig` | Module-based, not class-based |\n| `MyConfig() { this = "MyConfig" }` | _(removed)_ | No constructor needed |\n| `override predicate isSanitizer(...)` | `predicate isBarrier(...)` | Renamed |\n| `override predicate isAdditionalTaintStep(...)` | `predicate isAdditionalFlowStep(...)` | Renamed |\n| `config.hasFlowPath(source, sink)` | `MyFlow::flowPath(source, sink)` | Module-level predicate |\n| `DataFlow::PathNode` | `MyFlow::PathNode` | Path nodes scoped to flow module |\n| `isSanitizerGuard` | _(removed \u2014 use `isBarrier` with guard logic)_ | Fold guard into barrier |\n| `FlowLabel` (JS) | `FlowState` | Renamed; use `DataFlow::StateConfigSig` |\n\n## v1 Pattern\n\n```ql\nclass MyConfig extends DataFlow::Configuration {\n MyConfig() { this = "MyConfig" }\n override predicate isSource(DataFlow::Node source) { ... }\n override predicate isSink(DataFlow::Node sink) { ... }\n override predicate isSanitizer(DataFlow::Node node) { ... }\n override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) { ... }\n}\n\nfrom MyConfig config, DataFlow::PathNode source, DataFlow::PathNode sink\nwhere config.hasFlowPath(source, sink)\nselect sink, source, sink, "Message"\n```\n\n## v2 Pattern\n\n```ql\nmodule MyConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) { ... }\n predicate isSink(DataFlow::Node sink) { ... }\n predicate isBarrier(DataFlow::Node node) { ... }\n predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) { ... }\n}\n\nmodule MyFlow = TaintTracking::Global<MyConfig>;\nimport MyFlow::PathGraph\n\nfrom MyFlow::PathNode source, MyFlow::PathNode sink\nwhere MyFlow::flowPath(source, sink)\nselect sink.getNode(), source, sink, "Message"\n```\n\n## Migration Workflow\n\n1. **Capture baseline**: Run `codeql_test_run` on existing tests and save current `.expected` files\n2. **Rewrite config**: Replace the `class extends Configuration` with `module implements ConfigSig`, rename predicates per the table above\n3. **Instantiate module**: Add `module MyFlow = TaintTracking::Global<MyConfig>;` (or `DataFlow::Global<MyConfig>` for pure data flow)\n4. **Update select clause**: Replace `config.hasFlowPath(source, sink)` with `MyFlow::flowPath(source, sink)` and `DataFlow::PathNode` with `MyFlow::PathNode`\n5. **Handle flow state**: If the query uses `FlowLabel` (JS) or state-sensitive predicates, switch to `DataFlow::StateConfigSig` and `TaintTracking::GlobalWithState<MyConfig>`\n6. **Compile**: Run `codeql_query_compile` to catch syntax errors\n7. **Test**: Run `codeql_test_run` and verify results match the v1 baseline exactly\n8. **Accept**: Once equivalent, run `codeql_test_accept` to finalize\n\n## Language-Specific Notes\n\n### C/C++\n\n- Import paths stay the same (`semmle.code.cpp.dataflow.TaintTracking`); only the API usage changes.\n- Pointer indirection: use `asIndirectExpr()` in `isAdditionalFlowStep` to track through dereferences.\n- Track `std::move` operations as additional flow steps when relevant.\n- `IndirectParameterNode` usage is unchanged between v1 and v2.\n\n### C\\#\n\n- Use `semmle.code.csharp.dataflow.TaintTracking` (same import for v1 and v2).\n- `LibraryTypeDataFlow` extensions for custom library flow are unchanged.\n- Test LINQ, async/await, and property accessor patterns \u2014 these can surface subtle differences.\n- ASP.NET `[FromBody]`/`[FromQuery]` parameter annotations work identically.\n\n### Go\n\n- Node types (`ExprNode`, `ParameterNode`, `InstructionNode`) and AST/IR conversions (`asExpr()`, `asInstruction()`) are unchanged.\n- `RemoteFlowSource` and `UntrustedFlowSource` work identically in v2.\n- Channel send/receive and goroutine flow require `isAdditionalFlowStep`; these patterns are unchanged.\n- Error-handling tuples: use `ResultNode` with `hasResultIndex(0)` for the value element.\n- Interface type assertions (`TypeAssertExpr`) need explicit flow steps.\n\n### Java / Kotlin\n\n- `InstanceParameterNode` (implicit `this`) is unchanged.\n- Spring `@RequestParam`/`@PathVariable`/`@RequestBody` annotations work identically.\n- Stream/lambda/method-reference flows and boxing/unboxing steps carry over directly.\n- Kotlin `when` expressions and extension function receiver flow require explicit `isAdditionalFlowStep`.\n\n### JavaScript / TypeScript\n\n- **Flow labels \u2192 Flow states**: If the v1 query uses `FlowLabel`, switch to `DataFlow::StateConfigSig` with `class FlowState = string;` and `TaintTracking::GlobalWithState<MyConfig>`.\n- **Sanitizer guards \u2192 Barrier guards**: `isSanitizerGuard` becomes `isBarrierGuard` with `DataFlow::BarrierGuard`.\n- **Behavioral changes**: v2 taint steps propagate all flow states (not just `taint`). Jump steps across function boundaries (callbacks, Promises) may behave differently \u2014 watch for new or missing results.\n- Promise `.then()` and async/await flow, prototype pollution via `Object.assign`/spread, and module import/export flow are unchanged.\n\n### Python\n\n- Python has multiple dataflow nodes per expression due to CFG splitting. This behavior is identical in v2.\n- `CfgNode` / `CallCfgNode` / `getCfgNode()` conversions are unchanged.\n- API graph navigation (`API::moduleImport("pkg").getMember(...)`) is unchanged.\n- Django ORM, Flask routing, and FastAPI dependency injection patterns carry over directly.\n\n### Ruby\n\n- `asExpr()` returns `CfgNodes::ExprCfgNode` (CFG node, not AST). Use `.getExpr()` to get the AST node. This is unchanged between v1 and v2.\n- Rails `params`, ActiveRecord queries, and metaprogramming (`send`, `define_method`, `eval`) patterns carry over directly.\n- String interpolation and block/lambda flows are unchanged.\n\n### Swift\n\n- Import paths differ from other languages: `codeql.swift.dataflow.DataFlow`, `codeql.swift.dataflow.TaintTracking`, `codeql.swift.dataflow.FlowSources`.\n- Unique node types: `PatternNode`, `CaptureNode`, `InoutReturnNode`, `SsaDefinitionNode`.\n- `RemoteFlowSource` and `LocalFlowSource` from `codeql.swift.dataflow.FlowSources` work identically.\n- Requires macOS with Xcode for test extraction. Supports Swift 5.4\u20136.2.\n\n## Critical: Result Equivalence\n\nMigrated queries **must** produce identical results to the v1 version. Differences indicate a semantic change in the migration. Common causes:\n\n- **Barrier scope**: v2 barriers block all flow states; v1 sanitizers may have been state-specific\n- **Additional flow steps**: v2 uses `isAdditionalFlowStep` for both data flow and taint; v1 had separate `isAdditionalTaintStep`\n- **Jump steps** (JS): Taint propagation across function boundaries may differ\n';
|
|
63460
|
+
|
|
63461
|
+
// src/resources/learning-query-basics.md
|
|
63462
|
+
var learning_query_basics_default = '# Writing CodeQL Queries\n\nThis resource is a practical reference for writing CodeQL queries using the MCP server\'s tools. It covers query structure, metadata annotations, common QL patterns, compilation, testing, and the file conventions used by the CodeQL test framework.\n\n## Query Structure\n\nEvery CodeQL query has three main clauses:\n\n```ql\n/**\n * @name Descriptive name of what the query finds\n * @description Longer explanation of the vulnerability or pattern\n * @kind problem\n * @problem.severity warning\n * @precision medium\n * @id lang/query-id\n * @tags security\n * correctness\n */\n\nimport language\n\nfrom SourceType source, SinkType sink\nwhere <conditions linking source to sink>\nselect <result expression>, <message string>\n```\n\n### `from` Clause\n\nDeclares typed variables. Each variable ranges over all values of its type in the database:\n\n```ql\nfrom Function f, FunctionCall call\n```\n\n### `where` Clause\n\nFilters the cross-product of `from` variables using predicates:\n\n```ql\nwhere call.getTarget() = f\n and f.getName() = "eval"\n```\n\n### `select` Clause\n\nDefines the output columns. The first expression is the "element" (the location in source code), followed by a message string:\n\n```ql\nselect call, "Call to dangerous function " + f.getName()\n```\n\n## Metadata Annotations\n\nMetadata goes in a QLDoc comment block (`/** ... */`) at the top of the query file:\n\n| Annotation | Required | Description |\n| -------------------- | ---------------------------- | ------------------------------------------------------------ |\n| `@name` | Yes | Short human-readable name |\n| `@description` | Yes | Explanation of the query\'s purpose |\n| `@kind` | Yes | Output format: `problem`, `path-problem`, `table`, `graph` |\n| `@id` | Yes | Unique identifier (e.g., `js/sql-injection`) |\n| `@problem.severity` | For `problem`/`path-problem` | `error`, `warning`, or `recommendation` |\n| `@security-severity` | For security queries | CVSS score (e.g., `8.8`) |\n| `@precision` | Recommended | `very-high`, `high`, `medium`, or `low` |\n| `@tags` | Recommended | Categories like `security`, `correctness`, `maintainability` |\n\nUse `codeql_resolve_metadata` to extract and validate a query\'s metadata.\n\n## Common `@kind` Values\n\n- **`problem`** \u2014 Reports a single location with a message. Use `select element, message`.\n- **`path-problem`** \u2014 Reports a source-to-sink data flow path. Requires a `PathGraph` import and `select sink, source, sink, message`.\n- **`table`** \u2014 Generic tabular output (no alert interpretation).\n- **`graph`** \u2014 Structural output (AST, CFG, call graphs). Used by `PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo` tool queries.\n\n## Common QL Patterns\n\n### Predicate Definition\n\n```ql\npredicate isUserInput(DataFlow::Node node) {\n exists(Parameter p | p = node.asParameter() |\n p.getFunction().isPublic()\n )\n}\n```\n\n### Class Definition\n\n```ql\nclass DangerousCall extends MethodCall {\n DangerousCall() {\n this.getMethodName() = ["exec", "eval", "system"]\n }\n}\n```\n\n### Existential Quantifier (`exists`)\n\n```ql\nwhere exists(Assignment a | a.getLhs() = var and a.getRhs() instanceof NullLiteral)\n```\n\n### Aggregates\n\n```ql\nselect f, count(FunctionCall call | call.getTarget() = f) as callCount\n order by callCount desc\n```\n\n## Taint Tracking / Data Flow Configuration (v2 API)\n\n```ql\nmodule MyFlowConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n // define sources\n }\n\n predicate isSink(DataFlow::Node sink) {\n // define sinks\n }\n\n predicate isBarrier(DataFlow::Node node) {\n // define sanitizers (optional)\n }\n}\n\nmodule MyFlow = TaintTracking::Global<MyFlowConfig>;\n```\n\n## Query Compilation and Validation\n\nUse these tools to validate queries at different fidelity levels:\n\n| Tool | Speed | Fidelity | When to Use |\n| ------------------------ | ------- | ------------------ | ----------------------------------------------------------------- |\n| `validate_codeql_query` | Instant | Heuristic only | Quick structure check (no compilation) |\n| `codeql_query_compile` | Fast | Full compilation | Syntax and type checking |\n| `codeql_lsp_diagnostics` | Fast | Full (single file) | Real-time validation during editing (cannot resolve pack imports) |\n\nTypical workflow:\n\n1. `validate_codeql_query` \u2014 quick structural check\n2. `codeql_query_compile` with `checkOnly: true` \u2014 full compilation\n3. `codeql_lsp_diagnostics` \u2014 interactive feedback during editing\n\n## Test File Conventions\n\nCodeQL query tests use this directory layout:\n\n```text\npack-root/\n\u251C\u2500\u2500 src/\n\u2502 \u251C\u2500\u2500 codeql-pack.yml # Source pack\n\u2502 \u2514\u2500\u2500 MyQuery/\n\u2502 \u2514\u2500\u2500 MyQuery.ql # The query\n\u2514\u2500\u2500 test/\n \u251C\u2500\u2500 codeql-pack.yml # Test pack\n \u2514\u2500\u2500 MyQuery/\n \u251C\u2500\u2500 MyQuery.qlref # Points to ../../src/MyQuery/MyQuery.ql\n \u251C\u2500\u2500 test.js # Test source code (language-appropriate)\n \u2514\u2500\u2500 MyQuery.expected # Expected query output\n```\n\n- **`.qlref` file**: Contains the relative path from the test pack\'s `src/` directory to the query file.\n- **`.expected` file**: Contains the expected output of running the query against the test code. Use `codeql_test_accept` to generate or update this file.\n- **Test source code**: Write code with both positive cases (should trigger the query) and negative cases (should not trigger).\n\n### Running Tests\n\n1. `codeql_test_run` \u2014 run tests and compare against `.expected` files\n2. `codeql_test_accept` \u2014 update `.expected` files when results are verified correct\n3. `codeql_resolve_tests` \u2014 discover and validate test structure\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/queries` \u2014 Bundled tools queries (PrintAST, PrintCFG, CallGraphFrom, CallGraphTo)\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://templates/security` \u2014 Security query templates\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n';
|
|
63463
|
+
|
|
63464
|
+
// src/resources/performance-patterns.md
|
|
63465
|
+
var performance_patterns_default = '# Performance Optimization Patterns\n\nThis resource describes how to evaluate and improve the performance of CodeQL queries using the MCP server\'s profiling tools. Rather than prescribing generic optimization rules, it focuses on using the `profile_codeql_query_from_logs` tool and the `explain_codeql_query` prompt to make evidence-based performance improvements.\n\n## Primary Performance Tool: `profile_codeql_query_from_logs`\n\nThe `profile_codeql_query_from_logs` tool is the primary means of evaluating the actual performance of a CodeQL query. It parses existing CodeQL evaluator logs into a structured performance profile without re-running the query.\n\n### Workflow\n\n1. **Run the query**: Use `codeql_query_run` with `evaluationOutput` set to a directory path. This generates evaluator log files.\n2. **Profile**: Use `profile_codeql_query_from_logs` to parse the evaluator log. Returns compact JSON with the slowest predicates (by wall-clock time) and per-predicate metrics. Full RA operations and pipeline-stage tuple progressions are in a line-indexed detail file \u2014 use `read_file` with the `detailLines` ranges from the response to drill into any predicate.\n3. **Identify bottlenecks**: Review the profile JSON for predicates with high evaluation times, tuple count explosions in pipeline stages, or expensive RA operations (large JOINs, cross-products).\n4. **Refine**: Modify the query to address identified bottlenecks, then re-run and re-profile to verify improvements.\n\n### What the Profile Shows\n\n- **Predicate evaluation times** \u2014 which predicates are the most expensive\n- **Tuple counts** \u2014 how many intermediate results each predicate produces\n- **Pipeline stages** \u2014 the internal evaluation plan chosen by the CodeQL engine\n- **RA (relational algebra) operations** \u2014 join orders, aggregation steps, and recursive evaluations\n\n## Using `explain_codeql_query` for Performance Understanding\n\nThe `explain_codeql_query` prompt generates a detailed explanation of a query, including Mermaid evaluation diagrams that visualize the data flow and evaluation order. This is useful for understanding _why_ a query may be slow before profiling.\n\n## Key Performance Concepts\n\nThe following concepts are relevant when interpreting profiling output. Verify these against actual profiling data rather than applying them blindly.\n\n### Large Intermediate Result Sets\n\nWhen a predicate produces significantly more tuples than expected, it may indicate:\n\n- Missing or insufficiently restrictive filter conditions in the `where` clause\n- A cross-product between two large relations that should be joined more tightly\n\n**How to detect**: Look for predicates in the profile output with high tuple counts relative to their expected output size.\n\n### Recursive Predicate Costs\n\nRecursive predicates (e.g., transitive closures via `+` or `*`) can be expensive when the underlying relation is large. The profiler shows iteration counts and per-iteration tuple growth.\n\n**How to detect**: Look for recursive predicates with many iterations or high per-iteration costs in the profile output.\n\n### Join Order Sensitivity\n\nThe CodeQL evaluator chooses a join order for predicates in the `where` clause. In some cases, the chosen order may not be optimal.\n\n**How to detect**: Look for pipeline stages where a large intermediate result is produced before being filtered down. The profiler shows tuple counts at each stage.\n\n### Improving "Performance" \u2014 Two Dimensions\n\nThe word "performance" for CodeQL queries has two meanings:\n\n1. **Runtime efficiency** \u2014 how fast the query evaluates. Addressed by reducing tuple counts, improving join orders, and simplifying recursive predicates.\n2. **Result quality** \u2014 how accurate the query\'s output is (precision and recall). Addressed by refining source/sink/sanitizer definitions, adding or removing filter conditions, and testing against diverse codebases.\n\nThe `profile_codeql_query_from_logs` tool addresses runtime efficiency. For result quality, use the `run_query_and_summarize_false_positives` prompt and the `sarif_rank_false_positives` / `sarif_rank_true_positives` prompts.\n\n## Performance Review for GitHub Actions CodeQL Scans\n\nWhen reviewing CodeQL performance in the context of GitHub Actions CI/CD scans, key areas to examine include:\n\n### Code Exclusion\n\nExcluding non-essential files from analysis (vendored dependencies, generated code, test files) is one of the most impactful performance improvements. Any interpreted language or compiled language using `build-mode: none` can use a `paths-ignore` array in the CodeQL configuration file to exclude paths.\n\n### Hardware Sizing\n\nRecommended runner sizes based on lines of code:\n\n- Small (< 100K lines): 8 GB RAM, 2 cores\n- Medium (100K\u20131M lines): 16 GB RAM, 4\u20138 cores\n- Large (> 1M lines): 64 GB RAM, 8 cores\n\n### Monorepo Splitting\n\nFor monorepos with multiple independent applications separated by process/network boundaries, consider splitting CodeQL scans by application. This reduces database size and enables parallel scanning via Actions matrix strategies.\n\n## Related Tools and Prompts\n\n| Tool / Prompt | Purpose |\n| ------------------------------------------------ | -------------------------------------------------------- |\n| `profile_codeql_query_from_logs` | Profile from existing evaluator logs (primary tool) |\n| `codeql_generate_log-summary` | Optional: human-readable evaluator log summary |\n| `codeql_query_run` | Execute a query (set `evaluationOutput` to capture logs) |\n| `explain_codeql_query` prompt | Understand query evaluation flow with Mermaid diagrams |\n| `run_query_and_summarize_false_positives` prompt | Assess result quality (precision) |\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://learning/query-basics` \u2014 Query structure and compilation tools\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for iterative query improvement\n';
|
|
63466
|
+
|
|
63467
|
+
// src/resources/ql-test-driven-development.md
|
|
63468
|
+
var ql_test_driven_development_default = "# Test-Driven Development for CodeQL Queries\n\nThis resource explains the theory and value of test-driven development (TDD) for CodeQL queries, and how the MCP server's tools and prompts support the TDD workflow. It is a conceptual overview \u2014 for step-by-step guided workflows, use the `test_driven_development`, `ql_tdd_basic`, or `ql_tdd_advanced` prompts.\n\n## Why TDD for CodeQL?\n\nCodeQL queries are programs that search for patterns in source code. Like any program, they can have bugs: false positives (flagging safe code), false negatives (missing vulnerable code), and runtime performance issues. TDD addresses all three by establishing a feedback loop between expected and actual behavior.\n\n### Why TDD Makes LLMs More Effective\n\nLLMs generating CodeQL queries face two challenges:\n\n1. **Syntactic correctness** \u2014 QL has unique syntax (classes, predicates, `exists`, aggregates) that differs from mainstream languages. Compilation via `codeql_query_compile` catches syntax errors early.\n2. **Semantic correctness** \u2014 A query that compiles may still produce wrong results. Test cases with `.expected` files provide ground truth that the LLM can compare against, enabling iterative refinement.\n\nTDD provides the LLM with a concrete, automated signal (tests pass / tests fail) at every iteration, replacing guesswork with evidence. This is especially valuable for data flow and taint tracking queries where the correctness of source/sink/sanitizer definitions can only be verified by running the query against representative code.\n\n## The TDD Cycle\n\n```text\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 1. Write Tests \u2502 \u2190 Define expected behavior through test cases\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 2. Run (Red) \u2502 \u2190 Verify tests fail (no query logic yet)\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 3. Implement \u2502 \u2190 Write minimal query logic to pass tests\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 4. Run (Green) \u2502 \u2190 Verify tests pass\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 5. Refactor \u2502 \u2190 Improve query while keeping tests green\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n \u25BC\n\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 6. Repeat \u2502 \u2190 Add more tests for additional scenarios\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n## The Value of AST Data in Test Code\n\nA critical step in the TDD workflow is running `PrintAST` on test source code before writing the query. The AST output reveals how the CodeQL database represents the test code \u2014 which QL classes correspond to which source constructs, and which predicates are available for matching.\n\nWithout AST data, the LLM must guess which classes and predicates to use, leading to trial-and-error. With AST data, the LLM can:\n\n- **Map source patterns to QL classes**: See exactly which QL class represents a `for` loop, a method call, or an assignment\n- **Discover available predicates**: Learn what methods are available on each AST node type\n- **Write precise `from`/`where` clauses**: Use the correct class names and predicate calls from the start\n\nUse `codeql_query_run` with `queryName=\"PrintAST\"` to generate AST data for test source files. The `ql_tdd_advanced` prompt guides this step in detail.\n\n## MCP Tools for TDD\n\n| Step | Tool | Purpose |\n| ------------ | ------------------------------------- | ---------------------------------------------------- |\n| Scaffold | `create_codeql_query` | Generate query, test, and `.qlref` files |\n| Dependencies | `codeql_pack_install` | Install pack dependencies for src and test packs |\n| Extract | `codeql_test_extract` | Create a test database from test source files |\n| AST Analysis | `codeql_query_run` (PrintAST) | Understand test code structure via AST |\n| CFG Analysis | `codeql_query_run` (PrintCFG) | Understand control flow (advanced) |\n| Call Graph | `codeql_query_run` (CallGraphFrom/To) | Trace call relationships (advanced) |\n| Compile | `codeql_query_compile` | Validate query syntax before testing |\n| Test | `codeql_test_run` | Run tests and compare against `.expected` |\n| Accept | `codeql_test_accept` | Update `.expected` when results are verified correct |\n| Profile | `profile_codeql_query_from_logs` | Analyze query performance from evaluator logs |\n| Format | `codeql_query_format` | Auto-format query source code |\n| Metadata | `codeql_resolve_metadata` | Validate query metadata annotations |\n\n## MCP Prompts for TDD\n\n| Prompt | When to Use |\n| ------------------------- | ---------------------------------------------------------- |\n| `test_driven_development` | End-to-end TDD workflow with required `language` parameter |\n| `ql_tdd_basic` | Standalone TDD checklist (all parameters optional) |\n| `ql_tdd_advanced` | Extended TDD with AST/CFG/call graph analysis |\n| `tools_query_workflow` | Focused exploration of code structure via tool queries |\n| `explain_codeql_query` | Understand an existing query's logic before modifying it |\n\n## Writing Effective Test Cases\n\n### Structure\n\nEach test directory contains:\n\n- **Test source code** (e.g., `test.js`) \u2014 code that the query will analyze\n- **`.qlref` file** \u2014 points to the query being tested\n- **`.expected` file** \u2014 the expected query output\n\n### Best Practices\n\n1. **Include both positive and negative cases**: Write code that should trigger the query (vulnerable patterns) and code that should not (safe patterns)\n2. **Start simple**: Begin with the most obvious positive and negative cases, then add edge cases\n3. **Use realistic code**: Test against code patterns that occur in real-world projects\n4. **One concept per test directory**: Each test should verify one specific behavior\n5. **Document intent**: Use comments in test code to explain why each case should or should not match\n\n### Example Test Structure\n\n```text\ntest/SqlInjection/\n\u251C\u2500\u2500 SqlInjection.qlref # Points to src/SqlInjection/SqlInjection.ql\n\u251C\u2500\u2500 test.py # Test source code\n\u2514\u2500\u2500 SqlInjection.expected # Expected results\n```\n\nThe `.expected` file contains one line per query result, matching the `select` clause output.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation and quick-start guide\n- `codeql://learning/query-basics` \u2014 Query structure, metadata, and compilation reference\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://templates/security` \u2014 Security query templates with TDD workflow\n- `codeql://patterns/performance` \u2014 Performance profiling tools\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n- `codeql://languages/{language}/security` \u2014 Language-specific security patterns\n";
|
|
63469
|
+
|
|
63470
|
+
// src/resources/codeql-query-unit-testing.md
|
|
63471
|
+
var codeql_query_unit_testing_default = '# CodeQL Query Unit Testing\n\nGuide for creating and running unit tests for CodeQL queries. For the broader TDD workflow (write tests, implement, iterate), see the `test_driven_development` resource and `ql_tdd_basic` / `ql_tdd_advanced` prompts.\n\n## Test Directory Layout\n\nThere is no one single way to arrange CodeQL unit tests, though there are some commonalities.\n\nFor a recommended setup that uses separate "qlpacks" for CodeQL queries versus tests, a given CodeQL query and associated unit test may be laid out on the filesystem like:\n\n```text\n<query-pack-root>/<optional-queries-subdir>/{QueryName}/\n\u251C\u2500\u2500 {QueryName}.{md,qhelp} # Recommended query documentation file\n\u251C\u2500\u2500 {QueryName}.ql # Required query implementation file\n\u2514\u2500\u2500 {QueryName}.qll # Optional query-specific library file\n<test-pack-root>/<optional-tests-subdir>/{QueryOrTestName}/\n\u251C\u2500\u2500 {QueryName}.qlref # qlref file contents point to the path of the query, relative to <query-pack-root>\n\u251C\u2500\u2500 Example1.{ext} # Test source code (positive + negative cases)\n\u251C\u2500\u2500 {QueryName}.actual # Actual test results; created dynamically via `codeql_test_run` tool\n\u251C\u2500\u2500 {QueryName}.expected # Expected query results; defined prior to calling `codeql_test_run` tool\n\u2514\u2500\u2500 {QueryName}.testproj/ # Test database; auto-created by `codeql_test_extract` or `codeql_test_run` tools\n```\n\n## File Extensions by Language\n\n| Language | Test source extension(s) | Notes |\n| ---------- | ------------------------ | ---------------------------------------- |\n| C/C++ | `.cpp`, `.c`, `.h` | Use header files for shared declarations |\n| C# | `.cs` | |\n| Go | `.go` | Must include `package` declaration |\n| Java | `.java` | Must include `class` matching filename |\n| JavaScript | `.js` | Use `.ts` for TypeScript |\n| Python | `.py` | |\n| Ruby | `.rb` | |\n| Swift | `.swift` | |\n\n## Creating a Test\n\n### 1. Query Reference File (`{QueryName}.qlref`)\n\nSingle line with the path to the query, relative to the query pack root:\n\n```sh\nsrc/{QueryName}/{QueryName}.ql\n```\n\n### 2. Test Source Code\n\nWrite test source files containing:\n\n- **Positive cases**: Code patterns the query **should** detect\n- **Negative cases**: Safe code the query **should not** flag\n- **Edge cases**: Boundary conditions and unusual but valid patterns\n\nAdd comments to describe what each section tests.\n\n### 3. Expected Results (`{QueryName}.expected`)\n\nTabular format matching the query\'s `select` clause columns:\n\n```text\n| file | line | col | endLine | endCol | message |\n| Example1.js | 5 | 1 | 7 | 2 | Function: myFunc |\n```\n\nLeave the file empty or create it with a placeholder initially \u2014 run the query to generate actual results, then baseline with `codeql_test_accept`.\n\n## Language-Specific Notes\n\n### C/C++\n\n- Use an `options` file in the test directory to set the C++ standard (e.g., `--std=c++17`).\n- Include header files with include guards when testing patterns that span headers.\n- Test pointer/reference, smart pointer, template instantiation, and STL container patterns as relevant.\n- Key AST nodes: `Function`, `MemberFunction`, `Constructor`, `Class`, `Struct`, `PointerDereferenceExpr`, `FunctionCall`, `NewExpr`, `DeleteExpr`, `TemplateClass`, `TemplateFunction`.\n\n### C\\#\n\n- Always include required `using` statements so test code compiles.\n- Test .NET-specific patterns: LINQ, async/await, properties, pattern matching, ASP.NET controllers, Entity Framework.\n- Key AST nodes: `Class`, `Method`, `Property`, `MethodCall`, `QueryExpr`, `AwaitExpr`, `Annotation`.\n\n### Go\n\n- Every test file must have a `package` declaration (typically `package main`).\n- Test goroutine, channel, interface assertion, and error-handling patterns as relevant.\n- Key AST nodes: `Function`, `CallExpr`, `SelectorExpr`, `GoStmt`, `SendStmt`, `TypeAssertExpr`.\n\n### Java\n\n- Each `.java` test file must contain a `public class` matching the filename.\n- Test annotations, generics, lambda expressions, streams, and try-with-resources as relevant.\n- Supports Spring, Servlet, and Jakarta EE framework patterns.\n- Key AST nodes: `Method`, `Constructor`, `Class`, `MethodCall`, `LambdaExpr`, `MethodReference`, `Annotation`, `TypeVariable`.\n\n### JavaScript / TypeScript\n\n- Both CommonJS (`require`) and ES modules (`import`) are supported.\n- Use `.ts` for TypeScript; JSX is supported in `.jsx`/`.tsx` files.\n- Test browser APIs (DOM, `document.write`), Node.js APIs (`child_process`, `fs`), and framework patterns (Express, React) as relevant.\n- Test async/await, Promises, and callback patterns.\n- Key AST nodes: `Function`, `ArrowFunctionExpr`, `CallExpr`, `MethodCallExpr`, `PropAccess`, `AwaitExpr`, `TemplateLiteral`.\n\n### Python\n\n- Supports both Python 2 and Python 3 syntax.\n- Test decorators, async/await, type hints, and dynamic code execution (`eval`, `exec`) as relevant.\n- Test framework patterns: Django (ORM, templates), Flask (request, routing), FastAPI (dependency injection).\n- Key AST nodes: `FunctionDef`, `ClassDef`, `Call`, `Attribute`, `Name`, `Lambda`, `Await`.\n\n### Ruby\n\n- Test metaprogramming (`send`, `define_method`, `eval`), blocks/lambdas, and string interpolation as relevant.\n- Test Rails patterns (params, ActiveRecord, ActionView) and gem-specific APIs (Sinatra, Grape).\n- Note: `asExpr()` in Ruby returns `CfgNodes::ExprCfgNode` (CFG node), not an AST node; use `.getExpr()` to get the AST node.\n- Key AST nodes: `MethodCall`, `Block`, `StringInterpolation`, `ConstantReadAccess`.\n\n### Swift\n\n- Requires macOS with Xcode installed for test extraction.\n- Supports Swift 5.4 through 6.2.\n- Test iOS/macOS framework patterns: Foundation, UIKit, Security, CryptoKit, WKWebView.\n- Test actors, property wrappers, async/await, and result builders as relevant.\n- Key AST nodes: `ClassDecl`, `StructDecl`, `FuncDecl`, `CallExpr`, `MemberRefExpr`, `ClosureExpr`, `GuardStmt`.\n\n## MCP Tool Workflow\n\n| Step | Tool | Purpose |\n| --------------------- | ----------------------------- | ----------------------------------------- |\n| Create test files | `create_codeql_query` | Scaffold query + test + `.qlref` |\n| Install dependencies | `codeql_pack_install` | Install pack dependencies |\n| Extract test database | `codeql_test_extract` | Build test DB from source files |\n| Inspect AST | `codeql_query_run` (PrintAST) | Understand how test code is represented |\n| Run tests | `codeql_test_run` | Compare actual vs. expected results |\n| Accept results | `codeql_test_accept` | Baseline correct results into `.expected` |\n';
|
|
63472
|
+
|
|
63473
|
+
// src/resources/security-templates.md
|
|
63474
|
+
var security_templates_default = '# Security Query Templates\n\nThis resource provides actionable security query templates for multiple languages and vulnerability classes. Each template shows the recommended query structure, explains how to adapt it, and references the MCP tools and TDD workflow to use during development.\n\n## General Workflow for Security Queries\n\n1. **Scaffold**: Use `create_codeql_query` to generate the query, test, and `.qlref` files\n2. **Write tests**: Create test source code with vulnerable (positive) and safe (negative) examples\n3. **Analyze AST**: Use `codeql_query_run` with `queryName="PrintAST"` to understand code representation\n4. **Implement**: Write the query using the taint tracking / data flow template below\n5. **Compile**: Use `codeql_query_compile` to validate syntax\n6. **Test**: Use `codeql_test_run` to run tests; iterate until all pass\n7. **Accept**: Use `codeql_test_accept` to baseline correct results\n\nSee the `test_driven_development` or `ql_tdd_basic` prompts for guided step-by-step workflows.\n\n## Taint Tracking Template (v2 API)\n\nMost security queries use taint tracking to find data flowing from untrusted sources to dangerous sinks. The standard template structure for all languages is:\n\n```ql\n/**\n * @name <Vulnerability Name>\n * @description <Description of the vulnerability>\n * @kind path-problem\n * @problem.severity error\n * @security-severity <CVSS score>\n * @precision high\n * @id <lang>/<vulnerability-id>\n * @tags security\n * external/cwe/cwe-<NNN>\n */\n\nimport <language>\n\nmodule MyFlowConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n // Define untrusted input sources\n }\n\n predicate isSink(DataFlow::Node sink) {\n // Define dangerous sinks\n }\n\n predicate isBarrier(DataFlow::Node node) {\n // Define sanitizers that make data safe (optional)\n }\n}\n\nmodule MyFlow = TaintTracking::Global<MyFlowConfig>;\n\nimport MyFlow::PathGraph\n\nfrom MyFlow::PathNode source, MyFlow::PathNode sink\nwhere MyFlow::flowPath(source, sink)\nselect sink.getNode(), source, sink, "Tainted data from $@ reaches this sink.",\n source.getNode(), "user-provided value"\n```\n\n### Adapting the Template\n\n1. **Choose sources**: Identify where untrusted data enters (HTTP parameters, file reads, environment variables)\n2. **Choose sinks**: Identify where data becomes dangerous (SQL queries, command execution, HTML output)\n3. **Add sanitizers**: Identify validation or encoding functions that neutralize the threat\n4. **Adjust metadata**: Set appropriate `@security-severity`, `@id`, and CWE tags\n\n## Source, Sink, and Sanitizer Patterns\n\n### Defining Sources\n\nSources represent entry points for untrusted data. The most common pattern uses `RemoteFlowSource`:\n\n```ql\npredicate isSource(DataFlow::Node source) {\n source instanceof RemoteFlowSource\n}\n```\n\n### Defining Sinks\n\nSinks are locations where untrusted data causes harm. Identify the dangerous API call and pin the taint to the relevant argument position:\n\n```ql\npredicate isSink(DataFlow::Node sink) {\n exists(CallExpr dangerousCall |\n dangerousCall.getTarget().hasName("vulnerableFunction") and\n sink.asExpr() = dangerousCall.getArgument(0)\n )\n}\n```\n\n### Defining Sanitizers (Barriers)\n\nSanitizers stop taint propagation when data is validated or encoded. Return `true` for nodes where the taint is neutralized:\n\n```ql\npredicate isBarrier(DataFlow::Node node) {\n exists(CallExpr validationCall |\n validationCall.getTarget().hasName("sanitize") and\n node.asExpr() = validationCall\n )\n}\n```\n\n## Language-Specific Guidance\n\nEach language has pre-built security libraries in the CodeQL standard library. Import these instead of writing source/sink definitions from scratch when possible.\n\n### Go\n\n- **SQL Injection**: Import `semmle.go.security.SqlInjection` \u2014 provides `SqlInjection::Flow` module with pre-defined sources and sinks. Tag with CWE-089, severity 8.8.\n- **Command Injection**: Import `semmle.go.security.CommandInjection`.\n- See `codeql://languages/go/security` for Go-specific framework modeling.\n\n### JavaScript / TypeScript\n\n- **DOM-based XSS**: Import `semmle.javascript.security.dataflow.DomBasedXss` \u2014 provides `DomBasedXss::Flow` module. Tag with CWE-079, severity 6.1.\n- **SQL Injection**: Import `semmle.javascript.security.dataflow.SqlInjection`.\n- See `codeql://languages/javascript/security` for JavaScript-specific patterns.\n\n### Python\n\n- **Command Injection**: Import `semmle.python.security.dataflow.CommandInjection`. Tag with CWE-078, severity 9.8.\n- **SQL Injection**: Import `semmle.python.security.dataflow.SqlInjection`.\n- See `codeql://languages/python/security` for Python-specific patterns.\n\n### Java / Kotlin\n\n- **SQL Injection**: Import `semmle.java.security.SqlInjectionQuery` \u2014 provides `SqlInjectionFlow` module. Tag with CWE-089, severity 8.8.\n- **SSRF**: Import `semmle.java.security.RequestForgery`.\n\n### C# (.NET)\n\n- **Path Traversal**: Import `semmle.csharp.security.dataflow.PathInjection`. Tag with CWE-022, severity 7.5.\n- **SQL Injection**: Import `semmle.csharp.security.dataflow.SqlInjection`.\n- See `codeql://languages/csharp/security` for C#-specific patterns.\n\n### C / C++\n\n- **Buffer Overflow**: Import `semmle.code.cpp.security.BufferAccess`. Tag with CWE-120, severity 9.8.\n- See `codeql://languages/cpp/security` for C/C++-specific patterns.\n\n## Vulnerability Classes Reference\n\n| Vulnerability | CWE | Typical Sources | Typical Sinks |\n| ----------------- | ------- | ---------------------------------- | ----------------------------- |\n| SQL Injection | CWE-089 | HTTP parameters, form data | Database query functions |\n| XSS | CWE-079 | HTTP parameters, URL data | HTML output, DOM writes |\n| Command Injection | CWE-078 | HTTP parameters, config files | `exec`, `system`, `popen` |\n| Path Traversal | CWE-022 | HTTP parameters, file names | File system access functions |\n| SSRF | CWE-918 | HTTP parameters, user URLs | HTTP client request functions |\n| Code Injection | CWE-094 | HTTP parameters, deserialized data | `eval`, template engines |\n| LDAP Injection | CWE-090 | HTTP parameters | LDAP query functions |\n| XML Injection | CWE-091 | HTTP parameters | XML parsers, XPath queries |\n\n## Related Resources\n\n- `codeql://learning/query-basics` \u2014 Query structure and metadata reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for developing queries\n- `codeql://patterns/performance` \u2014 Performance optimization guidance\n- `codeql://languages/{language}/security` \u2014 Language-specific security patterns and framework modeling\n';
|
|
63475
|
+
|
|
63476
|
+
// src/resources/server-overview.md
|
|
63477
|
+
var server_overview_default = '# CodeQL Development MCP Server \u2014 Getting Started\n\nThis resource is the primary onboarding guide for LLM clients connecting to the CodeQL Development MCP Server. It explains what the server provides, which tools and prompts are available, and how to orchestrate common workflows.\n\n## What This Server Does\n\nThe CodeQL Development MCP Server wraps the CodeQL CLI and supporting utilities behind the Model Context Protocol (MCP). It exposes **tools** (executable actions), **prompts** (reusable workflow templates), and **resources** (reference material) that enable an LLM to develop, test, and analyze CodeQL queries without direct shell access.\n\n## Available Resources\n\nRead these resources via `resources/read` to deepen your understanding:\n\n| URI | Purpose |\n| --------------------------------------------- | --------------------------------------------------- |\n| `codeql://server/overview` | This guide \u2014 MCP server orientation |\n| `codeql://server/queries` | Bundled tools queries (PrintAST, PrintCFG, etc.) |\n| `codeql://server/tools` | Complete default tool reference |\n| `codeql://server/prompts` | Complete prompt reference |\n| `codeql://learning/query-basics` | QL query writing reference (syntax, metadata, etc.) |\n| `codeql://learning/test-driven-development` | TDD theory and workflow for CodeQL |\n| `codeql://templates/security` | Security query templates (multi-language) |\n| `codeql://patterns/performance` | Performance profiling and optimization |\n| `codeql://guides/query-unit-testing` | Guide for creating and running CodeQL query tests |\n| `codeql://guides/dataflow-migration-v1-to-v2` | Migrating from v1 to v2 dataflow API |\n| `codeql://languages/{language}/ast` | Language-specific AST class reference |\n| `codeql://languages/{language}/security` | Language-specific security patterns |\n\n## Quick-Start Workflows\n\n### 1. Create a New Query (TDD Approach)\n\nUse the `test_driven_development` prompt (or `ql_tdd_basic` / `ql_tdd_advanced`):\n\n1. `create_codeql_query` \u2014 scaffold query, test files, and `.qlref`\n2. `codeql_pack_install` \u2014 install pack dependencies\n3. Write test code with positive and negative cases\n4. `codeql_test_run` \u2014 run tests (expect failure initially)\n5. Implement query logic\n6. `codeql_query_compile` \u2014 validate syntax\n7. `codeql_test_run` \u2014 iterate until tests pass\n8. `codeql_test_accept` \u2014 accept correct results as baseline\n\n### 2. Understand Code Structure\n\nUse the `tools_query_workflow` prompt:\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\n\n### 3. Analyze Query Quality\n\n1. `codeql_database_analyze` \u2014 run queries against a database\n2. `profile_codeql_query` or `profile_codeql_query_from_logs` \u2014 analyze performance\n3. `run_query_and_summarize_false_positives` prompt \u2014 assess precision\n4. `sarif_rank_false_positives` / `sarif_rank_true_positives` prompts \u2014 rank results\n\n### 4. Iterative Development with LSP\n\nUse the `ql_lsp_iterative_development` prompt:\n\n1. `codeql_lsp_completion` \u2014 get code completions while writing QL\n2. `codeql_lsp_definition` \u2014 navigate to symbol definitions\n3. `codeql_lsp_references` \u2014 find all references to a symbol\n4. `codeql_lsp_diagnostics` \u2014 real-time syntax and semantic validation\n\n## Tool Categories\n\nThe server provides default tools across these categories (see `codeql://server/tools` for the full reference):\n\n- **CodeQL CLI tools** \u2014 Database creation, query compilation, execution, result decoding, pack management\n- **LSP tools** \u2014 Code completion, go-to-definition, find references, diagnostics\n- **Query development tools** \u2014 Scaffolding, validation, profiling, quick evaluation, database registration\n\n## Prompt Categories\n\nThe server provides **11 prompts** (see `codeql://server/prompts` for the full reference):\n\n- **Test-driven development** \u2014 `test_driven_development`, `ql_tdd_basic`, `ql_tdd_advanced`\n- **Code understanding** \u2014 `tools_query_workflow`, `explain_codeql_query`\n- **Iterative development** \u2014 `ql_lsp_iterative_development`\n- **Documentation and quality** \u2014 `document_codeql_query`, `run_query_and_summarize_false_positives`, `sarif_rank_false_positives`, `sarif_rank_true_positives`\n- **Workshop creation** \u2014 `workshop_creation_workflow`\n\n## Key Concepts\n\n- **CodeQL database**: A relational representation of source code created by `codeql_database_create`. All queries execute against a database.\n- **QL pack**: A directory containing `codeql-pack.yml` with query or library code. Use `codeql_pack_install` to resolve dependencies.\n- **`.qlref` file**: A test reference that points from a test directory to the query being tested.\n- **`.expected` file**: The expected output of a query test. Use `codeql_test_accept` to update it when results are correct.\n- **BQRS**: Binary Query Result Sets \u2014 the native output format of `codeql_query_run`. Decode with `codeql_bqrs_decode` or interpret with `codeql_bqrs_interpret`.\n- **SARIF**: Static Analysis Results Interchange Format \u2014 the standard output format for `codeql_database_analyze`.\n\n## Supported Languages\n\nThe server supports CodeQL queries for: `actions`, `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `swift`.\n';
|
|
63478
|
+
|
|
63479
|
+
// src/resources/server-prompts.md
|
|
63480
|
+
var server_prompts_default = "# MCP Server Prompts\n\nThis resource provides a complete reference of the prompts exposed by the CodeQL Development MCP Server. Prompts are reusable workflow templates that guide the LLM through common CodeQL development tasks. Invoke a prompt via the MCP `prompts/get` protocol.\n\n## Prompt Reference\n\n| Prompt | Description |\n| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------- |\n| `document_codeql_query` | Create or update standardized markdown documentation for a CodeQL query |\n| `explain_codeql_query` | Generate a detailed explanation of a CodeQL query with Mermaid evaluation diagrams |\n| `ql_lsp_iterative_development` | Iterative CodeQL query development using LSP tools for completion, navigation, and validation |\n| `ql_tdd_advanced` | Advanced test-driven CodeQL development with AST visualization, control flow, and call graph analysis |\n| `ql_tdd_basic` | Test-driven CodeQL query development checklist \u2014 write tests first, implement query, iterate until tests pass |\n| `run_query_and_summarize_false_positives` | Run a CodeQL query and summarize its false positives by root cause |\n| `sarif_rank_false_positives` | Analyze SARIF results to identify and rank likely false positives |\n| `sarif_rank_true_positives` | Analyze SARIF results to identify and rank likely true positives |\n| `test_driven_development` | End-to-end test-driven development workflow for CodeQL queries using MCP tools |\n| `tools_query_workflow` | Guide for using PrintAST, PrintCFG, CallGraphFrom, and CallGraphTo tool queries to understand code structure |\n| `workshop_creation_workflow` | Guide for creating multi-exercise CodeQL query development workshops from production-grade queries |\n\n## Prompt Categories\n\n### Test-Driven Development\n\n- **`test_driven_development`** \u2014 The primary TDD prompt. Requires a `language` parameter and optionally accepts `queryName`. Loads the `ql-tdd-basic.prompt.md` template and walks through the complete TDD cycle: scaffold \u2192 write tests \u2192 implement \u2192 compile \u2192 test \u2192 iterate.\n- **`ql_tdd_basic`** \u2014 A standalone TDD checklist. All parameters are optional. Covers the core loop: write test cases, implement the query, run tests, iterate.\n- **`ql_tdd_advanced`** \u2014 Extends basic TDD with AST visualization (`PrintAST`), control flow graph analysis (`PrintCFG`), and call graph exploration (`CallGraphFrom`, `CallGraphTo`). Optionally accepts a `database` path for immediate analysis.\n\n### Code Understanding\n\n- **`tools_query_workflow`** \u2014 Orchestrates the four built-in tool queries (PrintAST, PrintCFG, CallGraphFrom, CallGraphTo) to explore how source code is represented in a CodeQL database. Requires `language` and `database` parameters.\n- **`explain_codeql_query`** \u2014 Produces a verbal explanation of a query's logic and generates Mermaid diagrams showing the evaluation flow. Requires `queryPath` and `language`.\n\n### Iterative Development\n\n- **`ql_lsp_iterative_development`** \u2014 Combines LSP-based code completions (`codeql_lsp_completion`), go-to-definition (`codeql_lsp_definition`), find-references (`codeql_lsp_references`), and diagnostics (`codeql_lsp_diagnostics`) for an interactive development loop.\n\n### Documentation and Quality\n\n- **`document_codeql_query`** \u2014 Generates standardized markdown documentation as a sibling `.md` file to a query. Requires `queryPath` and `language`.\n- **`run_query_and_summarize_false_positives`** \u2014 Runs a CodeQL query on a database and groups results into false-positive categories by root cause.\n- **`sarif_rank_false_positives`** / **`sarif_rank_true_positives`** \u2014 Analyze SARIF output to assess query precision by ranking results as likely true or false positives.\n\n### Workshop Creation\n\n- **`workshop_creation_workflow`** \u2014 Guides the creation of multi-exercise workshops that teach CodeQL query development. Requires `queryPath` and `language`, optionally accepts `workshopName` and `numStages`.\n\n## Related Resources\n\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 theory and workflow overview\n";
|
|
63481
|
+
|
|
63482
|
+
// src/resources/server-queries.md
|
|
63483
|
+
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 four 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\nAll four 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## Language Support\n\n| Language | PrintAST | PrintCFG | CallGraphFrom | CallGraphTo |\n| ---------- | :------: | :------: | :-----------: | :---------: |\n| actions | \u2713 | \u2713 | | |\n| cpp | \u2713 | \u2713 | \u2713 | \u2713 |\n| csharp | \u2713 | \u2713 | \u2713 | \u2713 |\n| go | \u2713 | \u2713 | \u2713 | \u2713 |\n| java | \u2713 | \u2713 | \u2713 | \u2713 |\n| javascript | \u2713 | \u2713 | \u2713 | \u2713 |\n| python | \u2713 | \u2713 | \u2713 | \u2713 |\n| ruby | \u2713 | \u2713 | \u2713 | \u2713 |\n| swift | \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. **Write detection queries**: Use the insights from steps 2\u20134 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';
|
|
63484
|
+
|
|
63485
|
+
// src/resources/server-tools.md
|
|
63486
|
+
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## 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\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## 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';
|
|
63487
|
+
|
|
62765
63488
|
// src/lib/resources.ts
|
|
62766
|
-
|
|
62767
|
-
|
|
62768
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
62769
|
-
var __filename2 = fileURLToPath3(import.meta.url);
|
|
62770
|
-
var __dirname2 = dirname8(__filename2);
|
|
62771
|
-
function getGettingStartedGuide() {
|
|
62772
|
-
try {
|
|
62773
|
-
return readFileSync10(join15(__dirname2, "../resources/getting-started.md"), "utf-8");
|
|
62774
|
-
} catch {
|
|
62775
|
-
return "Getting started guide not available";
|
|
62776
|
-
}
|
|
63489
|
+
function getLearningQueryBasics() {
|
|
63490
|
+
return learning_query_basics_default;
|
|
62777
63491
|
}
|
|
62778
|
-
function
|
|
62779
|
-
|
|
62780
|
-
return readFileSync10(join15(__dirname2, "../resources/query-basics.md"), "utf-8");
|
|
62781
|
-
} catch {
|
|
62782
|
-
return "Query basics guide not available";
|
|
62783
|
-
}
|
|
63492
|
+
function getPerformancePatterns() {
|
|
63493
|
+
return performance_patterns_default;
|
|
62784
63494
|
}
|
|
62785
63495
|
function getSecurityTemplates() {
|
|
62786
|
-
|
|
62787
|
-
return readFileSync10(join15(__dirname2, "../resources/security-templates.md"), "utf-8");
|
|
62788
|
-
} catch {
|
|
62789
|
-
return "Security templates not available";
|
|
62790
|
-
}
|
|
63496
|
+
return security_templates_default;
|
|
62791
63497
|
}
|
|
62792
|
-
function
|
|
62793
|
-
|
|
62794
|
-
|
|
62795
|
-
|
|
62796
|
-
|
|
62797
|
-
|
|
63498
|
+
function getServerOverview() {
|
|
63499
|
+
return server_overview_default;
|
|
63500
|
+
}
|
|
63501
|
+
function getServerPrompts() {
|
|
63502
|
+
return server_prompts_default;
|
|
63503
|
+
}
|
|
63504
|
+
function getServerQueries() {
|
|
63505
|
+
return server_queries_default;
|
|
63506
|
+
}
|
|
63507
|
+
function getServerTools() {
|
|
63508
|
+
return server_tools_default;
|
|
63509
|
+
}
|
|
63510
|
+
function getTestDrivenDevelopment() {
|
|
63511
|
+
return ql_test_driven_development_default;
|
|
63512
|
+
}
|
|
63513
|
+
function getQueryUnitTesting() {
|
|
63514
|
+
return codeql_query_unit_testing_default;
|
|
63515
|
+
}
|
|
63516
|
+
function getDataflowMigration() {
|
|
63517
|
+
return dataflow_migration_v1_to_v2_default;
|
|
62798
63518
|
}
|
|
62799
63519
|
|
|
62800
63520
|
// src/tools/codeql-resources.ts
|
|
62801
63521
|
function registerCodeQLResources(server) {
|
|
62802
63522
|
server.resource(
|
|
62803
|
-
"CodeQL
|
|
62804
|
-
"codeql://learning/
|
|
63523
|
+
"CodeQL Query Basics",
|
|
63524
|
+
"codeql://learning/query-basics",
|
|
62805
63525
|
{
|
|
62806
|
-
description: "
|
|
63526
|
+
description: "QL query writing reference: syntax, metadata, from/where/select, common patterns, testing conventions",
|
|
62807
63527
|
mimeType: "text/markdown"
|
|
62808
63528
|
},
|
|
62809
63529
|
async () => {
|
|
62810
63530
|
return {
|
|
62811
63531
|
contents: [
|
|
62812
63532
|
{
|
|
62813
|
-
uri: "codeql://learning/
|
|
63533
|
+
uri: "codeql://learning/query-basics",
|
|
62814
63534
|
mimeType: "text/markdown",
|
|
62815
|
-
text:
|
|
63535
|
+
text: getLearningQueryBasics()
|
|
62816
63536
|
}
|
|
62817
63537
|
]
|
|
62818
63538
|
};
|
|
62819
63539
|
}
|
|
62820
63540
|
);
|
|
62821
63541
|
server.resource(
|
|
62822
|
-
"CodeQL
|
|
62823
|
-
"codeql://learning/
|
|
63542
|
+
"CodeQL Test-Driven Development",
|
|
63543
|
+
"codeql://learning/test-driven-development",
|
|
62824
63544
|
{
|
|
62825
|
-
description: "
|
|
63545
|
+
description: "TDD theory and workflow for developing CodeQL queries with MCP tools",
|
|
62826
63546
|
mimeType: "text/markdown"
|
|
62827
63547
|
},
|
|
62828
63548
|
async () => {
|
|
62829
63549
|
return {
|
|
62830
63550
|
contents: [
|
|
62831
63551
|
{
|
|
62832
|
-
uri: "codeql://learning/
|
|
63552
|
+
uri: "codeql://learning/test-driven-development",
|
|
62833
63553
|
mimeType: "text/markdown",
|
|
62834
|
-
text:
|
|
63554
|
+
text: getTestDrivenDevelopment()
|
|
63555
|
+
}
|
|
63556
|
+
]
|
|
63557
|
+
};
|
|
63558
|
+
}
|
|
63559
|
+
);
|
|
63560
|
+
server.resource(
|
|
63561
|
+
"CodeQL Performance Patterns",
|
|
63562
|
+
"codeql://patterns/performance",
|
|
63563
|
+
{
|
|
63564
|
+
description: "Performance profiling and optimization for CodeQL queries",
|
|
63565
|
+
mimeType: "text/markdown"
|
|
63566
|
+
},
|
|
63567
|
+
async () => {
|
|
63568
|
+
return {
|
|
63569
|
+
contents: [
|
|
63570
|
+
{
|
|
63571
|
+
uri: "codeql://patterns/performance",
|
|
63572
|
+
mimeType: "text/markdown",
|
|
63573
|
+
text: getPerformancePatterns()
|
|
63574
|
+
}
|
|
63575
|
+
]
|
|
63576
|
+
};
|
|
63577
|
+
}
|
|
63578
|
+
);
|
|
63579
|
+
server.resource(
|
|
63580
|
+
"CodeQL Server Overview",
|
|
63581
|
+
"codeql://server/overview",
|
|
63582
|
+
{
|
|
63583
|
+
description: "MCP server orientation guide: available tools, prompts, resources, and workflows",
|
|
63584
|
+
mimeType: "text/markdown"
|
|
63585
|
+
},
|
|
63586
|
+
async () => {
|
|
63587
|
+
return {
|
|
63588
|
+
contents: [
|
|
63589
|
+
{
|
|
63590
|
+
uri: "codeql://server/overview",
|
|
63591
|
+
mimeType: "text/markdown",
|
|
63592
|
+
text: getServerOverview()
|
|
63593
|
+
}
|
|
63594
|
+
]
|
|
63595
|
+
};
|
|
63596
|
+
}
|
|
63597
|
+
);
|
|
63598
|
+
server.resource(
|
|
63599
|
+
"CodeQL Server Prompts",
|
|
63600
|
+
"codeql://server/prompts",
|
|
63601
|
+
{
|
|
63602
|
+
description: "Complete reference of MCP prompts for CodeQL development workflows",
|
|
63603
|
+
mimeType: "text/markdown"
|
|
63604
|
+
},
|
|
63605
|
+
async () => {
|
|
63606
|
+
return {
|
|
63607
|
+
contents: [
|
|
63608
|
+
{
|
|
63609
|
+
uri: "codeql://server/prompts",
|
|
63610
|
+
mimeType: "text/markdown",
|
|
63611
|
+
text: getServerPrompts()
|
|
63612
|
+
}
|
|
63613
|
+
]
|
|
63614
|
+
};
|
|
63615
|
+
}
|
|
63616
|
+
);
|
|
63617
|
+
server.resource(
|
|
63618
|
+
"CodeQL Server Queries",
|
|
63619
|
+
"codeql://server/queries",
|
|
63620
|
+
{
|
|
63621
|
+
description: "Overview of bundled tools queries: PrintAST, PrintCFG, CallGraphFrom, CallGraphTo",
|
|
63622
|
+
mimeType: "text/markdown"
|
|
63623
|
+
},
|
|
63624
|
+
async () => {
|
|
63625
|
+
return {
|
|
63626
|
+
contents: [
|
|
63627
|
+
{
|
|
63628
|
+
uri: "codeql://server/queries",
|
|
63629
|
+
mimeType: "text/markdown",
|
|
63630
|
+
text: getServerQueries()
|
|
63631
|
+
}
|
|
63632
|
+
]
|
|
63633
|
+
};
|
|
63634
|
+
}
|
|
63635
|
+
);
|
|
63636
|
+
server.resource(
|
|
63637
|
+
"CodeQL Server Tools",
|
|
63638
|
+
"codeql://server/tools",
|
|
63639
|
+
{
|
|
63640
|
+
description: "Complete reference of default MCP tools for CodeQL development",
|
|
63641
|
+
mimeType: "text/markdown"
|
|
63642
|
+
},
|
|
63643
|
+
async () => {
|
|
63644
|
+
return {
|
|
63645
|
+
contents: [
|
|
63646
|
+
{
|
|
63647
|
+
uri: "codeql://server/tools",
|
|
63648
|
+
mimeType: "text/markdown",
|
|
63649
|
+
text: getServerTools()
|
|
62835
63650
|
}
|
|
62836
63651
|
]
|
|
62837
63652
|
};
|
|
@@ -62841,7 +63656,7 @@ function registerCodeQLResources(server) {
|
|
|
62841
63656
|
"CodeQL Security Templates",
|
|
62842
63657
|
"codeql://templates/security",
|
|
62843
63658
|
{
|
|
62844
|
-
description: "
|
|
63659
|
+
description: "Security query templates for multiple languages and vulnerability classes",
|
|
62845
63660
|
mimeType: "text/markdown"
|
|
62846
63661
|
},
|
|
62847
63662
|
async () => {
|
|
@@ -62857,19 +63672,38 @@ function registerCodeQLResources(server) {
|
|
|
62857
63672
|
}
|
|
62858
63673
|
);
|
|
62859
63674
|
server.resource(
|
|
62860
|
-
"CodeQL
|
|
62861
|
-
"codeql://
|
|
63675
|
+
"CodeQL Query Unit Testing",
|
|
63676
|
+
"codeql://guides/query-unit-testing",
|
|
62862
63677
|
{
|
|
62863
|
-
description: "
|
|
63678
|
+
description: "Guide for creating and running CodeQL query unit tests across all supported languages",
|
|
62864
63679
|
mimeType: "text/markdown"
|
|
62865
63680
|
},
|
|
62866
63681
|
async () => {
|
|
62867
63682
|
return {
|
|
62868
63683
|
contents: [
|
|
62869
63684
|
{
|
|
62870
|
-
uri: "codeql://
|
|
63685
|
+
uri: "codeql://guides/query-unit-testing",
|
|
62871
63686
|
mimeType: "text/markdown",
|
|
62872
|
-
text:
|
|
63687
|
+
text: getQueryUnitTesting()
|
|
63688
|
+
}
|
|
63689
|
+
]
|
|
63690
|
+
};
|
|
63691
|
+
}
|
|
63692
|
+
);
|
|
63693
|
+
server.resource(
|
|
63694
|
+
"CodeQL Dataflow Migration v1 to v2",
|
|
63695
|
+
"codeql://guides/dataflow-migration-v1-to-v2",
|
|
63696
|
+
{
|
|
63697
|
+
description: "Guide for migrating CodeQL queries from legacy v1 dataflow API to modern v2 module-based API",
|
|
63698
|
+
mimeType: "text/markdown"
|
|
63699
|
+
},
|
|
63700
|
+
async () => {
|
|
63701
|
+
return {
|
|
63702
|
+
contents: [
|
|
63703
|
+
{
|
|
63704
|
+
uri: "codeql://guides/dataflow-migration-v1-to-v2",
|
|
63705
|
+
mimeType: "text/markdown",
|
|
63706
|
+
text: getDataflowMigration()
|
|
62873
63707
|
}
|
|
62874
63708
|
]
|
|
62875
63709
|
};
|
|
@@ -62880,13 +63714,13 @@ function registerCodeQLResources(server) {
|
|
|
62880
63714
|
// src/tools/lsp/lsp-diagnostics.ts
|
|
62881
63715
|
init_logger();
|
|
62882
63716
|
init_temp_dir();
|
|
62883
|
-
import { join as
|
|
63717
|
+
import { join as join17 } from "path";
|
|
62884
63718
|
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
62885
63719
|
|
|
62886
63720
|
// src/tools/lsp/lsp-server-helper.ts
|
|
62887
63721
|
init_server_manager();
|
|
62888
63722
|
init_logger();
|
|
62889
|
-
import { isAbsolute as isAbsolute5, resolve as
|
|
63723
|
+
import { isAbsolute as isAbsolute5, resolve as resolve11 } from "path";
|
|
62890
63724
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
62891
63725
|
async function getInitializedLanguageServer(opts = {}) {
|
|
62892
63726
|
const { packageRootDir: pkgRoot, getUserWorkspaceDir: getUserWorkspaceDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
@@ -62894,7 +63728,7 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
62894
63728
|
const config2 = {
|
|
62895
63729
|
checkErrors: "ON_CHANGE",
|
|
62896
63730
|
loglevel: options.loglevel ?? "WARN",
|
|
62897
|
-
searchPath: options.searchPath ??
|
|
63731
|
+
searchPath: options.searchPath ?? resolve11(pkgRoot, "ql"),
|
|
62898
63732
|
synchronous: options.synchronous,
|
|
62899
63733
|
verbosity: options.verbosity
|
|
62900
63734
|
};
|
|
@@ -62902,10 +63736,10 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
62902
63736
|
const server = await manager.getLanguageServer(config2);
|
|
62903
63737
|
let effectiveUri = opts.workspaceUri;
|
|
62904
63738
|
if (effectiveUri && !effectiveUri.startsWith("file://")) {
|
|
62905
|
-
const absWorkspace = isAbsolute5(effectiveUri) ? effectiveUri :
|
|
63739
|
+
const absWorkspace = isAbsolute5(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
|
|
62906
63740
|
effectiveUri = pathToFileURL2(absWorkspace).href;
|
|
62907
63741
|
}
|
|
62908
|
-
effectiveUri = effectiveUri ?? pathToFileURL2(
|
|
63742
|
+
effectiveUri = effectiveUri ?? pathToFileURL2(resolve11(pkgRoot, "ql")).href;
|
|
62909
63743
|
await server.initialize(effectiveUri);
|
|
62910
63744
|
logger.debug(`Language server initialized with workspace: ${effectiveUri}`);
|
|
62911
63745
|
return server;
|
|
@@ -62978,7 +63812,7 @@ async function lspDiagnostics({
|
|
|
62978
63812
|
serverOptions,
|
|
62979
63813
|
workspaceUri
|
|
62980
63814
|
});
|
|
62981
|
-
const evalUri = pathToFileURL3(
|
|
63815
|
+
const evalUri = pathToFileURL3(join17(getProjectTmpDir("lsp-eval"), `eval_${Date.now()}.ql`)).href;
|
|
62982
63816
|
const diagnostics = await languageServer.evaluateQL(qlCode, evalUri);
|
|
62983
63817
|
const summary = {
|
|
62984
63818
|
errorCount: diagnostics.filter((d) => d.severity === 1).length,
|
|
@@ -63067,7 +63901,7 @@ function registerLspDiagnosticsTool(server) {
|
|
|
63067
63901
|
init_logger();
|
|
63068
63902
|
init_package_paths();
|
|
63069
63903
|
import { readFile as readFile3 } from "fs/promises";
|
|
63070
|
-
import { isAbsolute as isAbsolute6, resolve as
|
|
63904
|
+
import { isAbsolute as isAbsolute6, resolve as resolve12 } from "path";
|
|
63071
63905
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
63072
63906
|
async function getInitializedServer(params) {
|
|
63073
63907
|
return getInitializedLanguageServer({
|
|
@@ -63076,7 +63910,7 @@ async function getInitializedServer(params) {
|
|
|
63076
63910
|
});
|
|
63077
63911
|
}
|
|
63078
63912
|
function prepareDocumentPosition(params) {
|
|
63079
|
-
const absPath = isAbsolute6(params.filePath) ? params.filePath :
|
|
63913
|
+
const absPath = isAbsolute6(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
|
|
63080
63914
|
const docUri = pathToFileURL4(absPath).href;
|
|
63081
63915
|
return { absPath, docUri };
|
|
63082
63916
|
}
|
|
@@ -63251,83 +64085,107 @@ function registerLSPTools(server) {
|
|
|
63251
64085
|
);
|
|
63252
64086
|
}
|
|
63253
64087
|
|
|
63254
|
-
// src/resources/
|
|
63255
|
-
|
|
63256
|
-
|
|
64088
|
+
// src/resources/languages/actions_ast.md
|
|
64089
|
+
var actions_ast_default = '# CodeQL AST nodes for `actions` language\n\n## CodeQL\'s core AST classes for `actions` language\n\nBased on analysis of CodeQL\'s Actions AST test results from local test files, here are the core AST classes for GitHub Actions analysis:\n\n### Top-Level Action and Workflow Structures\n\n**Action Files (action.yml):**\n\n- `CompositeActionImpl` - Root composite action declaration (e.g., `name: "Hello World"`)\n- Action metadata including name, description, and runtime configuration\n\n**Workflow Files (.github/workflows/\\*.yml):**\n\n- `WorkflowImpl` - Root workflow declaration (e.g., `name: Reusable workflow example`)\n- Complete workflow structure with events, jobs, and steps\n\n### Event Handling\n\n**Event Triggers:**\n\n- `OnImpl` - Event trigger definitions (e.g., `workflow_call:`)\n- `EventImpl` - Specific event types (e.g., `workflow_call`)\n- Event configuration with inputs, outputs, and secrets\n\n### Input and Output Management\n\n**Input Structures:**\n\n- `InputsImpl` - Input containers for actions and workflows\n- `InputImpl` - Individual input definitions (e.g., `who-to-greet`, `config-path`)\n- Input properties: description, required, type, default values\n\n**Output Structures:**\n\n- `OutputsImpl` - Output containers for workflows and jobs\n- Output value expressions and job output references\n\n### Job Management\n\n**Job Structure:**\n\n- `JobImpl` - Job definitions (e.g., `Job: job1`)\n- Job configuration including runner, outputs, and steps\n- Job-level environment and dependency management\n\n**Job Execution Environment:**\n\n- Runner specifications (e.g., `ubuntu-latest`)\n- Job outputs and step output references\n\n### Step Execution\n\n**Step Types:**\n\n- `StepImpl` - Generic step containers\n- `Run Step` - Steps with shell commands and scripts\n- `Uses Step` - Steps using external actions\n\n**Step Components:**\n\n- Step identification and naming\n- Shell command execution\n- External action usage (e.g., `tj-actions/changed-files@v40`)\n\n### Environment and Variable Management\n\n**Environment Variables:**\n\n- `EnvImpl` - Environment variable definitions\n- Environment variable scoping (step-level, job-level)\n- Variable interpolation and expression evaluation\n\n### Expression System\n\n**Expression Handling:**\n\n- `ExpressionImpl` - GitHub Actions expressions (e.g., `inputs.who-to-greet`, `jobs.job1.outputs.job-output1`)\n- Expression contexts: inputs, steps, jobs, github, env\n- Complex expression evaluation and context access\n\n**Expression Contexts:**\n\n- Input references: `inputs.config-path`, `inputs.who-to-greet`\n- Step output references: `steps.step1.outputs.step-output`, `steps.step2.outputs.all_changed_files`\n- Job output references: `jobs.job1.outputs.job-output1`\n\n### Value and Data Types\n\n**Scalar Values:**\n\n- `ScalarValueImpl` - String literals, booleans, and scalar data\n- Configuration values (e.g., `"Hello World"`, `"composite"`, `true`)\n- Command strings and action references\n\n**Value Types:**\n\n- String values for names, descriptions, commands\n- Boolean values for required flags and conditions\n- Action references and version specifications\n\n### Action Runtime Configuration\n\n**Composite Actions:**\n\n- `using: "composite"` runtime specification\n- Step sequence execution within composite actions\n- Input parameter passing and environment setup\n\n**Action Metadata:**\n\n- Action names and descriptions\n- Input/output specifications\n- Runtime environment configuration\n\n### Shell and Command Execution\n\n**Command Execution:**\n\n- Shell command strings (e.g., `echo "Hello $INPUT_WHO_TO_GREET."`)\n- Shell specification (e.g., `bash`)\n- Multi-line command support\n\n**Environment Integration:**\n\n- Environment variable usage in commands\n- Variable substitution and expansion\n- Input-to-environment variable mapping\n\n### External Action Integration\n\n**Action Usage:**\n\n- External action references (e.g., `tj-actions/changed-files@v40`)\n- Version pinning and action marketplace integration\n- Action parameter passing and configuration\n\n### Workflow Reusability\n\n**Reusable Workflows:**\n\n- Workflow call triggers and parameters\n- Input/output parameter definitions\n- Secret management and passing\n\n**Workflow Composition:**\n\n- Job dependencies and sequencing\n- Output propagation between jobs\n- Workflow-level input and output management\n\n### Security and Secrets\n\n**Secret Management:**\n\n- Secret declarations and requirements\n- Secret passing in reusable workflows\n- Secure environment variable handling\n\n### Example AST Hierarchy\n\nBased on CodeQL\'s GitHub Actions analysis capabilities:\n\n```\nWorkflowImpl (root workflow)\n\u251C\u2500\u2500 OnImpl (event triggers)\n\u2502 \u2514\u2500\u2500 EventImpl (specific events like workflow_call)\n\u251C\u2500\u2500 InputsImpl (workflow inputs)\n\u2502 \u2514\u2500\u2500 InputImpl (individual inputs)\n\u251C\u2500\u2500 OutputsImpl (workflow outputs)\n\u251C\u2500\u2500 JobImpl (job definitions)\n\u2502 \u251C\u2500\u2500 OutputsImpl (job outputs)\n\u2502 \u2514\u2500\u2500 StepImpl (job steps)\n\u2502 \u251C\u2500\u2500 EnvImpl (step environment)\n\u2502 \u2514\u2500\u2500 ScalarValueImpl (step commands/actions)\n\u2514\u2500\u2500 ScalarValueImpl (scalar values throughout)\n\nCompositeActionImpl (root action)\n\u251C\u2500\u2500 InputsImpl (action inputs)\n\u251C\u2500\u2500 RunsImpl (execution configuration)\n\u2514\u2500\u2500 StepImpl (action steps)\n \u251C\u2500\u2500 EnvImpl (step environment)\n \u2514\u2500\u2500 ScalarValueImpl (commands and values)\n\nExpressionImpl (expressions like ${{ inputs.name }})\n\u2514\u2500\u2500 Context access (inputs, steps, jobs, github, env)\n```\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `actions` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="actions"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n';
|
|
64090
|
+
|
|
64091
|
+
// src/resources/languages/cpp_ast.md
|
|
64092
|
+
var cpp_ast_default = '# CodeQL AST nodes for `cpp` language\n\n## CodeQL\'s core AST classes for `cpp` language\n\nBased on comprehensive analysis of CodeQL\'s C++ AST test results from both local and GitHub test files, here are the core AST classes for C/C++ analysis:\n\n### Function and Method Declarations\n\n**Function Types:**\n\n- `TopLevelFunction` - Global functions (e.g., `void fun3(someClass*)`, `int main()`)\n- `MemberFunction` - Class member functions (e.g., `void someClass::f()`, `int someClass::g(int, int)`)\n- `VirtualFunction` - Virtual functions with dynamic dispatch (e.g., `virtual void Base::v()`)\n- `ConstMemberFunction` - Const member functions (e.g., `char const* std::type_info::name() const`)\n- `FormattingFunction` - Functions with format string checking (e.g., `int printf(char const*)`)\n- `TemplateFunction` - Template function declarations\n\n**Constructors and Destructors:**\n\n- `Constructor` - Class constructors (e.g., `void C::C(int)`)\n- `CopyConstructor` - Copy constructors (e.g., `void C::C(C const&)`)\n- `CopyAssignmentOperator` - Copy assignment operators (e.g., `C& C::operator=(C const&)`)\n- `MoveAssignmentOperator` - Move assignment operators (e.g., `C& C::operator=(C&&)`)\n- `Destructor` - Destructor declarations\n- `DestructorCall` - Explicit and implicit destructor calls (e.g., `call to ~C`)\n\n**Operator Functions:**\n\n- `Operator` - Operator overloads (e.g., `void operator delete(void*)`, `void* operator new(unsigned long)`)\n\n### Statements\n\n**Control Flow Statements:**\n\n- `BlockStmt` - Block statements containing multiple statements (e.g., `{ ... }`)\n- `IfStmt` - Conditional statements with condition and branches\n- `ForStmt` - For loops with initialization, condition, and increment\n- `ReturnStmt` - Return statements with optional expressions\n- `GotoStmt` - Goto statements for jumping to labels\n- `LabelStmt` - Label statements for goto targets\n\n**Declaration Statements:**\n\n- `DeclStmt` - Declaration statements containing variable and type declarations\n- `VariableDeclarationEntry` - Individual variable declarations (e.g., `definition of i`)\n- `TypeDeclarationEntry` - Type declarations (e.g., `definition of u`)\n\n**Expression Statements:**\n\n- `ExprStmt` - Statement wrappers for expressions\n\n**Variable Length Array Support:**\n\n- `VlaDimensionStmt` - VLA dimension size statements\n- `VlaDeclStmt` - VLA declaration statements\n\n### Expressions\n\n**Primary Expressions:**\n\n- `Literal` - Literal values (e.g., `1`, `2`, `42`, `"hello"`)\n- `StringLiteral` - String literals (e.g., `"int"`, `"string"`)\n- `VariableAccess` - Variable references (e.g., `sc`, `i`, `args`)\n- `ThisExpr` - The `this` keyword in member functions\n\n**Function Calls:**\n\n- `FunctionCall` - Function calls (e.g., `call to f`, `call to printf`)\n- `FormattingFunctionCall` - Calls to format string functions with type checking\n- `MethodCall` - Method calls on objects\n- `ConstructorCall` - Constructor calls (e.g., `call to C`)\n\n**Operators and Assignments:**\n\n- `AssignExpr` - Assignment expressions (e.g., `... = ...`)\n- `AddExpr` - Addition expressions (e.g., `... + ...`)\n- `MulExpr` - Multiplication expressions (e.g., `... * ...`)\n- `SubExpr` - Subtraction expressions\n\n**Object Creation and Destruction:**\n\n- `ClassInstanceExpr` - Object instantiation expressions\n- `NewExpr` - Dynamic memory allocation with `new`\n- `DeleteExpr` - Dynamic memory deallocation with `delete`\n- `VacuousDestructorCall` - Vacuous destructor calls for trivial types\n\n**Array and Pointer Operations:**\n\n- `ArrayExpr` - Array access expressions (e.g., `access to array`)\n- `PointerDereferenceExpr` - Pointer dereference (e.g., `* ...`)\n- `AddressOfExpr` - Address-of operator (e.g., `& ...`)\n- `ArrayToPointerConversion` - Implicit array to pointer conversions\n\n**Field Access:**\n\n- `ValueFieldAccess` - Value-based field access (e.g., `obj.field`)\n- `PointerFieldAccess` - Pointer-based field access (e.g., `ptr->field`)\n\n**Type Casting:**\n\n- `CStyleCast` - C-style casts (e.g., `(int)...`, `(char)...`)\n- `StaticCast` - Static casts for safe conversions\n- `DynamicCast` - Dynamic casts for runtime type checking (e.g., `dynamic_cast<Derived *>...`)\n- `ConstCast` - Const casts (e.g., `const_cast<T *>...`)\n- `ReinterpretCast` - Reinterpret casts (e.g., `reinterpret_cast<S *>...`)\n\n**Reference Operations:**\n\n- `ReferenceToExpr` - Reference creation (e.g., `(reference to)`)\n- `ReferenceDereferenceExpr` - Reference dereference (e.g., `(reference dereference)`)\n\n**Type Information:**\n\n- `TypeidOperator` - Runtime type information (e.g., `typeid ...`)\n\n**Modern C++ Features:**\n\n- `ParenthesizedExpr` - Parenthesized expressions for grouping\n\n### Type System\n\n**Basic Types:**\n\n- `IntType` - Integer types (e.g., `int`)\n- `VoidType` - Void type\n- `FloatType` - Floating-point types\n- `LongType` - Long integer types (e.g., `unsigned long`)\n- `PlainCharType` - Plain char type\n- `CharType` - Character types\n\n**Pointer Types:**\n\n- `PointerType` - Pointer types (e.g., `someClass *`, `Base *`)\n- `IntPointerType` - Integer pointer types (e.g., `int *`)\n- `CharPointerType` - Character pointer types (e.g., `char *`)\n- `VoidPointerType` - Void pointer types (e.g., `void *`)\n- `FunctionPointerType` - Function pointer types\n\n**Reference Types:**\n\n- `LValueReferenceType` - L-value references (e.g., `const someClass &`)\n- `RValueReferenceType` - R-value references (e.g., `someClass &&`)\n\n**Array Types:**\n\n- `ArrayType` - Array types (e.g., `char[]`, `char[4]`)\n\n**Class and Struct Types:**\n\n- `Class` - Class types (e.g., `Base`, `Derived`)\n- `Struct` - Struct types\n- `NestedClass` - Nested class types\n- `LocalUnion` - Local union types\n\n**Template Types:**\n\n- `TypeTemplateParameter` - Template type parameters (e.g., `T`)\n\n**Advanced Types:**\n\n- `SpecifiedType` - Type qualifiers (e.g., `const type_info`)\n- `CTypedefType` - C typedef types (e.g., `va_list`, `MYINT`)\n\n### C11 Generic Support\n\n**Generic Expressions:**\n\n- `C11GenericExpr` - C11 \\_Generic expressions for type-based selection\n- `ReuseExpr` - Expression reuse in generic contexts\n- `TypeName` - Type names in generic associations\n\n### Parameters and Initializers\n\n**Parameter Handling:**\n\n- `Parameter` - Function parameters with types (e.g., `i`, `j`, `sc`)\n- Support for unnamed parameters and default arguments\n\n**Initialization:**\n\n- `Initializer` - Variable initializers (e.g., `initializer for i`)\n- Constructor initialization lists\n- Field initialization\n\n### Built-in Functions\n\n**Variable Arguments:**\n\n- `BuiltInVarArgsStart` - `__builtin_va_start` for variadic functions\n- `BuiltInVarArgsEnd` - `__builtin_va_end` for cleanup\n\n### Type Conversions\n\n**Implicit Conversions:**\n\n- `IntegralConversion` - Integer type conversions\n- `PointerConversion` - Pointer type conversions\n- `BaseClassConversion` - Base class conversions for inheritance\n- `GlvalueConversion` - Glvalue conversions\n\n**Explicit Conversions:**\n\n- Support for all cast types with conversion tracking\n- Value category preservation through conversions\n\n### Value Categories and Properties\n\n**Value Categories:**\n\n- `prvalue` - Pure r-values (temporary values)\n- `lvalue` - L-values (addressable values)\n- `prvalue(load)` - Loaded values from memory\n\n**Type Properties:**\n\n- Type information preservation through all expressions\n- Conversion tracking for type safety analysis\n\n### Example AST Hierarchy\n\nBased on CodeQL\'s comprehensive C++ analysis capabilities:\n\n```\nTopLevelFunction (global functions)\n\u251C\u2500\u2500 Parameter (function parameters)\n\u251C\u2500\u2500 BlockStmt (function body)\n\u2502 \u251C\u2500\u2500 DeclStmt (declarations)\n\u2502 \u2502 \u2514\u2500\u2500 VariableDeclarationEntry (variable definitions)\n\u2502 \u251C\u2500\u2500 ExprStmt (expression statements)\n\u2502 \u2502 \u251C\u2500\u2500 FunctionCall (function calls)\n\u2502 \u2502 \u251C\u2500\u2500 AssignExpr (assignments)\n\u2502 \u2502 \u2514\u2500\u2500 VariableAccess (variable references)\n\u2502 \u2514\u2500\u2500 ReturnStmt (return statements)\n\u2514\u2500\u2500 Type information (IntType, PointerType, etc.)\n\nClass (class declarations)\n\u251C\u2500\u2500 Constructor/Destructor (special members)\n\u251C\u2500\u2500 MemberFunction (methods)\n\u251C\u2500\u2500 CopyAssignmentOperator (copy operations)\n\u2514\u2500\u2500 MoveAssignmentOperator (move operations)\n\nExpression hierarchy with full type and conversion tracking\n\u251C\u2500\u2500 Primary expressions (literals, variables)\n\u251C\u2500\u2500 Operators (arithmetic, logical, comparison)\n\u251C\u2500\u2500 Casts (static, dynamic, const, reinterpret)\n\u251C\u2500\u2500 Object operations (new, delete, field access)\n\u2514\u2500\u2500 Type operations (sizeof, typeid, alignof)\n```\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `cpp` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="cpp"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `cpp` language:\n\n- [library-tests/destructors/PrintAST.expected](https://github.com/github/codeql/blob/main/cpp/ql/test/library-tests/destructors/PrintAST.expected)\n- [library-tests/c11_generic/PrintAST.expected](https://github.com/github/codeql/blob/main/cpp/ql/test/library-tests/c11_generic/PrintAST.expected)\n- [library-tests/ir/ir/PrintAST.expected](https://github.com/github/codeql/blob/main/cpp/ql/test/library-tests/ir/ir/PrintAST.expected)\n- [library-tests/ir/no-function-calls/PrintAST.expected](https://github.com/github/codeql/blob/main/cpp/ql/test/library-tests/ir/no-function-calls/PrintAST.expected)\n- [examples/expressions/PrintAST.expected](https://github.com/github/codeql/blob/main/cpp/ql/test/examples/expressions/PrintAST.expected)\n';
|
|
64093
|
+
|
|
64094
|
+
// src/resources/languages/cpp_security_query_guide.md
|
|
64095
|
+
var cpp_security_query_guide_default = "# C++ Security Query Guide\n\nLanguage-specific notes for writing C++ security queries in CodeQL. For the general taint-tracking template and workflow, see the `security_templates` resource.\n\n## Imports\n\n```ql\nimport cpp\nimport semmle.code.cpp.dataflow.new.DataFlow\nimport semmle.code.cpp.dataflow.new.TaintTracking\n```\n\nFor path-problem queries add `import MyFlow::PathGraph` after defining your flow module.\n\n## Sources and Sinks\n\n- **Sources**: Use the `RemoteFlowSource` class from `semmle.code.cpp.security.FlowSources`, or model custom sources as `DataFlow::Node` subclasses.\n- **Sinks**: Model as `DataFlow::Node` subclasses matching the dangerous API (e.g., buffer writes, system calls, SQL execution).\n- **Barriers**: Use `semmle.code.cpp.controlflow.Guards` to model guard conditions that sanitize tainted data.\n\n## Key Library Modules\n\n| Module | Purpose |\n| -------------------------------------------- | ------------------------------------- |\n| `semmle.code.cpp.dataflow.new.DataFlow` | Data flow nodes and global analysis |\n| `semmle.code.cpp.dataflow.new.TaintTracking` | Taint tracking analysis |\n| `semmle.code.cpp.controlflow.Guards` | Guard-condition analysis for barriers |\n| `semmle.code.cpp.security.BufferWrite` | Buffer-write sink modeling |\n| `semmle.code.cpp.security.FlowSources` | Remote and local flow sources |\n";
|
|
64096
|
+
|
|
64097
|
+
// src/resources/languages/csharp_ast.md
|
|
64098
|
+
var csharp_ast_default = '# CodeQL AST nodes for `csharp` language\n\n## CodeQL\'s core AST classes for `csharp` language\n\nBased on the C# PrintAst.expected test results, here are the core CodeQL AST classes for the C# language:\n\n### Declarations and Members\n\n- **`Class`** - Class declaration\n- **`NamespaceDeclaration`** - Namespace declaration\n- **`Method`** - Method declaration\n- **`Property`** - Property declaration\n- **`Field`** - Field declaration\n- **`Parameter`** - Method parameter\n- **`DelegateType`** - Delegate type declaration\n- **`InstanceConstructor`** - Instance constructor\n- **`StaticConstructor`** - Static constructor\n- **`Destructor`** - Destructor/finalizer\n\n### Type System\n\n- **`TypeMention`** - Reference to a type\n- **`TypeParameter`** - Generic type parameter\n- **`TypeAccess`** - Access to a type\n- **`TypeAccessPatternExpr`** - Type access in pattern expressions\n\n### Statements\n\n- **`BlockStmt`** - Block statement `{...}`\n- **`ExprStmt`** - Expression statement\n- **`LocalVariableDeclStmt`** - Local variable declaration statement\n- **`ReturnStmt`** - Return statement\n- **`IfStmt`** - If statement\n- **`TryStmt`** - Try statement\n- **`ThrowStmt`** - Throw statement\n- **`UsingBlockStmt`** - Using statement with block\n- **`FixedStmt`** - Fixed statement (for unsafe code)\n- **`LabelStmt`** - Label statement\n- **`EmptyStmt`** - Empty statement `;`\n\n### Expressions\n\n- **`LocalVariableDeclAndInitExpr`** - Local variable declaration and initialization\n- **`LocalVariableAccess`** - Access to local variable\n- **`ParameterAccess`** - Access to parameter\n- **`FieldAccess`** - Access to field\n- **`PropertyCall`** - Property access/call\n- **`MethodCall`** - Method call\n- **`MethodAccess`** - Method access\n- **`ObjectCreation`** - Object creation expression `new T()`\n- **`AnonymousObjectCreation`** - Anonymous object creation\n- **`ArrayCreation`** - Array creation expression\n- **`ArrayAccess`** - Array element access\n- **`AssignExpr`** - Assignment expression `=`\n- **`AssignAddExpr`** - Addition assignment `+=`\n- **`AssignSubExpr`** - Subtraction assignment `-=`\n- **`ThisAccess`** - `this` access\n- **`CastExpr`** - Type cast expression\n- **`IsExpr`** - Type check expression `is`\n- **`DefaultValueExpr`** - Default value expression `default(...)`\n\n### Arithmetic and Logical Expressions\n\n- **`AddExpr`** - Addition expression `+`\n- **`SubExpr`** - Subtraction expression `-`\n- **`DivExpr`** - Division expression `/`\n- **`BitwiseAndExpr`** - Bitwise AND expression `&`\n- **`LogicalOrExpr`** - Logical OR expression `||`\n- **`LTExpr`** - Less than expression `<`\n- **`GEExpr`** - Greater than or equal expression `>=`\n- **`PostIncrExpr`** - Post-increment expression `++`\n- **`OperatorCall`** - Operator call\n\n### Literals\n\n- **`IntLiteral`** - Integer literal\n- **`StringLiteralUtf16`** - String literal\n- **`BoolLiteral`** - Boolean literal (`true`/`false`)\n- **`DoubleLiteral`** - Double literal\n- **`CharLiteral`** - Character literal\n- **`NullLiteral`** - Null literal\n\n### Object and Collection Initialization\n\n- **`ObjectInitializer`** - Object initializer `{ ... }`\n- **`MemberInitializer`** - Member initializer in object initializer\n- **`CollectionInitializer`** - Collection initializer `{ ..., ... }`\n- **`ElementInitializer`** - Element initializer in collection\n- **`ArrayInitializer`** - Array initializer `{ ..., ... }`\n\n### Delegates and Events\n\n- **`DelegateCall`** - Delegate call\n- **`ImplicitDelegateCreation`** - Implicit delegate creation\n- **`ExplicitDelegateCreation`** - Explicit delegate creation\n- **`EventAccess`** - Event access\n- **`EventCall`** - Event call\n- **`AddEventExpr`** - Event subscription `+=`\n- **`RemoveEventExpr`** - Event unsubscription `-=`\n\n### Properties and Accessors\n\n- **`Getter`** - Property getter\n- **`Setter`** - Property setter\n\n### Special Members and Access\n\n- **`MemberConstantAccess`** - Access to member constant\n- **`LocalFunctionAccess`** - Access to local function\n- **`AddressOfExpr`** - Address-of expression `&` (unsafe code)\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `csharp` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="csharp"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `csharp` language:\n\n- [library-tests/arguments/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/arguments/PrintAst.expected)\n- [library-tests/assignments/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/assignments/PrintAst.expected)\n- [library-tests/attributes/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/attributes/PrintAst.expected)\n- [library-tests/comments/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/comments/PrintAst.expected)\n- [library-tests/constructors/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/constructors/PrintAst.expected)\n- [library-tests/conversion/operator/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/conversion/operator/PrintAst.expected)\n- [library-tests/csharp6/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp6/PrintAst.expected)\n- [library-tests/csharp7/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp7/PrintAst.expected)\n- [library-tests/csharp7.1/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp7.1/PrintAst.expected)\n- [library-tests/csharp7.2/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp7.2/PrintAst.expected)\n- [library-tests/csharp7.3/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp7.3/PrintAst.expected)\n- [library-tests/csharp8/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp8/PrintAst.expected)\n- [library-tests/csharp9/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp9/PrintAst.expected)\n- [library-tests/csharp11/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/csharp11/PrintAst.expected)\n- [library-tests/dataflow/implicittostring/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/dataflow/implicittostring/PrintAst.expected)\n- [library-tests/dataflow/tuples/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/dataflow/tuples/PrintAst.expected)\n- [library-tests/definitions/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/definitions/PrintAst.expected)\n- [library-tests/delegates/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/delegates/PrintAst.expected)\n- [library-tests/dynamic/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/dynamic/PrintAst.expected)\n- [library-tests/enums/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/enums/PrintAst.expected)\n- [library-tests/exceptions/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/exceptions/PrintAst.expected)\n- [library-tests/expressions/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/expressions/PrintAst.expected)\n- [library-tests/events/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/events/PrintAst.expected)\n- [library-tests/fields/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/fields/PrintAst.expected)\n- [library-tests/generics/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/generics/PrintAst.expected)\n- [library-tests/goto/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/goto/PrintAst.expected)\n- [library-tests/indexers/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/indexers/PrintAst.expected)\n- [library-tests/initializers/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/initializers/PrintAst.expected)\n- [library-tests/linq/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/linq/PrintAst.expected)\n- [library-tests/members/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/members/PrintAst.expected)\n- [library-tests/methods/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/methods/PrintAst.expected)\n- [library-tests/namespaces/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/namespaces/PrintAst.expected)\n- [library-tests/nestedtypes/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/nestedtypes/PrintAst.expected)\n- [library-tests/operators/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/operators/PrintAst.expected)\n- [library-tests/partial/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/partial/PrintAst.expected)\n- [library-tests/properties/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/properties/PrintAst.expected)\n- [library-tests/statements/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/statements/PrintAst.expected)\n- [library-tests/stringinterpolation/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/stringinterpolation/PrintAst.expected)\n- [library-tests/types/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/types/PrintAst.expected)\n- [library-tests/unsafe/PrintAst.expected](https://github.com/github/codeql/blob/main/csharp/ql/test/library-tests/unsafe/PrintAst.expected)\n';
|
|
64099
|
+
|
|
64100
|
+
// src/resources/languages/csharp_security_query_guide.md
|
|
64101
|
+
var csharp_security_query_guide_default = "# C# Security Query Guide\n\nLanguage-specific notes for writing C# security queries in CodeQL. For the general taint-tracking template and workflow, see the `security_templates` resource.\n\n## Imports\n\n```ql\nimport csharp\nimport semmle.code.csharp.dataflow.DataFlow\nimport semmle.code.csharp.dataflow.TaintTracking\n```\n\nFor path-problem queries add `import MyFlow::PathGraph` after defining your flow module.\n\n## Sources and Sinks\n\n- **Sources**: Use `RemoteFlowSource` from `semmle.code.csharp.security.dataflow.flowsources.Remote`, or model custom sources as `DataFlow::Node` subclasses.\n- **Sinks**: Use or extend existing sink libraries under `semmle.code.csharp.security.dataflow` (e.g., `SqlInjectionQuery`, `flowsinks.Html`, `UrlRedirectQuery`), or model custom sinks as `DataFlow::Node` subclasses.\n- **Sanitizers**: Use `semmle.code.csharp.security.Sanitizers` for common encoding and validation barriers.\n\n## Key Library Modules\n\n| Module | Purpose |\n| ------------------------------------------- | ---------------------------------------- |\n| `semmle.code.csharp.dataflow.DataFlow` | Data flow nodes and global analysis |\n| `semmle.code.csharp.dataflow.TaintTracking` | Taint tracking analysis |\n| `semmle.code.csharp.security.Sanitizers` | Common sanitizer predicates |\n| `semmle.code.csharp.security.dataflow.*` | Pre-built vulnerability-specific configs |\n| `semmle.code.csharp.frameworks.system.*` | .NET framework API models |\n";
|
|
64102
|
+
|
|
64103
|
+
// src/resources/languages/go_ast.md
|
|
64104
|
+
var go_ast_default = '# CodeQL AST Classes for Go Programs\n\n## Purpose\n\nWrite CodeQL queries over Go by navigating the Go AST classes. Model: Syntax \u2192 CodeQL class hierarchy; use predicates to access parts (condition, body, operands). Pattern: `get<Part>()`, `getA<Part>()`, `get<Left/Right>Operand>()`, `getAnArgument()`, `getCallee()`.\n\n## Core Namespaces\n\n- **Statements**: subclasses of `Stmt`\n- **Expressions**: subclasses of `Expr` (literals, unary, binary, calls, selectors, etc.)\n- **Declarations**: `FuncDecl`, `GenDecl` (+ `ImportSpec`, `TypeSpec`, `ValueSpec`)\n- **Types**: `TypeExpr` nodes (`ArrayTypeExpr`, `StructTypeExpr`, `FuncTypeExpr`, `InterfaceTypeExpr`, `MapTypeExpr`, `ChanTypeExpr` variants)\n- **Names/Selectors**: `SimpleName`, `SelectorExpr`; Name hierarchy: `PackageName`, `TypeName`, `ValueName`, `LabelName`\n\n## Statements (Stmt)\n\n### Basic Statements\n\n- **`EmptyStmt`** - Empty statement ";"\n- **`ExprStmt`** - Expression used as statement\n- **`BlockStmt`** - Block statement "{\u2026}"\n- **`DeclStmt`** - Declaration statement\n\n### Control Flow Statements\n\n- **`IfStmt`** - if condition then [else]; supports init; Then/Else are blocks or statements\n - `getCondition()`, `getThen()`, `getElse()`, `getInit()`\n- **`ForStmt`** - Classic init/cond/post; `LoopStmt` superclass\n - `getInit()`, `getCondition()`, `getPost()`, `getBody()`\n- **`RangeStmt`** - "for k,v := range expr { \u2026 }"\n - `getKey()`, `getValue()`, `getDomain()`, `getBody()`\n\n### Switch and Select Statements\n\n- **`SwitchStmt`/`ExpressionSwitchStmt`** - Expression-based switch\n- **`TypeSwitchStmt`** - Type-based switch\n- **`CaseClause`** - Case clause inside switch statements\n - `getExpr(i)`, `getStmt(i)`\n- **`SelectStmt`** - Select statement for channel operations\n- **`CommClause`** - Communication clause in select statement\n\n### Channel and Concurrency Statements\n\n- **`SendStmt`** - Channel send "ch <- x"\n- **`RecvStmt`** - Channel receive "x = <-ch"\n- **`GoStmt`** - Goroutine launch "go f()"\n- **`DeferStmt`** - Deferred function call "defer f()"\n\n### Assignment and Increment Statements\n\n- **`SimpleAssignStmt`** - Simple assignment "="\n- **`DefineStmt`** - Short variable declaration ":="\n- **`CompoundAssignStmt`** - Compound assignment (+=, -=, \\*=, /=, %=, &=, |=, ^=, <<=, >>=, &^=)\n- **`IncStmt`** - Increment "x++"\n- **`DecStmt`** - Decrement "x--"\n\n### Jump Statements\n\n- **`LabeledStmt`** - Labeled statement\n- **`BreakStmt`** - Break statement\n- **`ContinueStmt`** - Continue statement\n- **`GotoStmt`** - Goto statement\n- **`FallthroughStmt`** - Fallthrough statement\n- **`ReturnStmt`** - Return statement\n - `getResult(i)` to access return values\n\n## Expressions (Expr)\n\n### Literals\n\n- **`BasicLit`** subclasses:\n - **`IntLit`** - Integer literal\n - **`FloatLit`** - Floating point literal\n - **`ImagLit`** - Imaginary literal\n - **`CharLit`/`RuneLit`** - Character/rune literal\n - **`StringLit`** - String literal\n- **`CompositeLit`** - Composite literals:\n - **`StructLit`** - Struct literal "T{\u2026}"\n - **`MapLit`** - Map literal "map[K]V{\u2026}"\n- **`FuncLit`** - Function literal (anonymous function)\n\n### Unary Expressions\n\n- **`PlusExpr`** - Unary plus "+x"\n- **`MinusExpr`** - Unary minus "-x"\n- **`NotExpr`** - Logical not "!x"\n- **`ComplementExpr`** - Bitwise complement "^x"\n- **`AddressExpr`** - Address-of "&x"\n- **`RecvExpr`** - Channel receive "<-x"\n\n### Binary Expressions\n\n- **Arithmetic**: `MulExpr`, `QuoExpr`, `RemExpr`, `AddExpr`, `SubExpr`\n- **Shift**: `ShlExpr` "<<", `ShrExpr` ">>"\n- **Logical**: `LandExpr` "&&", `LorExpr` "||"\n- **Relational**: `LssExpr` "<", `GtrExpr` ">", `LeqExpr` "<=", `GeqExpr` ">="\n- **Equality**: `EqlExpr` "==", `NeqExpr` "!="\n- **Bitwise**: `AndExpr` "&", `OrExpr` "|", `XorExpr` "^", `AndNotExpr` "&^"\n\n### Access and Call Expressions\n\n- **`SelectorExpr`** - Field/method access "X.Y"\n - `getBase()`, `getSelector()`\n- **`CallExpr`** - Function/method call\n - `getCallee()`, `getAnArgument()`, `getArgument(i)`\n- **`IndexExpr`** - Array/slice/map index "a[i]"\n- **`SliceExpr`** - Slice expression "a[i:j:k]"\n- **`KeyValueExpr`** - Key-value pair in composite literals\n\n### Type-related Expressions\n\n- **`ParenExpr`** - Parenthesized expression\n- **`StarExpr`** - Pointer dereference/type\n- **`TypeAssertExpr`** - Type assertion "x.(T)"\n- **`Conversion`** - Type conversion "T(x)"\n\n## Type Expressions (no common superclass)\n\n- **`ArrayTypeExpr`** - Array type "[N]T" or slice type "[]T"\n- **`StructTypeExpr`** - Struct type "struct{\u2026}"\n- **`FuncTypeExpr`** - Function type "func(\u2026) \u2026"\n- **`InterfaceTypeExpr`** - Interface type\n- **`MapTypeExpr`** - Map type\n- **`ChanTypeExpr`** variants:\n - **`SendChanTypeExpr`** - Send-only channel\n - **`RecvChanTypeExpr`** - Receive-only channel\n - **`SendRecvChanTypeExpr`** - Bidirectional channel\n\n## Names and Identifiers\n\n### Name Hierarchy\n\n- **`Name`** subclasses:\n - **`SimpleName`** - Simple identifier\n - **`QualifiedName`** - Package-qualified name\n- **`ValueName`** subclasses:\n - **`ConstantName`** - Constant identifier\n - **`VariableName`** - Variable identifier\n - **`FunctionName`** - Function identifier\n\n### Specialized Names\n\n- **`PackageName`** - Package name identifier\n- **`TypeName`** - Type name identifier\n- **`LabelName`** - Label identifier\n\n## Declarations\n\n### Function Declarations\n\n- **`FuncDecl`/`FuncLit`** via **`FuncDef`**:\n - `getBody()`, `getName()`, `getParameter(i)`, `getResultVar(i)`, `getACall()`\n\n### General Declarations\n\n- **`GenDecl`** with:\n - **`ImportSpec`** - Import specification\n - **`TypeSpec`** - Type specification\n - **`ValueSpec`** - Variable/constant specification\n- **`Field`/`FieldList`** - For parameters, results, struct/interface fields\n\n## Navigation Idioms and Patterns\n\n### Control Flow Navigation\n\n- **If statements**: `getCondition()`, `getThen()`, `getElse()`\n- **For/Range loops**: inspect `getInit()`/`getCondition()`/`getPost()` or range expression\n- **Switch statements**: use `CaseClause`, `getExpr(i)`/`getStmt(i)`\n- **Select statements**: use `CommClause`\n\n### Function and Method Calls\n\n```ql\n// Method calls by name\nfrom CallExpr call, SelectorExpr sel\nwhere call.getCallee() = sel and sel.getMemberName() = "Close"\nselect call\n\n// Method vs function calls\n// SelectorExpr callee = method call\n// SimpleName callee = function call\n```\n\n### Assignment Operations\n\n- **Assignment**: match `AssignStmt` subclasses\n- **Short variable declaration**: `DefineStmt` for ":="\n- **Compound assignment**: `CompoundAssignStmt` for "+=", etc.\n\n### Binary and Unary Operations\n\n- Use specific subclasses or operator accessors\n- Access operands via `getLeftOperand()`, `getRightOperand()`\n\n### Literals and Composite Expressions\n\n- **Basic literals**: filter `BasicLit` subclasses\n- **Composite literals**: `CompositeLit` elements via keys/values\n- **Struct literals**: `StructLit` with type information\n\n## Common Query Patterns\n\n### Finding Specific Constructs\n\n```ql\n// Range over map/slice\nfrom RangeStmt r select r\n\n// Defer calls\nfrom DeferStmt d, CallExpr c\nwhere d.getExpr() = c\nselect d, c\n\n// Struct literal of specific type\nfrom StructLit lit\nwhere lit.getType().getName() = "Point"\nselect lit\n\n// Channel operations\nfrom SendStmt s select s // ch <- x\nfrom RecvStmt r select r // x = <-ch\n```\n\n### Method Resolution\n\n```ql\n// Find method calls on specific receiver types\nfrom CallExpr call, SelectorExpr sel\nwhere call.getCallee() = sel and\n sel.getBase().getType().toString() = "MyType"\nselect call\n```\n\n## File and Module Navigation\n\n- **`GoFile`** - Represents a Go source file\n- **`GoModFile`** - Represents a go.mod file\n- **`GoModModuleLine`** - Module declaration in go.mod\n- **`GoModGoLine`** - Go version declaration in go.mod\n\n## Comments and Documentation\n\n- **`CommentGroup`** - Group of related comments\n- **`DocComment`** - Documentation comment group (typically for functions/types)\n- **`SlashSlashComment`** - Single-line comment (//) within comment groups\n\n## Advanced Features\n\n### Generics Support\n\n- **`TypeParamDecl`** - Type parameter declaration with constraints\n- Generic type parameters and constraints for Go generics\n- Support for type inference and constraint satisfaction\n\n### Concurrency Constructs\n\n- **Goroutines**: `GoStmt` for "go f()" patterns\n- **Channels**: `SendStmt`, `RecvStmt`, `RecvExpr` for channel operations\n- **Select**: `SelectStmt` with `CommClause` for channel multiplexing\n- **Defer**: `DeferStmt` for cleanup patterns\n\n## Tips and Best Practices\n\n### Preferred Patterns\n\n- **Class tests over string parsing**: Use specific AST classes rather than string matching\n- **Type conversion disambiguation**: `CallExpr` callee is a `TypeExpr` for type conversions\n- **Statement vs expression**: Inc/Dec are statements, not expressions\n- **Assignment variants**: Handle ":=" vs "=" separately with `DefineStmt` vs `SimpleAssignStmt`\n- **Error handling**: Exclude `BadStmt`/`BadExpr` from analysis\n\n### Syntax to Class Mapping Cheatsheet\n\n- **Control Flow**: If\u2192`IfStmt`, For\u2192`ForStmt`, Range\u2192`RangeStmt`, Switch\u2192`SwitchStmt`/`ExpressionSwitchStmt`, Type switch\u2192`TypeSwitchStmt`, Select\u2192`SelectStmt`\n- **Cases**: Case\u2192`CaseClause`, Select case\u2192`CommClause`\n- **Assignment**: `=`\u2192`SimpleAssignStmt`, `:=`\u2192`DefineStmt`, `+=` etc.\u2192`CompoundAssignStmt`\n- **Increment**: `++`\u2192`IncStmt`, `--`\u2192`DecStmt`\n- **Access**: Call\u2192`CallExpr`, Selector\u2192`SelectorExpr`, Index\u2192`IndexExpr`, Slice\u2192`SliceExpr`\n- **Type operations**: Type assert\u2192`TypeAssertExpr`, Conversion\u2192`Conversion`\n- **Unary/Binary**: Specific subclasses of `UnaryExpr`/`BinaryExpr`\n- **Literals**: `IntLit`, `FloatLit`, `StringLit`, `StructLit`, `MapLit`, `FuncLit`\n- **Types**: `ArrayTypeExpr`, `StructTypeExpr`, `FuncTypeExpr`, `InterfaceTypeExpr`, `MapTypeExpr`, `ChanTypeExpr`\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `go` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="go"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `go` language:\n\n- [library-tests/semmle/go/PrintAst/PrintAst.expected](https://github.com/github/codeql/blob/main/go/ql/test/library-tests/semmle/go/PrintAst/PrintAst.expected)\n- [library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected](https://github.com/github/codeql/blob/main/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstExcludeComments.expected)\n- [library-tests/semmle/go/PrintAst/PrintAstNestedFunction.expected](https://github.com/github/codeql/blob/main/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstNestedFunction.expected)\n- [library-tests/semmle/go/PrintAst/PrintAstRestrictFile.expected](https://github.com/github/codeql/blob/main/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFile.expected)\n- [library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.expected](https://github.com/github/codeql/blob/main/go/ql/test/library-tests/semmle/go/PrintAst/PrintAstRestrictFunction.expected)\n';
|
|
64105
|
+
|
|
64106
|
+
// src/resources/languages/go_basic_queries.md
|
|
64107
|
+
var go_basic_queries_default = '# Basic CodeQL Query Examples for Go\n\n## Purpose\n\nMinimal Go query examples in VS Code; variables, constraints, and results for concrete bug patterns. Demonstrates query structure and common Go programming pattern detection.\n\n## Basic Query Structure\n\n### Query Components (SQL-like analogy)\n\n- **`import`**: Include standard Go library (`import go`)\n- **`from`**: Declare typed variables to range over (`Method`, `Variable`, `Write`, `Field`)\n- **`where`**: Constrain relationships among variables with predicates\n- **`select`**: Emit results; message can concatenate strings and AST entities\n\n### Template Structure\n\n```ql\nimport go\n\nfrom <Type1> var1, <Type2> var2, ...\nwhere <conditions and relationships>\nselect <results>, "<message with " + var1 + " references>"\n```\n\n## Example 1: Value Receiver Method Modifications\n\n### Target Pattern\n\nMethods defined on value receivers that write to a field have no effect (receiver is copied). Should use pointer receiver instead.\n\n### Query\n\n```ql\nimport go\n\nfrom Method m, Variable recv, Write w, Field f\nwhere recv = m.getReceiver() and\n w.writesField(recv.getARead(), f, _) and\n not recv.getType() instanceof PointerType\nselect w, "This update to " + f + " has no effect, because " + recv + " is not a pointer."\n```\n\n### Key Predicates\n\n- **`Method.getReceiver()`**: Receiver variable of a method\n- **`Write.writesField(baseRead, field, idx)`**: Write whose LHS writes field of base expression\n- **`Variable.getARead()`**: Read expression of the variable\n- **`PointerType`**: Type test to exclude pointer receivers\n\n## Example 2: Missing Error Handling\n\n### Target Pattern\n\nFunction calls that return errors but the error is ignored.\n\n### Query\n\n```ql\nimport go\n\nfrom CallExpr call, AssignStmt assign\nwhere call.getType().toString().matches("%error%") and\n assign.getRhs() = call and\n assign.getLhs().(Ident).getName() = "_"\nselect call, "Error from " + call.getTarget().getName() + " is ignored"\n```\n\n## Example 3: Nil Pointer Dereference Risk\n\n### Target Pattern\n\nPointer dereference without nil check.\n\n### Query\n\n```ql\nimport go\n\nfrom StarExpr deref, Variable ptr\nwhere deref.getExpr() = ptr.getARead() and\n not exists(IfStmt guard, NeqExpr check |\n check.getLeftOperand() = ptr.getARead() and\n check.getRightOperand().(Ident).getName() = "nil" and\n guard.getCondition() = check and\n deref.getParent*() = guard.getThen()\n )\nselect deref, "Potential nil pointer dereference of " + ptr\n```\n\n## Example 4: Goroutine Without Context\n\n### Target Pattern\n\nGoroutines launched without context cancellation mechanism.\n\n### Query\n\n```ql\nimport go\n\nfrom GoStmt goStmt, FuncLit funcLit\nwhere goStmt.getExpr() = funcLit and\n not exists(Parameter ctx |\n ctx = funcLit.getParameter(0) and\n ctx.getType().toString().matches("%context.Context%")\n )\nselect goStmt, "Goroutine launched without context parameter"\n```\n\n## Example 5: Unsafe Type Assertion\n\n### Target Pattern\n\nType assertions without the "ok" idiom to check success.\n\n### Query\n\n```ql\nimport go\n\nfrom TypeAssertExpr assert\nwhere not exists(TupleExpr tuple, VariableName ok |\n tuple = assert.getParent() and\n tuple.getElement(1) = ok.getARead() and\n ok.getName() = "ok"\n )\nselect assert, "Type assertion without ok check: " + assert.toString()\n```\n\n## Example 6: Resource Leak - Missing Close\n\n### Target Pattern\n\nFiles opened without corresponding defer close.\n\n### Query\n\n```ql\nimport go\n\nfrom CallExpr open, VariableName file\nwhere open.getTarget().hasQualifiedName("os", "Open") and\n open.getARead() = file.getARead() and\n not exists(DeferStmt defer, CallExpr close |\n close.getTarget().getName() = "Close" and\n close.getReceiver() = file.getARead() and\n defer.getExpr() = close\n )\nselect open, "File opened without defer close: " + file\n```\n\n## Example 7: SQL Injection Risk\n\n### Target Pattern\n\nString concatenation used to build SQL queries.\n\n### Query\n\n```ql\nimport go\n\nfrom CallExpr dbCall, AddExpr concat, StringLit sqlPart\nwhere dbCall.getTarget().hasQualifiedName("database/sql", ["Query", "Exec"]) and\n dbCall.getArgument(0) = concat and\n concat.getAnOperand() = sqlPart and\n sqlPart.getValue().matches("%SELECT%")\nselect concat, "SQL query built by concatenation, potential injection risk"\n```\n\n## Example 8: Command Injection Risk\n\n### Target Pattern\n\nUser input used directly in command execution.\n\n### Query\n\n```ql\nimport go\n\nfrom CallExpr execCall, CallExpr inputCall\nwhere execCall.getTarget().hasQualifiedName("os/exec", "Command") and\n inputCall.getTarget().hasQualifiedName("os", "Getenv") and\n DataFlow::localFlow(DataFlow::exprNode(inputCall), DataFlow::exprNode(execCall.getAnArgument()))\nselect execCall, "Environment variable flows to command execution"\n```\n\n## Example 9: Range Over Map in Goroutine\n\n### Target Pattern\n\nRange over map in goroutine without copying the value (race condition risk).\n\n### Query\n\n```ql\nimport go\n\nfrom GoStmt goStmt, RangeStmt rangeStmt, Variable mapVar\nwhere goStmt.getExpr().(FuncLit).getBody().getAStmt*() = rangeStmt and\n rangeStmt.getDomain() = mapVar.getARead() and\n mapVar.getType().toString().matches("map[%")\nselect rangeStmt, "Range over map " + mapVar + " in goroutine may cause race condition"\n```\n\n## Example 10: Slice Bounds Check Missing\n\n### Target Pattern\n\nSlice access without bounds checking.\n\n### Query\n\n```ql\nimport go\n\nfrom IndexExpr index, Variable slice\nwhere index.getBase() = slice.getARead() and\n slice.getType().toString().matches("[]%") and\n not exists(IfStmt guard, CallExpr lenCall, RelationalComparisonExpr compare |\n lenCall.getTarget().getName() = "len" and\n lenCall.getArgument(0) = slice.getARead() and\n compare.getAnOperand() = index.getIndex() and\n compare.getAnOperand() = lenCall and\n guard.getCondition() = compare\n )\nselect index, "Slice access without bounds check: " + slice\n```\n\n## Usage Patterns\n\n### Finding Specific Function Calls\n\n```ql\n// Find all calls to specific function\nfrom CallExpr call\nwhere call.getTarget().hasQualifiedName("fmt", "Printf")\nselect call\n\n// Find method calls on specific type\nfrom CallExpr call, SelectorExpr sel\nwhere call.getCallee() = sel and\n sel.getBase().getType().toString() = "MyType" and\n sel.getSelector().getName() = "MyMethod"\nselect call\n```\n\n### Working with Control Flow\n\n```ql\n// Find if statements with specific conditions\nfrom IfStmt ifStmt, EqlExpr eq\nwhere ifStmt.getCondition() = eq and\n eq.getRightOperand().(Ident).getName() = "nil"\nselect ifStmt\n\n// Find loops with range\nfrom RangeStmt rangeStmt\nwhere rangeStmt.getKey().getName() != "_" and\n rangeStmt.getValue().getName() != "_"\nselect rangeStmt\n```\n\n### Package and Import Analysis\n\n```ql\n// Find specific imports\nfrom ImportSpec spec\nwhere spec.getPath().getValue() = "unsafe"\nselect spec, "Unsafe package imported"\n\n// Find package-level variables\nfrom Variable v\nwhere v.isPackageLevel() and\n v.getName().matches("debug%")\nselect v\n```\n\n## Testing and Refinement\n\n### Running Queries in VS Code\n\n1. Open VS Code with CodeQL extension\n2. Paste query after `import go`\n3. Click "Run Query" or use Ctrl+Shift+P \u2192 "CodeQL: Run Query"\n4. Click results to jump to code locations\n\n### Refining Results\n\n```ql\n// Add guards to exclude false positives\nwhere not exists(CommentGroup comment |\n comment.getText().matches("%TODO%") and\n comment.getLocation().getStartLine() < result.getLocation().getStartLine()\n )\n\n// Restrict to specific files or packages\nwhere result.getFile().getBaseName().matches("%.go") and\n not result.getFile().getAbsolutePath().matches("%test%")\n```\n\n### Extensions and Improvements\n\n- Add guards to exclude writes to temporary copies\n- Restrict to exported methods/types\n- Focus on specific packages with `hasQualifiedName`\n- Convert to path queries to show data flow\n- Add more specific type checking\n\nThese examples provide practical starting points for finding real Go programming issues and can be customized for specific codebases and requirements.\n';
|
|
64108
|
+
|
|
64109
|
+
// src/resources/languages/go_dataflow.md
|
|
64110
|
+
var go_dataflow_default = '# Analyzing Data Flow in Go\n\n## Purpose\n\nUse CodeQL\'s Go data-flow libraries to find how values and taint propagate through Go programs. Cover local flow/taint (intra-procedural) and global flow/taint (inter-procedural), with configurable sources/sinks/barriers.\n\n## Core Concepts\n\n### Data Flow vs Taint Tracking\n\n- **Data Flow**: Tracks exact value preservation through assignments, calls, and returns\n- **Taint Tracking**: Tracks influence/contamination, including non-value-preserving operations like concatenation\n\n### Node Hierarchy\n\n- **`Node`** - Base class for data flow nodes\n - **`ExprNode`** - Expression in the AST\n - **`ParameterNode`** - Function parameter\n - **`InstructionNode`** - Intermediate representation instruction\n\n### Node Conversion\n\n- **AST to DataFlow**: `DataFlow::exprNode(expr)`, `DataFlow::parameterNode(param)`\n- **DataFlow to AST**: `node.asExpr()`, `node.asParameter()`, `node.asInstruction()`\n\n## Local Data Flow\n\n### Basic Predicates\n\n- **`localFlowStep(Node a, Node b)`** - Direct flow from `a` to `b` within same function\n- **`localFlow(Node a, Node b)`** - Transitive closure (`localFlowStep*`)\n\n### Example: Tracking to Function Arguments\n\n```ql\nimport go\nfrom Function osOpen, CallExpr call, Expr src\nwhere osOpen.hasQualifiedName("os","Open") and\n call.getTarget() = osOpen and\n DataFlow::localFlow(DataFlow::exprNode(src), DataFlow::exprNode(call.getArgument(0)))\nselect src, "flows to os.Open argument"\n```\n\n### Local Flow Patterns\n\n```ql\n// Variable assignment flow\nfrom Variable v, Expr source, Expr use\nwhere DataFlow::localFlow(DataFlow::exprNode(source), DataFlow::exprNode(use)) and\n source = v.getAnAssignment() and\n use = v.getARead()\nselect source, use\n\n// Parameter to return flow\nfrom Function f, Parameter p, ReturnStmt ret\nwhere DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(ret.getAResult()))\nselect p, ret\n```\n\n## Local Taint Tracking\n\n### Basic Predicates\n\n- **`localTaintStep(Node a, Node b)`** - Direct taint from `a` to `b`\n- **`localTaint(Node a, Node b)`** - Transitive taint closure\n\n### Taint vs Flow Examples\n\n```ql\n// String concatenation - taint but not flow\nfrom Expr source, Expr concat\nwhere concat.(AddExpr).getAnOperand() = source and\n TaintTracking::localTaint(DataFlow::exprNode(source), DataFlow::exprNode(concat))\nselect source, concat\n\n// Array element access - taint propagation\nfrom Expr array, Expr element\nwhere element.(IndexExpr).getBase() = array and\n TaintTracking::localTaint(DataFlow::exprNode(array), DataFlow::exprNode(element))\nselect array, element\n```\n\n## Global Data Flow\n\n### Configuration Interface\n\nImplement `DataFlow::ConfigSig`:\n\n```ql\nmodule MyConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n // Define where flow starts\n }\n\n predicate isSink(DataFlow::Node sink) {\n // Define where flow ends\n }\n\n predicate isBarrier(DataFlow::Node node) {\n // Optional: block flow through certain nodes\n }\n\n predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {\n // Optional: add custom flow edges\n }\n}\n\nmodule MyFlow = DataFlow::Global<MyConfig>;\n```\n\n### Usage Pattern\n\n```ql\nfrom DataFlow::Node source, DataFlow::Node sink\nwhere MyFlow::flow(source, sink)\nselect source, "flows to $@", sink, "sink"\n```\n\n### Complete Example: Hard-coded Strings to URL Parse\n\n```ql\nmodule StringToUrlConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n source.asExpr() instanceof StringLit\n }\n\n predicate isSink(DataFlow::Node sink) {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("net/url", "Parse") and\n sink.asExpr() = call.getArgument(0)\n )\n }\n}\n\nmodule StringToUrlFlow = DataFlow::Global<StringToUrlConfig>;\n\nfrom DataFlow::Node source, DataFlow::Node sink\nwhere StringToUrlFlow::flow(source, sink)\nselect source, "String literal flows to URL parse $@", sink, "here"\n```\n\n## Global Taint Tracking\n\n### Configuration Interface\n\nSame as data flow but with taint semantics:\n\n```ql\nmodule MyTaintConfig implements TaintTracking::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n source instanceof RemoteFlowSource // Built-in remote sources\n }\n\n predicate isSink(DataFlow::Node sink) {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("os/exec", "Command") and\n sink.asExpr() = call.getAnArgument()\n )\n }\n}\n\nmodule MyTaintFlow = TaintTracking::Global<MyTaintConfig>;\n```\n\n### Built-in Sources\n\n```ql\n// RemoteFlowSource covers common user input sources\nclass MyRemoteSource extends RemoteFlowSource {\n MyRemoteSource() {\n // Additional remote sources beyond built-ins\n }\n}\n```\n\n## Advanced Flow Configuration\n\n### Custom Flow Steps\n\n```ql\npredicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {\n // Custom builder pattern\n exists(CallExpr call |\n call.getTarget().getName() = "WithValue" and\n node1.asExpr() = call.getReceiver() and\n node2.asExpr() = call\n )\n or\n // Flow through slice append\n exists(CallExpr append |\n append.getTarget().getName() = "append" and\n node1.asExpr() = append.getAnArgument() and\n node2.asExpr() = append\n )\n}\n```\n\n### Barriers and Sanitizers\n\n```ql\npredicate isBarrier(DataFlow::Node node) {\n // Block flow through validation functions\n exists(CallExpr call |\n call.getTarget().getName().matches("%Validate%") and\n node.asExpr() = call\n )\n or\n // Block at error checks\n exists(IfStmt guard, NeqExpr check |\n check.getRightOperand().(Ident).getName() = "nil" and\n guard.getCondition() = check and\n node.asExpr().getParent*() = guard.getThen()\n )\n}\n```\n\n## Common Data Flow Patterns\n\n### Environment Variables to Sinks\n\n```ql\nclass GetenvSource extends DataFlow::Node {\n GetenvSource() {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("os", "Getenv") and\n this.asExpr() = call\n )\n }\n}\n\nmodule EnvToSinkConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) { source instanceof GetenvSource }\n predicate isSink(DataFlow::Node sink) { /* define sinks */ }\n}\n```\n\n### Command Line Arguments\n\n```ql\nclass CommandLineArgSource extends DataFlow::Node {\n CommandLineArgSource() {\n exists(IndexExpr access |\n access.getBase().(Ident).getName() = "Args" and\n access.getBase().getType().toString() = "[]string" and\n this.asExpr() = access\n )\n }\n}\n```\n\n### HTTP Request Data\n\n```ql\nclass HttpRequestSource extends DataFlow::Node {\n HttpRequestSource() {\n exists(CallExpr call, SelectorExpr sel |\n sel.getBase().getType().toString().matches("%Request%") and\n sel.getSelector().getName() in ["FormValue", "PostFormValue", "Header"] and\n call.getCallee() = sel and\n this.asExpr() = call\n )\n }\n}\n```\n\n### Database Queries\n\n```ql\npredicate isDatabaseQuerySink(DataFlow::Node sink) {\n exists(CallExpr call, Function target |\n call.getTarget() = target and\n target.hasQualifiedName("database/sql", ["Query", "QueryRow", "Exec", "Prepare"]) and\n sink.asExpr() = call.getArgument(0)\n )\n}\n```\n\n## Path Queries for Better Results\n\n### Basic Path Query Structure\n\n```ql\n/**\n * @kind path-problem\n */\nimport go\nimport DataFlow::PathGraph\n\n// ... config definition ...\n\nfrom MyFlow::PathNode source, MyFlow::PathNode sink\nwhere MyFlow::flowPath(source, sink)\nselect sink.getNode(), source, sink,\n "Value from $@ reaches sink", source.getNode(), "source"\n```\n\n### Multi-step Flow Analysis\n\n```ql\n// First: literal to getenv parameter\nmodule LiteralToGetenvConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) { source.asExpr() instanceof StringLit }\n predicate isSink(DataFlow::Node sink) {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("os", "Getenv") and\n sink.asExpr() = call.getArgument(0)\n )\n }\n}\n\n// Second: getenv result to url.Parse\nmodule GetenvToUrlConfig implements DataFlow::ConfigSig {\n predicate isSource(DataFlow::Node source) {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("os", "Getenv") and\n source.asExpr() = call\n )\n }\n predicate isSink(DataFlow::Node sink) {\n exists(CallExpr call |\n call.getTarget().hasQualifiedName("net/url", "Parse") and\n sink.asExpr() = call.getArgument(0)\n )\n }\n}\n```\n\n## Performance and Precision Tips\n\n### Query Optimization\n\n- Start with local flow/taint for better performance\n- Use specific predicates rather than broad matching\n- Prefer `hasQualifiedName` over string patterns\n- Add barriers to reduce false paths\n\n### Debugging Flow\n\n```ql\n// Debug: show intermediate flow steps\nfrom DataFlow::Node n1, DataFlow::Node n2\nwhere DataFlow::localFlowStep(n1, n2) and\n n1.getFile().getBaseName() = "target.go"\nselect n1, n2\n```\n\n### Testing Configurations\n\n```ql\n// Test source identification\nfrom DataFlow::Node source\nwhere MyConfig::isSource(source)\nselect source\n\n// Test sink identification\nfrom DataFlow::Node sink\nwhere MyConfig::isSink(sink)\nselect sink\n```\n\n## Integration with Security Queries\n\n### Combining Multiple Configurations\n\n```ql\n// Union of different taint sources\npredicate isAnyTaintSource(DataFlow::Node source) {\n source instanceof RemoteFlowSource or\n source instanceof GetenvSource or\n source instanceof CommandLineArgSource\n}\n\n// Combined configuration\nmodule UnifiedTaintConfig implements TaintTracking::ConfigSig {\n predicate isSource(DataFlow::Node source) { isAnyTaintSource(source) }\n predicate isSink(DataFlow::Node sink) { /* any dangerous sink */ }\n}\n```\n\n### Framework-specific Flow\n\n```ql\n// Framework method chaining\npredicate isFrameworkFlowStep(DataFlow::Node node1, DataFlow::Node node2) {\n exists(CallExpr call |\n call.getReceiver() = node1.asExpr() and\n call.getTarget().getName().regexpMatch("With|Set|Add") and\n node2.asExpr() = call\n )\n}\n```\n\nThis provides the foundation for building sophisticated security queries that can track how untrusted data flows through Go programs to reach dangerous operations.\n';
|
|
64111
|
+
|
|
64112
|
+
// src/resources/languages/go_library_modeling.md
|
|
64113
|
+
var go_library_modeling_default = "# Customizing Library Models for Go\n\n## Purpose\n\nCustomize data-flow/taint analysis for Go by modeling frameworks/libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\n## Data Extensions Overview\n\n### Structure\n\nData extensions use YAML format to extend CodeQL's knowledge of library behavior:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: <extensible-predicate>\n data:\n - <tuple1>\n - <tuple2>\n```\n\n### Union Semantics\n\n- Multiple YAML files are combined\n- Rows are merged across files\n- Duplicates are automatically removed\n- Order of files doesn't matter\n\n## Extensible Predicates for Go\n\n### Source Models\n\n**`sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)`**\n\nDefine sources of untrusted data (e.g., user input):\n\n- **package**: Go package path (e.g., \"net/http\")\n- **type**: Type name (\"\" for package-level functions)\n- **subtypes**: Include subtypes (true/false)\n- **name**: Function/method name\n- **signature**: Function signature (\"\" for any)\n- **ext**: External library marker (\"\" for stdlib)\n- **output**: Access path where taint emerges\n- **kind**: Threat model category\n- **provenance**: Origin marker (manual/ai-manual/etc.)\n\n**Example**: HTTP request as source\n\n```yaml\n- ['net/http', 'Request', false, 'FormValue', '', '', 'ReturnValue', 'remote', 'manual']\n```\n\n### Sink Models\n\n**`sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)`**\n\nDefine dangerous operations (sinks):\n\n- **input**: Access path where taint is dangerous\n\n**Example**: Command execution sink\n\n```yaml\n- ['os/exec', '', false, 'Command', '', '', 'Argument[1]', 'command-injection', 'manual']\n```\n\n### Summary Models\n\n**`summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)`**\n\nDefine how data flows through functions when dependency code isn't in the database:\n\n- **input**: Where data enters the function\n- **output**: Where data exits the function\n\n**Example**: String builder flow\n\n```yaml\n- ['strings', 'Builder', false, 'WriteString', '', '', 'Argument[0]', 'Receiver', 'taint', 'manual']\n```\n\n### Neutral Models\n\n**`neutralModel(package, type, name, signature, kind, provenance)`**\n\nDefine low-impact flows to reduce over-taint/noise:\n\n**Example**: Safe string operations\n\n```yaml\n- ['strings', '', 'ToUpper', '', 'value', 'manual']\n```\n\n## Access Paths\n\n### Basic Access Paths\n\n- **`Argument[i]`** - ith argument (0-indexed)\n- **`ReturnValue`** - Function return value\n- **`Receiver`** - Method receiver\n- **`Qualifier`** - Object being called on\n\n### Complex Access Paths\n\n- **`Argument[i].Field[\"name\"]`** - Field of argument\n- **`Argument[i].ArrayElement`** - Array/slice elements\n- **`ReturnValue.ArrayElement`** - Elements of returned array/slice\n- **`Field[\"name\"].ArrayElement`** - Elements of field array\n\n### Examples\n\n```yaml\n# Array/slice element flow\n- ['slices', '', false, 'Max', '', '', 'Argument[0].ArrayElement', 'ReturnValue', 'value', 'manual']\n\n# Nested array flow\n- [\n 'slices',\n '',\n false,\n 'Concat',\n '',\n '',\n 'Argument[0].ArrayElement.ArrayElement',\n 'ReturnValue.ArrayElement',\n 'value',\n 'manual'\n ]\n\n# Struct field flow\n- [\n 'encoding/json',\n '',\n false,\n 'Unmarshal',\n '',\n '',\n 'Argument[0]',\n 'Argument[1].Field[*]',\n 'taint',\n 'manual'\n ]\n```\n\n## Flow Kinds\n\n### Value vs Taint\n\n- **\"value\"**: Moves whole values (precise data flow)\n- **\"taint\"**: Propagates taint only (influence tracking)\n\n### Security Categories\n\nCommon `kind` values for threat modeling:\n\n- **\"remote\"**: Remote user input\n- **\"command-injection\"**: Command execution\n- **\"sql-injection\"**: Database queries\n- **\"path-injection\"**: File system access\n- **\"code-injection\"**: Code execution\n- **\"xss\"**: Cross-site scripting\n\n## Complete Examples\n\n### HTTP Framework Modeling\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: sourceModel\n data:\n # HTTP request sources\n - ['net/http', 'Request', false, 'FormValue', '', '', 'ReturnValue', 'remote', 'manual']\n - ['net/http', 'Request', false, 'PostFormValue', '', '', 'ReturnValue', 'remote', 'manual']\n - ['net/http', 'Request', false, 'Header', '', '', 'ReturnValue', 'remote', 'manual']\n - ['net/http', 'Request', false, 'URL', '', '', 'ReturnValue.Field[*]', 'remote', 'manual']\n\n - addsTo:\n pack: codeql/go-all\n extensible: sinkModel\n data:\n # HTTP response sinks\n - ['net/http', 'ResponseWriter', false, 'Write', '', '', 'Argument[0]', 'xss', 'manual']\n - [\n 'net/http',\n 'ResponseWriter',\n false,\n 'Header',\n '',\n '',\n 'ReturnValue',\n 'response-header',\n 'manual'\n ]\n```\n\n### Database Library Modeling\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: summaryModel\n data:\n # Database query builders\n - [\n 'github.com/jmoiron/sqlx',\n 'DB',\n false,\n 'Query',\n '',\n '',\n 'Argument[0]',\n 'ReturnValue.Field[*]',\n 'taint',\n 'manual'\n ]\n - [\n 'github.com/jmoiron/sqlx',\n 'DB',\n false,\n 'Select',\n '',\n '',\n 'Argument[1]',\n 'Argument[0].Field[*]',\n 'taint',\n 'manual'\n ]\n\n - addsTo:\n pack: codeql/go-all\n extensible: sinkModel\n data:\n # SQL injection sinks\n - [\n 'github.com/jmoiron/sqlx',\n 'DB',\n false,\n 'Query',\n '',\n '',\n 'Argument[0]',\n 'sql-injection',\n 'manual'\n ]\n - [\n 'github.com/jmoiron/sqlx',\n 'DB',\n false,\n 'Exec',\n '',\n '',\n 'Argument[0]',\n 'sql-injection',\n 'manual'\n ]\n```\n\n### JSON Processing\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: summaryModel\n data:\n # JSON unmarshaling\n - [\n 'encoding/json',\n '',\n false,\n 'Unmarshal',\n '',\n '',\n 'Argument[0]',\n 'Argument[1].Field[*]',\n 'taint',\n 'manual'\n ]\n - [\n 'encoding/json',\n '',\n false,\n 'Marshal',\n '',\n '',\n 'Argument[0].Field[*]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n\n - addsTo:\n pack: codeql/go-all\n extensible: sourceModel\n data:\n # JSON from HTTP as source\n - [\n 'encoding/json',\n 'Decoder',\n false,\n 'Decode',\n '',\n '',\n 'Argument[0].Field[*]',\n 'remote',\n 'manual'\n ]\n```\n\n### String Processing Libraries\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: summaryModel\n data:\n # String builder patterns\n - [\n 'strings',\n 'Builder',\n false,\n 'WriteString',\n '',\n '',\n 'Argument[0]',\n 'Receiver',\n 'taint',\n 'manual'\n ]\n - [\n 'strings',\n 'Builder',\n false,\n 'String',\n '',\n '',\n 'Receiver',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n\n # Template processing\n - [\n 'text/template',\n 'Template',\n false,\n 'Execute',\n '',\n '',\n 'Argument[1].Field[*]',\n 'Argument[0]',\n 'taint',\n 'manual'\n ]\n - [\n 'html/template',\n 'Template',\n false,\n 'Execute',\n '',\n '',\n 'Argument[1].Field[*]',\n 'Argument[0]',\n 'taint',\n 'manual'\n ]\n```\n\n## Model Packs\n\n### Pack Structure\n\nCreate a CodeQL model pack to group and distribute YAML files:\n\n```yaml\n# codeql-pack.yml\nname: my-org/go-security-models\nversion: 1.0.0\ndependencies:\n codeql/go-all: '*'\ndataExtensions: '*.yml'\n```\n\n### Directory Structure\n\n```\nmy-go-models/\n\u251C\u2500\u2500 codeql-pack.yml\n\u251C\u2500\u2500 http-frameworks.yml\n\u251C\u2500\u2500 database-orms.yml\n\u2514\u2500\u2500 json-libraries.yml\n```\n\n### Publishing to GitHub Container Registry\n\n```bash\ncodeql pack publish\n```\n\n### Consuming Model Packs\n\n```yaml\n# In consumer's codeql-pack.yml\ndependencies:\n my-org/go-security-models: '^1.0.0'\n```\n\nOr via CLI:\n\n```bash\ncodeql database analyze --packs my-org/go-security-models\n```\n\n## Advanced Patterns\n\n### Framework-specific Source Patterns\n\n```yaml\n# Gin framework\n- ['github.com/gin-gonic/gin', 'Context', false, 'Param', '', '', 'ReturnValue', 'remote', 'manual']\n- ['github.com/gin-gonic/gin', 'Context', false, 'Query', '', '', 'ReturnValue', 'remote', 'manual']\n- [\n 'github.com/gin-gonic/gin',\n 'Context',\n false,\n 'PostForm',\n '',\n '',\n 'ReturnValue',\n 'remote',\n 'manual'\n ]\n\n# Echo framework\n- [\n 'github.com/labstack/echo/v4',\n 'Context',\n false,\n 'Param',\n '',\n '',\n 'ReturnValue',\n 'remote',\n 'manual'\n ]\n- [\n 'github.com/labstack/echo/v4',\n 'Context',\n false,\n 'QueryParam',\n '',\n '',\n 'ReturnValue',\n 'remote',\n 'manual'\n ]\n- [\n 'github.com/labstack/echo/v4',\n 'Context',\n false,\n 'FormValue',\n '',\n '',\n 'ReturnValue',\n 'remote',\n 'manual'\n ]\n```\n\n### ORM and Query Builder Models\n\n```yaml\n# GORM models\n- ['gorm.io/gorm', 'DB', false, 'Raw', '', '', 'Argument[0]', 'ReturnValue', 'taint', 'manual']\n- ['gorm.io/gorm', 'DB', false, 'Exec', '', '', 'Argument[0]', '', 'sql-injection', 'manual']\n\n# Squirrel query builder\n- [\n 'github.com/Masterminds/squirrel',\n 'SelectBuilder',\n false,\n 'Where',\n '',\n '',\n 'Argument[0]',\n 'Receiver',\n 'taint',\n 'manual'\n ]\n- [\n 'github.com/Masterminds/squirrel',\n 'SelectBuilder',\n false,\n 'ToSql',\n '',\n '',\n 'Receiver',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n```\n\n### Utility Library Flows\n\n```yaml\n# Viper configuration\n- ['github.com/spf13/viper', '', false, 'GetString', '', '', '', 'ReturnValue', 'config', 'manual']\n- ['github.com/spf13/viper', '', false, 'Get', '', '', '', 'ReturnValue', 'config', 'manual']\n\n# Cobra CLI arguments\n- [\n 'github.com/spf13/cobra',\n 'Command',\n false,\n 'Flags',\n '',\n '',\n '',\n 'ReturnValue',\n 'cli-input',\n 'manual'\n ]\n```\n\n## Workflow and Best Practices\n\n### Development Process\n\n1. **Identify Gap**: Find library calls that break data flow paths\n2. **Analyze Library**: Understand how data flows through the library\n3. **Create Models**: Start with summaries for common flows\n4. **Add Sources/Sinks**: Define security-relevant entry/exit points\n5. **Test and Iterate**: Validate with path queries and unit tests\n\n### Model Quality Guidelines\n\n- **Narrow Matching**: Use `hasQualifiedName` for precision\n- **Specific Access Paths**: Be precise about which fields/elements flow\n- **Appropriate Kinds**: Match `kind` to actual threat model\n- **Documentation**: Comment complex access paths\n- **Testing**: Validate with realistic code examples\n\n### Performance Considerations\n\n- Avoid overly broad models that create too many paths\n- Use `neutralModel` to reduce noise from safe operations\n- Consider performance impact of complex access paths\n- Test query performance with models enabled\n\n### Integration Testing\n\n```ql\n// Test model coverage\nfrom DataFlow::Node source, DataFlow::Node sink\nwhere MyFlow::flow(source, sink) and\n source.getFile().getBaseName() = \"test_library.go\"\nselect source, sink\n\n// Verify specific library modeling\nfrom CallExpr call\nwhere call.getTarget().hasQualifiedName(\"my/library\", \"MyFunction\")\nselect call, \"Library call found\"\n```\n\nThis comprehensive approach to library modeling enables accurate security analysis even when third-party library source code isn't available in the CodeQL database.\n";
|
|
64114
|
+
|
|
64115
|
+
// src/resources/languages/go_security_query_guide.md
|
|
64116
|
+
var go_security_query_guide_default = "# Go Security Query Guide\n\nLanguage-specific notes for writing Go security queries in CodeQL. For the general taint-tracking template and workflow, see the `security_templates` resource.\n\n## Imports\n\n```ql\nimport go\n```\n\nThe `go` top-level import re-exports data flow, taint tracking, and standard library models. For path-problem queries add `import MyFlow::PathGraph` after defining your flow module.\n\n## Sources and Sinks\n\n- **Sources**: Use `RemoteFlowSource` (covers `net/http` handlers, gRPC, and other HTTP frameworks). Also consider `UntrustedFlowSource` for broader input coverage.\n- **Sinks**: Model as `DataFlow::Node` subclasses matching dangerous APIs (e.g., `os/exec`, `database/sql`, `html/template`). Existing sink libraries live under `semmle.go.security.*`.\n- **Barriers**: Model sanitizers as `DataFlow::Node` subclasses and reference them in `isBarrier`.\n\n## Key Library Modules\n\n| Module | Purpose |\n| ---------------------------------- | ---------------------------------------- |\n| `semmle.go.dataflow.DataFlow` | Data flow nodes and global analysis |\n| `semmle.go.dataflow.TaintTracking` | Taint tracking analysis |\n| `semmle.go.security.*` | Pre-built vulnerability-specific configs |\n| `semmle.go.frameworks.*` | Framework-specific API models |\n";
|
|
64117
|
+
|
|
64118
|
+
// src/resources/languages/java_ast.md
|
|
64119
|
+
var java_ast_default = '# CodeQL AST nodes for `java` language\n\n## CodeQL\'s core AST classes for `java` language\n\nBased on comprehensive analysis of CodeQL\'s Java test results from GitHub, here are the core AST classes for Java analysis:\n\n### Compilation and Package Structure\n\n**Top-Level Units:**\n\n- `CompilationUnit` - Java source file compilation units (e.g., `CompilationUnit A`)\n- `ImportType` - Single type imports (e.g., `import HashMap`, `import IOException`)\n- `ImportOnDemandFromPackage` - Wildcard imports (e.g., `import java.util.*`)\n\n### Class and Interface Declarations\n\n**Class Structure:**\n\n- `Class` - Class declarations (e.g., `class A`, `class Test`)\n- `Interface` - Interface declarations (e.g., `interface Ann1`)\n- `GenericType` - Generic classes with type parameters\n- `ParameterizedType` - Parameterized types with specific type arguments\n\n**Generic Support:**\n\n- `TypeVariable` - Generic type parameters (e.g., `T`, `S extends Comparable`)\n- Generic class declarations and instantiations\n- Diamond operator support (`<>`) for type inference\n\n### Type System\n\n**Basic Type Access:**\n\n- `TypeAccess` - Type references (e.g., `String`, `int`, `void`, `Object`)\n- `ArrayTypeAccess` - Array types (e.g., `String[]`, `int[][]`)\n- Type access in generic contexts (e.g., `List<String>`, `Map<String,Integer>`)\n\n**Advanced Type Features:**\n\n- Parameterized types with multiple type arguments\n- Nested type access and inner class types\n- Array types with multiple dimensions\n\n### Field and Variable Declarations\n\n**Field Declarations:**\n\n- `FieldDeclaration` - Class field declarations (e.g., `String[] a;`, `float ff;`)\n- Field initialization with expressions\n- Generic field types (e.g., `List<> l`, `Map<String,Integer> m`)\n\n**Variable Declarations:**\n\n- `LocalVariableDeclStmt` - Local variable declaration statements\n- `LocalVariableDeclExpr` - Local variable declarator expressions\n- `Parameter` - Method and constructor parameters\n- `VarDecl` - Variable declaration identifiers\n\n### Method and Constructor Declarations\n\n**Method Structure:**\n\n- `Method` - Method declarations with return types and parameters\n- `Constructor` - Constructor declarations\n- Method signatures with generic types and varargs support\n\n**Parameter Handling:**\n\n- Parameter declarations with type access\n- Varargs parameters (e.g., `int... is`, `Object... os`)\n- Generic parameter types\n\n### Expressions\n\n**Primary Expressions:**\n\n- `IntegerLiteral` - Integer constants (e.g., `42`, `1`, `2`)\n- `FloatLiteral` - Floating-point literals (e.g., `2.3f`)\n- `StringLiteral` - String literals (e.g., `"hello"`, `"rawtypes"`)\n- `NullLiteral` - Null literal (`null`)\n- `BooleanLiteral` - Boolean literals (`true`, `false`)\n\n**Variable Access:**\n\n- `VarAccess` - Variable references (e.g., `thing`, `o`, `Initializers.SFIELD`)\n- Qualified variable access with type prefixes\n\n**Object Creation:**\n\n- `ClassInstanceExpr` - Object instantiation (e.g., `new ArrayList<>()`, `new LinkedHashMap<String,Integer>()`)\n- Constructor calls with type arguments\n- Anonymous class instances\n\n**Method Calls:**\n\n- `MethodCall` - Method invocations (e.g., `source()`, `sink()`)\n- Method calls with arguments and generic types\n\n**Type Operations:**\n\n- `CastExpr` - Type casting (e.g., `(E) thing`)\n- `InstanceOfExpr` - instanceof checks with pattern matching\n\n### Statements\n\n**Control Flow:**\n\n- `BlockStmt` - Block statements containing multiple statements\n- `IfStmt` - Conditional statements\n- `SwitchStmt` - Switch statements with traditional and pattern cases\n- `SwitchExpr` - Switch expressions with yield statements\n- `ReturnStmt` - Return statements\n- `YieldStmt` - Yield statements in switch expressions\n\n**Exception Handling:**\n\n- `TryStmt` - Try-catch-finally statements\n- `CatchClause` - Catch clauses with exception types\n- `ThrowStmt` - Throw statements\n- Multi-catch support for multiple exception types\n\n**Constructor Calls:**\n\n- `ThisConstructorInvocationStmt` - this() constructor calls\n- `SuperConstructorInvocationStmt` - super() constructor calls\n\n### Modern Java Features\n\n**Pattern Matching (Java 14+):**\n\n- `PatternCase` - Pattern matching in switch statements\n- `RecordPatternExpr` - Record pattern matching expressions\n- Pattern case declarations with local variables\n- Guarded patterns and complex pattern matching\n\n**Switch Expressions:**\n\n- `ConstCase` - Traditional constant cases\n- `DefaultCase` - Default cases in switch statements\n- Pattern-based case statements with guards\n\n**Records (Java 14+):**\n\n- Record declarations and pattern matching\n- Record component access and destructuring\n\n### Annotations and Documentation\n\n**Annotations:**\n\n- `Annotation` - Annotation usage (e.g., `@SuppressWarnings("rawtypes")`)\n- Annotation with arguments and values\n\n**Documentation:**\n\n- `Javadoc` - Javadoc comments (e.g., `/** A JavaDoc comment */`)\n- `JavadocText` - Text content within Javadoc\n- `JavadocTag` - Javadoc tags (e.g., `@author someone`)\n- Multi-line Javadoc support\n\n### Enum Support\n\n**Enumeration Features:**\n\n- Enum class declarations\n- Enum constant declarations with initialization\n- Enum constants with constructor arguments\n\n### Lambda Expressions and Functional Interfaces\n\n**Functional Programming:**\n\n- Anonymous class expressions for functional interfaces\n- Functional interface implementations (e.g., `BiFunction<Integer,Integer,Integer>`)\n- Lambda-style anonymous parameter handling\n\n### Advanced Expression Features\n\n**Complex Expressions:**\n\n- Parenthesized expressions for precedence control\n- Conditional expressions (ternary operator)\n- Assignment expressions and compound assignments\n\n**Array Operations:**\n\n- Array access and indexing expressions\n- Array initialization and manipulation\n- Multi-dimensional array support\n\n### Modifier Support\n\n**Access Modifiers:**\n\n- Support for `public`, `private`, `protected` modifiers\n- `static`, `final`, `abstract` modifier handling\n- Enum constant modifiers and initialization\n\n### Collection Framework Integration\n\n**Collections:**\n\n- Generic collection types (e.g., `List<String>`, `Map<String,Integer>`)\n- Collection instantiation with type inference\n- Iterator and collection method support\n\n### Error Handling and Diagnostics\n\n**Error Types:**\n\n- `ErrorExpr` - Error expressions for malformed code\n- `ErrorType` - Error types for type resolution failures\n- Error handling in generic contexts\n\n### Example AST Hierarchy\n\nA typical Java method declaration produces the following AST node hierarchy:\n\n```text\nCompilationUnit\n \u2514\u2500\u2500 ClassDecl\n \u251C\u2500\u2500 FieldDecl\n \u2502 \u251C\u2500\u2500 TypeAccess\n \u2502 \u2514\u2500\u2500 VarDeclExpr\n \u251C\u2500\u2500 MethodDecl\n \u2502 \u251C\u2500\u2500 TypeAccess (return type)\n \u2502 \u251C\u2500\u2500 Parameter\n \u2502 \u2502 \u2514\u2500\u2500 TypeAccess\n \u2502 \u2514\u2500\u2500 Block\n \u2502 \u251C\u2500\u2500 ExprStmt\n \u2502 \u2502 \u2514\u2500\u2500 MethodCall\n \u2502 \u2502 \u251C\u2500\u2500 VarAccess\n \u2502 \u2502 \u2514\u2500\u2500 StringLiteral\n \u2502 \u2514\u2500\u2500 ReturnStmt\n \u2502 \u2514\u2500\u2500 VarAccess\n \u2514\u2500\u2500 ConstructorDecl\n \u2514\u2500\u2500 Block\n```\n\nUse `PrintAST` on your test code to see the exact hierarchy for your specific source patterns.\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `java` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="java"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `java` language:\n\n- [library-tests/comments/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/comments/PrintAst.expected)\n- [library-tests/dependency-counts/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/dependency-counts/PrintAst.expected)\n- [library-tests/generics/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/generics/PrintAst.expected)\n- [library-tests/java7/Diamond/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/java7/Diamond/PrintAst.expected)\n- [library-tests/java7/MultiCatch/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/java7/MultiCatch/PrintAst.expected)\n- [library-tests/modifiers/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/modifiers/PrintAst.expected)\n- [library-tests/guards12/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/guards12/PrintAst.expected)\n- [library-tests/pattern-instanceof/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/pattern-instanceof/PrintAst.expected)\n- [library-tests/typeaccesses/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/typeaccesses/PrintAst.expected)\n- [library-tests/JDK/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/JDK/PrintAst.expected)\n- [library-tests/constants/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/constants/PrintAst.expected)\n- [library-tests/errortype/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/errortype/PrintAst.expected)\n- [library-tests/comment-encoding/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/comment-encoding/PrintAst.expected)\n- [library-tests/dependency/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/dependency/PrintAst.expected)\n- [library-tests/errortype-with-params/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/errortype-with-params/PrintAst.expected)\n- [library-tests/printAst/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/printAst/PrintAst.expected)\n- [library-tests/constructors/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/constructors/PrintAst.expected)\n- [library-tests/arrays/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/arrays/PrintAst.expected)\n- [library-tests/errorexpr/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/errorexpr/PrintAst.expected)\n- [library-tests/fields/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/fields/PrintAst.expected)\n- [library-tests/javadoc/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/javadoc/PrintAst.expected)\n- [library-tests/collections/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/collections/PrintAst.expected)\n- [library-tests/varargs/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/varargs/PrintAst.expected)\n- [library-tests/reflection/PrintAst.expected](https://github.com/github/codeql/blob/main/java/ql/test/library-tests/reflection/PrintAst.expected)\n';
|
|
64120
|
+
|
|
64121
|
+
// src/resources/languages/javascript_ast.md
|
|
64122
|
+
var javascript_ast_default = '# CodeQL AST nodes for `javascript` language\n\n## CodeQL\'s core AST classes for `javascript` language\n\nBased on comprehensive analysis of CodeQL\'s JavaScript test results from GitHub, here are the core AST classes for JavaScript/TypeScript analysis:\n\n### Core Expression Classes\n\n**Primary Expressions:**\n\n- `Literal` - String, number, boolean, null literals (e.g., `"hello"`, `42`, `true`, `null`)\n- `VarRef` - Variable references (e.g., `x`, `myVar`)\n- `ThisExpr` - The `this` keyword\n- `ArrayExpr` - Array literals (e.g., `[1, 2, 3]`, `["source"]`)\n- `ObjectExpr` - Object literals with properties (e.g., `{rel: "noopener"}`)\n\n**Function and Call Expressions:**\n\n- `FunctionExpr` - Function expressions and arrow functions\n- `ArrowFunctionExpr` - Arrow function expressions (e.g., `(x) => x`, `() => true`)\n- `CallExpr` - Function calls (e.g., `func()`, `getResource()`)\n- `MethodCallExpr` - Method calls (e.g., `console.log()`, `arr.push()`)\n- `NewExpr` - Constructor calls (e.g., `new Date()`, `new C3<number>()`)\n\n**Access and Member Expressions:**\n\n- `DotExpr` - Property access (e.g., `obj.prop`, `console.log`, `arr.length`)\n- `IndexExpr` - Array/object indexing (e.g., `arr[0]`, `props["a:b"]`)\n- `SpreadElement` - Spread syntax (e.g., `...arr`, `...linkTypes`)\n\n**Operators and Assignments:**\n\n- `BinaryExpr` - Binary operations (e.g., `x + y`, `i < arr.length`, `typeof val !== "string"`)\n- `UnaryExpr` - Unary operations (e.g., `!condition`, `typeof val`, `++i`)\n- `AssignExpr` - Assignment expressions (e.g., `x = 5`, `test = 20`)\n- `CompoundAssignExpr` - Compound assignments (e.g., `a2 &&= a3`)\n- `UpdateExpr` - Increment/decrement (e.g., `i++`, `--count`)\n\n### Statement Classes\n\n**Declaration Statements:**\n\n- `DeclStmt` - Variable declarations (e.g., `var x = 5`, `const arr = []`)\n- `VariableDeclarator` - Individual variable declarators within declarations\n- `VarDecl` - Variable declaration identifiers\n- `FunctionDeclStmt` - Function declarations\n- `ClassDefinition` - Class declarations with constructors and methods\n\n**Control Flow Statements:**\n\n- `IfStmt` - Conditional statements with test expressions and blocks\n- `ForStmt` - For loops with initialization, condition, and update\n- `ForOfStmt` - For-of loops for iterating arrays and iterables\n- `WhileStmt` - While loops\n- `BlockStmt` - Block statements containing multiple statements\n- `ReturnStmt` - Return statements with optional expressions\n- `BreakStmt` - Break statements for loop control\n- `ContinueStmt` - Continue statements\n- `ThrowStmt` - Throw statements for error handling\n\n**Expression Statements:**\n\n- `ExprStmt` - Expression statements wrapping expressions\n\n### Modern JavaScript Features\n\n**ES6+ and Modern Syntax:**\n\n- `TemplateString` - Template literals with interpolation\n- `TaggedTemplateExpr` - Tagged template literals\n- `ParenthesizedExpr` - Parenthesized expressions\n- `ConditionalExpr` - Ternary conditional expressions\n\n**Resource Management (Modern):**\n\n- `ExplicitResource` - Using declarations for resource management (e.g., `using stream = getResource()`)\n- Resource management in async contexts and for loops\n\n### TypeScript-Specific AST Classes\n\n**Type Annotations:**\n\n- `KeywordTypeExpr` - Built-in types (e.g., `string`, `number`, `boolean`, `any`, `void`)\n- `ArrayTypeExpr` - Array types (e.g., `string[]`, `number[][]`)\n- `UnionTypeExpr` - Union types (e.g., `string | number | boolean`)\n- `IntersectionTypeExpr` - Intersection types (e.g., `string & number & boolean`)\n- `TupleTypeExpr` - Tuple types (e.g., `[number, string, boolean]`, `[...T, ...U]`)\n- `ParenthesizedTypeExpr` - Parenthesized types (e.g., `(string)`, `(boolean | string)`)\n\n**Advanced Types:**\n\n- `GenericTypeExpr` - Generic types (e.g., `Generic<number>`, `Generic<Leaf[]>`)\n- `LocalTypeAccess` - Local type references (e.g., `Interface`, `Generic`, `Leaf`)\n- `FunctionTypeExpr` - Function types (e.g., `() => number`, `new () => Object`)\n- `TypeofTypeExpr` - Typeof types (e.g., `typeof x`)\n- `IsTypeExpr` - Type predicate expressions (e.g., `x is Generic<Leaf[]>`, `this is Leaf`)\n- `PredicateTypeExpr` - Assertion signatures (e.g., `asserts condition`)\n- `RestTypeExpr` - Rest types in tuples (e.g., `...T`, `...number[]`)\n\n**Type Declarations:**\n\n- `TypeDefinition` - Type definitions and interfaces\n- `InterfaceDeclaration` - Interface declarations with properties\n- `TypeParameter` - Generic type parameters (e.g., `T`, `S extends number`)\n- `FieldDeclaration` - Interface/class field declarations\n\n**Type Access:**\n\n- `LocalVarTypeAccess` - Local variable type access (e.g., `x` in type position)\n- `ThisVarTypeAccess` - This type access (e.g., `this` in type predicates)\n\n### JSX Classes (React Support)\n\n**JSX Elements:**\n\n- `JsxElement` - JSX elements (e.g., `<div>`, `<MyComponent>`, `<Foo/>`)\n- `JsxFragment` - JSX fragments (e.g., `<>...</>`)\n- `JsxAttribute` - JSX attributes (e.g., `href={href}`, `target="_blank"`)\n- `JsxEmptyExpr` - Empty JSX expressions (e.g., `{/* comment */}`)\n\n**JSX Structure:**\n\n- JSX elements support attributes, spread attributes, and nested content\n- Namespaced attributes (e.g., `a:b="hello"`)\n- Component references and dot notation (e.g., `MyComponents.FancyLink`)\n\n### Decorator Support\n\n**Decorator Classes:**\n\n- `Decorator` - Decorator expressions (e.g., `@Dec()`)\n- Decorators on classes, methods, and properties\n- Support for decorator factories and complex decorator expressions\n\n### Pattern Matching\n\n**Destructuring Patterns:**\n\n- `ObjectPattern` - Object destructuring patterns\n- `ArrayPattern` - Array destructuring patterns\n- `PropertyPattern` - Property patterns in object destructuring\n- `RestElement` - Rest elements in destructuring\n\n### Array Methods and Operations\n\n**Array-Specific AST:**\n\n- Comprehensive support for array methods: `forEach`, `map`, `filter`, `find`, `findLast`, `findLastIndex`\n- Array method chaining with proper AST representation\n- Spread operations in arrays and function calls\n- Array manipulation methods: `push`, `pop`, `slice`, `splice`, `toSpliced`\n\n### Class and OOP Features\n\n**Class Components:**\n\n- `ClassInitializedMember` - Class members (methods, constructors)\n- `ConstructorDefinition` - Class constructors\n- `MethodDefinition` - Class methods\n- `FieldDeclaration` - Class fields and properties\n\n### Parameter Handling\n\n**Parameter Types:**\n\n- `SimpleParameter` - Simple function parameters\n- `Parameter` - General parameter interface\n- `RestParameter` - Rest parameters (e.g., `...args`)\n\n### Utility and Meta Classes\n\n**Labels and References:**\n\n- `Label` - Property names, method names, and identifiers\n- `Identifier` - General identifiers in various contexts\n\n**Parser Infrastructure:**\n\n- `Arguments` - Function call arguments container\n- `Parameters` - Function parameter container\n- `Body` - Statement body container\n- `Attributes` - JSX attributes container\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `javascript` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="javascript"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `javascript` language:\n\n- [library-tests/RegExp/VFlagOperations/QuotedString/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/RegExp/VFlagOperations/QuotedString/printAst.expected)\n- [library-tests/RegExp/VFlagOperations/Subtraction/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/RegExp/VFlagOperations/Subtraction/printAst.expected)\n- [library-tests/RegExp/VFlagOperations/CombinationOfOperators/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/RegExp/VFlagOperations/CombinationOfOperators/printAst.expected)\n- [library-tests/RegExp/VFlagOperations/Intersection/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/RegExp/VFlagOperations/Intersection/printAst.expected)\n- [library-tests/TypeScript/TypeAnnotations/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/printAst.expected)\n- [library-tests/HTML/HTMLElementAndHTMLAttribute/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/HTML/HTMLElementAndHTMLAttribute/printAst.expected)\n- [library-tests/JSON/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/JSON/printAst.expected)\n- [library-tests/Arrays/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/Arrays/printAst.expected)\n- [library-tests/AST/Decorators/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/AST/Decorators/printAst.expected)\n- [library-tests/AST/ExplicitResource/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/AST/ExplicitResource/printAst.expected)\n- [library-tests/YAML/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/YAML/printAst.expected)\n- [library-tests/frameworks/AngularJS/expressions/parsing/AstNodes.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/frameworks/AngularJS/expressions/parsing/AstNodes.expected)\n- [library-tests/JSX/printAst.expected](https://github.com/github/codeql/blob/main/javascript/ql/test/library-tests/JSX/printAst.expected)\n';
|
|
64123
|
+
|
|
64124
|
+
// src/resources/languages/javascript_security_query_guide.md
|
|
64125
|
+
var javascript_security_query_guide_default = "# JavaScript Security Query Guide\n\nLanguage-specific notes for writing JavaScript/TypeScript security queries in CodeQL. For the general taint-tracking template and workflow, see the `security_templates` resource.\n\n## Imports\n\n```ql\nimport javascript\n```\n\nThe `javascript` top-level import re-exports data flow, taint tracking, and framework models. For path-problem queries add `import MyFlow::PathGraph` after defining your flow module.\n\n## Sources and Sinks\n\n- **Sources**: Use `RemoteFlowSource` (covers Express, Koa, Hapi, Fastify, and other HTTP frameworks automatically).\n- **Sinks**: Use or extend existing sink classes from `semmle.javascript.security.dataflow.*` (e.g., `DomBasedXss`, `SqlInjection`, `ServerSideUrlRedirect`), or model custom sinks as `DataFlow::Node` subclasses.\n- **Sanitizers**: Extend `Sanitizer` classes in the relevant `semmle.javascript.security.dataflow.*` module.\n\n## Key Library Modules\n\n| Module | Purpose |\n| ------------------------------------------ | ---------------------------------------- |\n| `semmle.javascript.dataflow.DataFlow` | Data flow nodes and global analysis |\n| `semmle.javascript.dataflow.TaintTracking` | Taint tracking analysis |\n| `semmle.javascript.security.dataflow.*` | Pre-built vulnerability-specific configs |\n| `semmle.javascript.frameworks.*` | Framework-specific API models |\n";
|
|
64126
|
+
|
|
64127
|
+
// src/resources/languages/python_ast.md
|
|
64128
|
+
var python_ast_default = '# CodeQL AST nodes for `python` language\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `python` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="python"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## CodeQL\'s core AST classes for `python` language\n\n### Expression Types\n\n- **`Call`** - Function/method calls (e.g., `func(args)`)\n- **`Attribute`** - Attribute access (e.g., `obj.attr`, `module.function`)\n- **`Subscript`** - Subscript operations (e.g., `obj[key]`, `list[0]`)\n- **`Name`** - Variable references and identifiers\n- **`StringLiteral`** - String literals (e.g., `"hello"`, `\'world\'`)\n- **`Bytes`** - Byte string literals\n- **`List`** - List literals (e.g., `[1, 2, 3]`)\n- **`Dict`** - Dictionary literals (e.g., `{"key": "value"}`)\n- **`KeyValuePair`** - Key-value pairs in dictionaries\n- **`BinOp`** - Binary operations (e.g., `+`, `-`, `*`)\n- **`UnaryExpr`** - Unary expressions (e.g., `not`, `-`)\n\n### Statement Types\n\n- **`FunctionDef`** - Function definitions\n- **`FunctionExpr`** - Function expressions\n- **`Function`** - Function objects\n- **`ClassDef`** - Class definitions\n- **`ClassExpr`** - Class expressions\n- **`Class`** - Class objects\n- **`Import`** - Import statements (`import module`)\n- **`ImportFrom`** - From-import statements (`from module import name`)\n- **`ImportExpr`** - Import expressions\n- **`Assign`** - Assignment statements (e.g., `x = y`)\n- **`AssignStmt`** - Assignment statement nodes\n- **`If`** - Conditional statements\n- **`For`** - For loop statements\n- **`While`** - While loop statements\n- **`Return`** - Return statements\n- **`ExprStmt`** - Expression statements\n- **`Pass`** - Pass statements\n\n### Parameters and Arguments\n\n- **`Parameter`** - Function parameters\n- **`arguments`** - Function argument lists\n- **`parameters`** - Function parameter lists\n\n### Control Flow\n\n- **`StmtList`** - Statement lists (body, orelse)\n- **`body`** - Statement body containers\n- **`orelse`** - Else clause containers\n\n### YAML Support (for configuration files)\n\n- **`YamlScalar`** - YAML scalar values\n- **`YamlMapping`** - YAML mapping/dictionary structures\n- **`YamlSequence`** - YAML sequence/list structures\n- **`YamlAliasNode`** - YAML alias references\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `python` language:\n\n- [github-codeql:python/ql/test/library-tests/taint/general/printAst.expected](https://github.com/github/codeql/blob/main/python/ql/test/library-tests/taint/general/printAst.expected)\n- [github-codeql:python/ql/test/library-tests/Yaml/printAst.expected](https://github.com/github/codeql/blob/main/python/ql/test/library-tests/Yaml/printAst.expected)\n';
|
|
64129
|
+
|
|
64130
|
+
// src/resources/languages/python_security_query_guide.md
|
|
64131
|
+
var python_security_query_guide_default = '# Python Security Query Guide\n\nLanguage-specific notes for writing Python security queries in CodeQL. For the general taint-tracking template and workflow, see the `security_templates` resource.\n\n## Imports\n\n```ql\nimport python\nimport semmle.python.dataflow.new.DataFlow\nimport semmle.python.dataflow.new.TaintTracking\nimport semmle.python.Concepts\nimport semmle.python.ApiGraphs\n```\n\nFor path-problem queries add `import MyFlow::PathGraph` after defining your flow module.\n\n## Sources and Sinks\n\n- **Sources**: Use `RemoteFlowSource` from `semmle.python.dataflow.new.RemoteFlowSources` (covers Flask, Django, FastAPI, and other HTTP frameworks).\n- **Sinks**: Use the `Concepts` module (e.g., `SqlExecution`, `SystemCommandExecution`, `FileSystemAccess`) or model custom sinks as `DataFlow::Node` subclasses.\n- **Barriers**: Use `semmle.python.dataflow.new.BarrierGuards` for common sanitizer patterns.\n\n## ApiGraph Navigation (Framework Modeling)\n\nUse `API::moduleImport("pkg")` to get a reference to an imported module, then chain `.getMember()`, `.getACall()`, `.getReturn()`, `.getParameter()`, and `.getASubclass()` to navigate the API surface. Convert to data flow nodes via `.asSource()` / `.asSink()`.\n\n## Key Library Modules\n\n| Module | Purpose |\n| ---------------------------------------------- | ------------------------------------------- |\n| `semmle.python.dataflow.new.DataFlow` | Data flow nodes and global analysis |\n| `semmle.python.dataflow.new.TaintTracking` | Taint tracking analysis |\n| `semmle.python.Concepts` | Abstract security concepts (sinks) |\n| `semmle.python.ApiGraphs` | API-graph navigation for framework modeling |\n| `semmle.python.dataflow.new.RemoteFlowSources` | Remote flow source definitions |\n';
|
|
64132
|
+
|
|
64133
|
+
// src/resources/languages/ruby_ast.md
|
|
64134
|
+
var ruby_ast_default = '# CodeQL AST nodes for `ruby` language\n\n## CodeQL\'s core AST classes for `ruby` language\n\nBased on comprehensive analysis of GitHub CodeQL Ruby AST test results\n\n### Expression Types\n\n#### Literal Expressions\n\n- **IntegerLiteral**: Numeric constants (1, 2, 100, -5)\n- **StringLiteral**: String constants with StringTextComponent and StringEscapeSequenceComponent\n- **BooleanLiteral**: true/false values\n- **NilLiteral**: nil value\n- **SymbolLiteral**: :foo, :"foo bar" symbols with StringTextComponent\n- **ArrayLiteral**: [1, 2, 3] arrays (desugared to Array.[])\n- **HashLiteral**: {:foo => 1} hashes (desugared to Hash.[])\n- **RegExpLiteral**: /foo.\\*/ regular expressions with RegExpSequence, RegExpConstant, RegExpStar, RegExpDot\n- **RangeLiteral**: 1..10, 1...10 ranges with getBegin/getEnd\n- **HereDoc**: <<SQL heredoc strings\n\n#### Variable Access\n\n- **LocalVariableAccess**: Local variable references\n- **InstanceVariableAccess**: @instance_var with getReceiver\n- **ClassVariableAccess**: @@class_var\n- **GlobalVariableAccess**: $global_var\n- **SelfVariableAccess**: self references\n\n#### Constant Access\n\n- **ConstantReadAccess**: Reading constants with optional getScopeExpr\n- **ConstantAssignment**: Assigning to constants with optional getScopeExpr\n\n#### Method and Call Expressions\n\n- **MethodCall**: Method invocations with getReceiver, getArgument, getBlock\n- **SetterMethodCall**: Setter method calls (foo=)\n- **SuperCall**: super calls with getArgument, getBlock\n\n#### Binary Operations\n\n- **AddExpr**: + addition\n- **SubExpr**: - subtraction\n- **MulExpr**: \\* multiplication\n- **DivExpr**: / division\n- **ModExpr**: % modulo\n- **PowerExpr**: \\*\\* exponentiation\n- **EqExpr**: == equality\n- **NeExpr**: != inequality\n- **LTExpr**: < less than\n- **LEExpr**: <= less than or equal\n- **GTExpr**: > greater than\n- **GEExpr**: >= greater than or equal\n- **SpaceshipExpr**: <=> spaceship operator\n- **RegExpMatchExpr**: =~ regex match\n- **NoRegExpMatchExpr**: !~ regex no match\n\n#### Logical Operations\n\n- **LogicalAndExpr**: && and \'and\'\n- **LogicalOrExpr**: || and \'or\'\n- **NotExpr**: ! negation\n\n#### Bitwise Operations\n\n- **BitwiseAndExpr**: & bitwise and\n- **BitwiseOrExpr**: | bitwise or\n- **BitwiseXorExpr**: ^ bitwise xor\n- **LeftShiftExpr**: << left shift\n- **RightShiftExpr**: >> right shift\n\n#### Unary Operations\n\n- **UnaryMinusExpr**: -value\n- **UnaryPlusExpr**: +value\n- **ComplementExpr**: ~value\n\n#### Assignment Operations\n\n- **AssignExpr**: = assignment\n- **AssignAddExpr**: += (desugared to = and +)\n- **AssignSubExpr**: -= (desugared to = and -)\n- **AssignMulExpr**: _= (desugared to = and _)\n- **AssignDivExpr**: /= (desugared to = and /)\n- **AssignModExpr**: %= (desugared to = and %)\n- **AssignPowerExpr**: **= (desugared to = and **)\n- **AssignLogicalAndExpr**: &&= (desugared to = and &&)\n- **AssignLogicalOrExpr**: ||= (desugared to = and ||)\n- **AssignBitwiseAndExpr**: &= (desugared to = and &)\n- **AssignBitwiseOrExpr**: |= (desugared to = and |)\n- **AssignBitwiseXorExpr**: ^= (desugared to = and ^)\n- **AssignLeftShiftExpr**: <<= (desugared to = and <<)\n- **AssignRightShiftExpr**: >>= (desugared to = and >>)\n\n#### Special Expressions\n\n- **TernaryIfExpr**: condition ? true_val : false_val\n- **SplatExpr**: \\*args splat operator\n- **HashSplatExpr**: \\*\\*kwargs hash splat\n- **DefinedExpr**: defined? operator\n- **DestructuredLhsExpr**: (a, b, c) destructuring assignment left side\n\n### Statement Types\n\n#### Method Definitions\n\n- **Method**: Regular method definitions with getParameter, getStmt\n- **SingletonMethod**: Class method definitions with getObject\n\n#### Class and Module Definitions\n\n- **ClassDeclaration**: Class definitions with optional getSuperclassExpr\n- **ModuleDeclaration**: Module definitions\n\n#### Control Flow Statements\n\n- **IfExpr**: if/elsif/else conditionals with getCondition, getThen, getElse\n- **UnlessExpr**: unless conditionals with getCondition, getThen, getElse\n- **IfModifierExpr**: statement if condition\n- **UnlessModifierExpr**: statement unless condition\n- **CaseExpr**: case statements with getValue, getBranch\n- **WhenClause**: when branches with getPattern, getBody\n- **InClause**: in pattern matching with getPattern, getCondition, getBody\n\n#### Loop Statements\n\n- **WhileExpr**: while loops with getCondition, getBody\n- **WhileModifierExpr**: statement while condition\n- **UntilExpr**: until loops with getCondition, getBody\n- **UntilModifierExpr**: statement until condition\n- **ForExpr**: for loops (desugared to each with blocks)\n\n#### Flow Control\n\n- **NextStmt**: next statement\n- **BreakStmt**: break statement\n- **ReturnStmt**: return statement\n- **RedoStmt**: redo statement\n- **RetryStmt**: retry statement\n\n#### Block Statements\n\n- **BeginExpr**: begin/rescue/ensure/end blocks\n- **RescueClause**: rescue clauses\n- **EnsureClause**: ensure clauses\n- **EndBlock**: END {} blocks\n\n#### Utility Statements\n\n- **UndefStmt**: undef method_name\n- **AliasStmt**: alias new_name old_name\n- **StmtSequence**: Statement sequences\n\n### Parameters\n\n#### Basic Parameters\n\n- **SimpleParameter**: Regular parameters with getDefiningAccess\n- **OptionalParameter**: Parameters with default values, getDefaultValue\n- **KeywordParameter**: Keyword parameters with optional getDefaultValue\n- **SplatParameter**: \\*args parameters with getDefiningAccess\n- **HashSplatParameter**: \\*\\*kwargs parameters with getDefiningAccess\n- **HashSplatNilParameter**: \\*\\*nil parameters\n- **BlockParameter**: &block parameters with getDefiningAccess\n- **DestructuredParameter**: (a, b) destructured parameters with getElement\n\n### Control Flow\n\n#### Conditional Expressions\n\n- **IfExpr**: Complete if/elsif/else with getBranch structure\n- **UnlessExpr**: unless statements with conditional logic\n- **CaseExpr**: case/when/else with pattern matching\n- **TernaryIfExpr**: Inline conditional expressions\n\n#### Loop Constructs\n\n- **WhileExpr**: while condition do body end\n- **UntilExpr**: until condition do body end\n- **ForExpr**: for var in collection (desugared to each)\n\n#### Block Constructs\n\n- **DoBlock**: do |params| body end blocks\n- **BraceBlock**: { |params| body } blocks\n- **Lambda**: -> { } and lambda { } constructs\n\n#### Pattern Matching\n\n- **ArrayPattern**: [a, b, *rest] array patterns\n- **AlternativePattern**: pattern1 | pattern2\n- **AsPattern**: pattern => variable\n- **CapturePattern**: Variable capture patterns\n\n#### Exception Handling\n\n- **BeginExpr**: begin/rescue/ensure structure\n- **RescueClause**: Exception rescue clauses\n- **EnsureClause**: Cleanup ensure clauses\n\n### Method Names and Identifiers\n\n- **MethodName**: Method name identifiers in various contexts\n- **Toplevel**: Top-level program scope\n\n## Expected test results for local `PrintAst.ql` query\n\nThis repo contains a variant of the open-source `PrintAst.ql` query for `ruby` language, with modifications for local testing:\n\n- Use the `codeql_query_run` tool with `queryName="PrintAST"` and `language="ruby"` to run the bundled PrintAST query\n- Use the `codeql_test_run` tool to run the PrintAST test and compare against expected results\n\n## Expected test results for open-source `PrintAst.ql` query\n\nThe following links can be fetched to get the expected results for different unit tests of the open-source `PrintAst.ql` query for the `ruby` language:\n\n- https://github.com/github/codeql/blob/main/ruby/ql/test/library-tests/ast/Ast.expected\n- https://github.com/github/codeql/blob/main/ruby/ql/test/library-tests/ast/AstDesugar.expected\n';
|
|
63257
64135
|
|
|
63258
64136
|
// src/types/language-types.ts
|
|
63259
64137
|
var LANGUAGE_RESOURCES = [
|
|
63260
64138
|
{
|
|
63261
64139
|
language: "actions",
|
|
63262
|
-
|
|
64140
|
+
astContent: actions_ast_default
|
|
63263
64141
|
},
|
|
63264
64142
|
{
|
|
63265
64143
|
language: "cpp",
|
|
63266
|
-
|
|
63267
|
-
|
|
64144
|
+
astContent: cpp_ast_default,
|
|
64145
|
+
securityContent: cpp_security_query_guide_default
|
|
63268
64146
|
},
|
|
63269
64147
|
{
|
|
63270
64148
|
language: "csharp",
|
|
63271
|
-
|
|
63272
|
-
|
|
64149
|
+
astContent: csharp_ast_default,
|
|
64150
|
+
securityContent: csharp_security_query_guide_default
|
|
63273
64151
|
},
|
|
63274
64152
|
{
|
|
63275
64153
|
language: "go",
|
|
63276
|
-
|
|
63277
|
-
|
|
63278
|
-
|
|
63279
|
-
"
|
|
63280
|
-
"
|
|
63281
|
-
"
|
|
64154
|
+
astContent: go_ast_default,
|
|
64155
|
+
securityContent: go_security_query_guide_default,
|
|
64156
|
+
additionalResources: {
|
|
64157
|
+
"basic-queries": go_basic_queries_default,
|
|
64158
|
+
"dataflow": go_dataflow_default,
|
|
64159
|
+
"library-modeling": go_library_modeling_default
|
|
63282
64160
|
}
|
|
63283
64161
|
},
|
|
63284
64162
|
{
|
|
63285
64163
|
language: "java",
|
|
63286
|
-
|
|
64164
|
+
astContent: java_ast_default
|
|
63287
64165
|
},
|
|
63288
64166
|
{
|
|
63289
64167
|
language: "javascript",
|
|
63290
|
-
|
|
63291
|
-
|
|
64168
|
+
astContent: javascript_ast_default,
|
|
64169
|
+
securityContent: javascript_security_query_guide_default
|
|
63292
64170
|
},
|
|
63293
64171
|
{
|
|
63294
64172
|
language: "python",
|
|
63295
|
-
|
|
63296
|
-
|
|
63297
|
-
},
|
|
63298
|
-
{
|
|
63299
|
-
language: "ql",
|
|
63300
|
-
astFile: "ql/languages/ql/tools/dev/ql_ast.prompt.md"
|
|
64173
|
+
astContent: python_ast_default,
|
|
64174
|
+
securityContent: python_security_query_guide_default
|
|
63301
64175
|
},
|
|
63302
64176
|
{
|
|
63303
64177
|
language: "ruby",
|
|
63304
|
-
|
|
64178
|
+
astContent: ruby_ast_default
|
|
63305
64179
|
}
|
|
63306
64180
|
];
|
|
63307
64181
|
|
|
63308
64182
|
// src/resources/language-resources.ts
|
|
63309
|
-
init_package_paths();
|
|
63310
64183
|
init_logger();
|
|
63311
|
-
function getQLBasePath() {
|
|
63312
|
-
return workspaceRootDir;
|
|
63313
|
-
}
|
|
63314
|
-
function loadResourceContent(relativePath) {
|
|
63315
|
-
try {
|
|
63316
|
-
const fullPath = join17(getQLBasePath(), relativePath);
|
|
63317
|
-
if (!existsSync12(fullPath)) {
|
|
63318
|
-
logger.warn(`Resource file not found: ${fullPath}`);
|
|
63319
|
-
return null;
|
|
63320
|
-
}
|
|
63321
|
-
return readFileSync11(fullPath, "utf-8");
|
|
63322
|
-
} catch (error2) {
|
|
63323
|
-
logger.error(`Error loading resource file ${relativePath}:`, error2);
|
|
63324
|
-
return null;
|
|
63325
|
-
}
|
|
63326
|
-
}
|
|
63327
64184
|
function registerLanguageASTResources(server) {
|
|
63328
64185
|
for (const langResource of LANGUAGE_RESOURCES) {
|
|
63329
|
-
if (!langResource.
|
|
64186
|
+
if (!langResource.astContent) continue;
|
|
63330
64187
|
const resourceUri = `codeql://languages/${langResource.language}/ast`;
|
|
64188
|
+
const content = langResource.astContent;
|
|
63331
64189
|
server.resource(
|
|
63332
64190
|
`${langResource.language.toUpperCase()} AST Reference`,
|
|
63333
64191
|
resourceUri,
|
|
@@ -63335,34 +64193,21 @@ function registerLanguageASTResources(server) {
|
|
|
63335
64193
|
description: `CodeQL AST class reference for ${langResource.language} programs`,
|
|
63336
64194
|
mimeType: "text/markdown"
|
|
63337
64195
|
},
|
|
63338
|
-
async () => {
|
|
63339
|
-
|
|
63340
|
-
|
|
63341
|
-
|
|
63342
|
-
|
|
63343
|
-
|
|
63344
|
-
|
|
63345
|
-
text: `# ${langResource.language.toUpperCase()} AST Reference
|
|
63346
|
-
|
|
63347
|
-
Resource file not found or could not be loaded.`
|
|
63348
|
-
}]
|
|
63349
|
-
};
|
|
63350
|
-
}
|
|
63351
|
-
return {
|
|
63352
|
-
contents: [{
|
|
63353
|
-
uri: resourceUri,
|
|
63354
|
-
mimeType: "text/markdown",
|
|
63355
|
-
text: content
|
|
63356
|
-
}]
|
|
63357
|
-
};
|
|
63358
|
-
}
|
|
64196
|
+
async () => ({
|
|
64197
|
+
contents: [{
|
|
64198
|
+
uri: resourceUri,
|
|
64199
|
+
mimeType: "text/markdown",
|
|
64200
|
+
text: content
|
|
64201
|
+
}]
|
|
64202
|
+
})
|
|
63359
64203
|
);
|
|
63360
64204
|
}
|
|
63361
64205
|
}
|
|
63362
64206
|
function registerLanguageSecurityResources(server) {
|
|
63363
64207
|
for (const langResource of LANGUAGE_RESOURCES) {
|
|
63364
|
-
if (!langResource.
|
|
64208
|
+
if (!langResource.securityContent) continue;
|
|
63365
64209
|
const resourceUri = `codeql://languages/${langResource.language}/security`;
|
|
64210
|
+
const content = langResource.securityContent;
|
|
63366
64211
|
server.resource(
|
|
63367
64212
|
`${langResource.language.toUpperCase()} Security Patterns`,
|
|
63368
64213
|
resourceUri,
|
|
@@ -63370,34 +64215,20 @@ function registerLanguageSecurityResources(server) {
|
|
|
63370
64215
|
description: `CodeQL security query patterns and framework modeling for ${langResource.language}`,
|
|
63371
64216
|
mimeType: "text/markdown"
|
|
63372
64217
|
},
|
|
63373
|
-
async () => {
|
|
63374
|
-
|
|
63375
|
-
|
|
63376
|
-
|
|
63377
|
-
|
|
63378
|
-
|
|
63379
|
-
|
|
63380
|
-
text: `# ${langResource.language.toUpperCase()} Security Patterns
|
|
63381
|
-
|
|
63382
|
-
Resource file not found or could not be loaded.`
|
|
63383
|
-
}]
|
|
63384
|
-
};
|
|
63385
|
-
}
|
|
63386
|
-
return {
|
|
63387
|
-
contents: [{
|
|
63388
|
-
uri: resourceUri,
|
|
63389
|
-
mimeType: "text/markdown",
|
|
63390
|
-
text: content
|
|
63391
|
-
}]
|
|
63392
|
-
};
|
|
63393
|
-
}
|
|
64218
|
+
async () => ({
|
|
64219
|
+
contents: [{
|
|
64220
|
+
uri: resourceUri,
|
|
64221
|
+
mimeType: "text/markdown",
|
|
64222
|
+
text: content
|
|
64223
|
+
}]
|
|
64224
|
+
})
|
|
63394
64225
|
);
|
|
63395
64226
|
}
|
|
63396
64227
|
}
|
|
63397
64228
|
function registerLanguageAdditionalResources(server) {
|
|
63398
64229
|
for (const langResource of LANGUAGE_RESOURCES) {
|
|
63399
|
-
if (!langResource.
|
|
63400
|
-
for (const [resourceType,
|
|
64230
|
+
if (!langResource.additionalResources) continue;
|
|
64231
|
+
for (const [resourceType, content] of Object.entries(langResource.additionalResources)) {
|
|
63401
64232
|
const resourceUri = `codeql://languages/${langResource.language}/${resourceType}`;
|
|
63402
64233
|
server.resource(
|
|
63403
64234
|
`${langResource.language.toUpperCase()} ${resourceType.replace("-", " ").replace(/\b\w/g, (l) => l.toUpperCase())}`,
|
|
@@ -63406,27 +64237,13 @@ function registerLanguageAdditionalResources(server) {
|
|
|
63406
64237
|
description: `CodeQL ${resourceType.replace("-", " ")} guide for ${langResource.language}`,
|
|
63407
64238
|
mimeType: "text/markdown"
|
|
63408
64239
|
},
|
|
63409
|
-
async () => {
|
|
63410
|
-
|
|
63411
|
-
|
|
63412
|
-
|
|
63413
|
-
|
|
63414
|
-
|
|
63415
|
-
|
|
63416
|
-
text: `# ${langResource.language.toUpperCase()} ${resourceType.replace("-", " ").replace(/\b\w/g, (l) => l.toUpperCase())}
|
|
63417
|
-
|
|
63418
|
-
Resource file not found or could not be loaded.`
|
|
63419
|
-
}]
|
|
63420
|
-
};
|
|
63421
|
-
}
|
|
63422
|
-
return {
|
|
63423
|
-
contents: [{
|
|
63424
|
-
uri: resourceUri,
|
|
63425
|
-
mimeType: "text/markdown",
|
|
63426
|
-
text: content
|
|
63427
|
-
}]
|
|
63428
|
-
};
|
|
63429
|
-
}
|
|
64240
|
+
async () => ({
|
|
64241
|
+
contents: [{
|
|
64242
|
+
uri: resourceUri,
|
|
64243
|
+
mimeType: "text/markdown",
|
|
64244
|
+
text: content
|
|
64245
|
+
}]
|
|
64246
|
+
})
|
|
63430
64247
|
);
|
|
63431
64248
|
}
|
|
63432
64249
|
}
|
|
@@ -63440,22 +64257,22 @@ function registerLanguageResources(server) {
|
|
|
63440
64257
|
}
|
|
63441
64258
|
|
|
63442
64259
|
// src/prompts/workflow-prompts.ts
|
|
63443
|
-
import { basename as
|
|
64260
|
+
import { basename as basename7 } from "path";
|
|
63444
64261
|
|
|
63445
64262
|
// src/prompts/document-codeql-query.prompt.md
|
|
63446
64263
|
var document_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Document a CodeQL Query\n\nThis prompt guides you through creating or updating documentation for a CodeQL query file. The documentation is stored as a sibling file to the query with a standardized markdown format.\n\n## Purpose\n\nThe `document_codeql_query` prompt creates/updates **query documentation files** for a specific version of a CodeQL query. Documentation files are stored alongside the query file and provide concise yet comprehensive information about what the query does.\n\nFor creating **workshop learning content** with detailed explanations and visual diagrams, use the `explain_codeql_query` prompt instead.\n\n## Required Inputs\n\n- **queryPath**: Path to the CodeQL query file (`.ql` or `.qlref`)\n- **language**: Target programming language (actions, cpp, csharp, go, java, javascript, python, ruby, swift)\n\n## Documentation File Conventions\n\n### File Location and Naming\n\nFor a query file `QueryFileBaseName.ql`, the documentation file should be:\n\n- **Primary**: `QueryFileBaseName.md` (markdown format, preferred)\n- **Legacy**: `QueryFileBaseName.qhelp` (XML-based query help format)\n\nDocumentation files are **siblings** to the query file (same directory).\n\n### Handling Existing Documentation\n\n1. **No documentation exists**: Create new `QueryFileBaseName.md` file\n2. **`.md` file exists**: Update the existing markdown file\n3. **`.qhelp` file exists**: Use #codeql_generate_query-help tool to convert to markdown, then update\n\n## Workflow Checklist\n\nUse the following MCP server tools to gather context before creating documentation:\n\n### Phase 1: Query Discovery\n\n- [ ] **Step 1: Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` = provided query path\n - Gather: Query source file path, existing documentation files, test files\n - Check: Does `QueryFileBaseName.md` or `QueryFileBaseName.qhelp` exist?\n\n- [ ] **Step 2: Read query metadata**\n - Tool: #codeql_resolve_metadata\n - Parameters: `query` = query file path\n - Gather: @name, @description, @kind, @id, @tags, @precision, @severity\n\n### Phase 2: Convert Existing qhelp (if needed)\n\n- [ ] **Step 3: Convert qhelp to markdown** (only if `.qhelp` exists)\n - Tool: #codeql_generate_query-help\n - Parameters: `query` = query file path, `format` = "markdown"\n - Use output as starting point for updated documentation\n\n### Phase 3: Gather Query Context\n\n- [ ] **Step 4: Validate query structure**\n - Tool: #validate_codeql_query\n - Parameters: `query` = query source code\n - Gather: Structural validation, suggestions\n - Note: This is a heuristic check only \u2014 for full validation, use #codeql_query_compile\n\n- [ ] **Step 5: Explore query types** (if deeper understanding needed)\n - Tool: #codeql_lsp_definition \u2014 navigate to class/predicate definitions\n - Tool: #codeql_lsp_completion \u2014 explore member predicates on types used in the query\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri` (pack root)\n - Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Step 6: Run tests** (if tests exist from Step 1)\n - Tool: #codeql_test_run\n - Parameters: `tests` = test directories\n - Gather: Pass/fail status, confirms query behavior\n\n### Phase 4: Create/Update Documentation\n\nBased on gathered context, create or update the documentation file.\n\n## Documentation Format\n\nThe documentation file (`QueryFileBaseName.md`) should follow this standardized format with these sections:\n\n### Section 1: Title and Description\n\n- H1 heading with the query name from @name metadata\n- One paragraph description from @description, expanded if needed\n\n### Section 2: Metadata Table\n\nA table with these rows:\n\n- ID: The @id value in backticks\n- Kind: The @kind value (problem, path-problem, etc.)\n- Severity: The @severity value\n- Precision: The @precision value\n- Tags: The @tags values\n\n### Section 3: Overview\n\nConcise explanation of what vulnerability/issue this query detects and why it matters. 2-4 sentences.\n\n### Section 4: Recommendation\n\nBrief guidance on how developers should fix issues flagged by this query. Include code patterns to use or avoid.\n\n### Section 5: Example\n\nTwo subsections:\n\n- **Vulnerable Code**: A code block showing a pattern that would be flagged by this query\n- **Fixed Code**: A code block showing the corrected version of the code\n\nUse the appropriate language identifier for the code blocks (e.g., `javascript`, `python`, `java`).\n\n### Section 6: References\n\nA list of links to:\n\n- Relevant CWE if security query\n- Relevant documentation or standards\n- CodeQL documentation for related concepts\n\n## Output Actions\n\nAfter generating documentation content:\n\n1. **For new documentation**: Create the file at `[QueryDirectory]/QueryFileBaseName.md`\n2. **For existing `.md` file**: Update the file with new content, preserving any custom sections\n3. **For existing `.qhelp` file**: Create new `.md` file (keeping `.qhelp` for backward compatibility)\n\n## Important Notes\n\n- **Be concise**: Documentation should be brief but complete. This is reference documentation, not tutorial content.\n- **Keep it current**: Documentation should reflect the current behavior of the query.\n- **Use examples from tests**: If unit tests exist, use those code patterns as examples.\n- **Standard format**: Always use the format above for consistency across all query documentation.\n- **Metadata accuracy**: Ensure documented metadata matches actual query metadata.\n- **For workshops**: Use `explain_codeql_query` prompt when creating workshop content that requires deeper explanations and visual diagrams.\n';
|
|
63447
64264
|
|
|
63448
64265
|
// src/prompts/explain-codeql-query.prompt.md
|
|
63449
|
-
var explain_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Explain a CodeQL Query (Workshop Learning Content)\n\nThis prompt guides you through gathering comprehensive context about a CodeQL query using MCP server tools, then generating detailed explanations suitable for CodeQL workshop learning content.\n\n## Purpose\n\nThe `explain_codeql_query` prompt is designed for creating **learning content** for CodeQL workshops and workshop improvements. It produces in-depth, educational explanations of how a query works, including visual diagrams.\n\nFor creating/updating **query documentation files** (`.md` or `.qhelp`), use the `document_codeql_query` prompt instead.\n\n## Required Inputs\n\n- **queryPath**: Path to the CodeQL query file (`.ql` or `.qlref`)\n- **language**: Target programming language (actions, cpp, csharp, go, java, javascript, python, ruby, swift)\n- **databasePath** (optional): Path to a real CodeQL database for profiling\n\n## Agent AI Instructions\n\n**Critical**: The evaluator logs and profiler outputs from CodeQL can be very large files.
|
|
64266
|
+
var explain_codeql_query_prompt_default = '---\nagent: agent\n---\n\n# Explain a CodeQL Query (Workshop Learning Content)\n\nThis prompt guides you through gathering comprehensive context about a CodeQL query using MCP server tools, then generating detailed explanations suitable for CodeQL workshop learning content.\n\n## Purpose\n\nThe `explain_codeql_query` prompt is designed for creating **learning content** for CodeQL workshops and workshop improvements. It produces in-depth, educational explanations of how a query works, including visual diagrams.\n\nFor creating/updating **query documentation files** (`.md` or `.qhelp`), use the `document_codeql_query` prompt instead.\n\n## Required Inputs\n\n- **queryPath**: Path to the CodeQL query file (`.ql` or `.qlref`)\n- **language**: Target programming language (actions, cpp, csharp, go, java, javascript, python, ruby, swift)\n- **databasePath** (optional): Path to a real CodeQL database for profiling\n\n## Agent AI Instructions\n\n**Critical**: The evaluator logs and profiler outputs from CodeQL can be very large files. Use the MCP server tools to analyze them efficiently:\n\n- Use #profile_codeql_query_from_logs to extract pipeline timing, predicate evaluation order, tuple count progressions, RA operations, and dependencies from evaluator logs \u2014 this single tool provides all evaluator log analysis\n- Use #search_ql_code to find predicates, classes, or patterns across QL library files\n\n## Choosing a Database\n\nSeveral steps below require a CodeQL database. Determine which database to use:\n\n1. **User-provided `databasePath`** \u2014 use this if provided and valid (check with #codeql_resolve_database).\n2. **Test database** \u2014 if Step 1 finds tests, run them in Step 3 to create a `.testproj` database.\n3. **No database available** \u2014 skip Steps 4-6, and base the explanation on source code analysis only.\n\nStore the chosen database path as `$DB` for use in Steps 4-6.\n\n## Workflow Checklist\n\nYou MUST use the following MCP server tools in sequence to gather context before generating your explanation:\n\n### Phase 1: Query Discovery and Validation\n\n- [ ] **Step 1: Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` = provided query path\n - Gather: Query source file, test files, expected results, metadata location\n - Note: If tests exist, record the test directory path for later steps\n\n- [ ] **Step 2: Validate query structure**\n - Tool: #validate_codeql_query\n - Parameters: `query` = contents of the query file\n - Gather: Structural validation results, heuristic warnings/suggestions\n\n### Phase 2: Test Execution and Database Creation\n\n- [ ] **Step 3: Run existing tests** (if tests exist from Step 1)\n - Tool: #codeql_test_run\n - Parameters: `tests` = array of test directories from Step 1\n - Purpose: Ensures test database is created and current with test code\n - Gather: Test pass/fail status, test database path (`.testproj` directory)\n - **If no tests exist**: Skip this step. Use user-provided `databasePath` as `$DB`.\n\n### Phase 3: Code Structure Analysis (requires `$DB`)\n\nSkip this phase entirely if no database is available.\n\n- [ ] **Step 4: Generate PrintAST output**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: provided language\n - `database`: `$DB`\n - `sourceFiles`: test source file names (or representative source files from the database)\n - `format`: `"graphtext"`\n - Gather: AST hierarchy showing code structure representation\n\n- [ ] **Step 5: Generate PrintCFG output** (for key functions)\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: provided language\n - `database`: `$DB`\n - `sourceFunction`: key function name(s) from test code or query source\n - `format`: `"graphtext"`\n - Gather: Control flow graph showing execution paths\n\n### Phase 4: Query Profiling and Evaluation Order (requires `$DB`)\n\nSkip this phase entirely if no database is available.\n\n- [ ] **Step 6a: Run the query with evaluator logging**\n - Tool: #codeql_query_run (or #codeql_database_analyze)\n - Run the query against `$DB` with evaluator logging enabled\n - The tool returns the path to the evaluator log file (`.jsonl`)\n\n- [ ] **Step 6b: Profile from evaluator logs**\n - Tool: #profile_codeql_query_from_logs\n - Parameters:\n - `evaluatorLog`: path to the evaluator log file from Step 6a\n - Gather: Pipeline execution order, predicate timing data, tuple counts\n - **Critical**: This reveals the actual bottom-up evaluation order of predicates\n\n- [ ] **Step 7: Quick evaluate specific predicates** (as needed)\n - First, locate the predicate: Tool: #find_predicate_position with `file` and `name`\n - Then evaluate: Tool: #quick_evaluate with `file`, `db`, and `symbol`\n - Use when: You need more context on how a specific predicate or class behaves\n - Note: #find_class_position finds `class` definitions only, not `module` definitions\n - Note: #find_predicate_position returns 1-based positions; LSP tools use 0-based\n\n### Phase 5: Generate Explanation\n\nBased on all gathered context, generate your explanation with both **verbal** and **visual** components.\n\n## Key Aspects to Analyze in Profiler Output\n\nUnderstanding the query profiler output is critical for explaining how the query actually works. Look for:\n\n1. **Evaluation Order**: Which predicates are evaluated first (base predicates) vs last (dependent predicates)\n2. **Pipeline Timing**: Time taken for each pipeline stage - indicates complexity\n3. **Tuple Counts**: Number of results at each stage - shows data flow volume\n4. **RA Operations**: The relational algebra operations (SCAN, JOIN, AGGREGATE) reveal query execution strategy\n5. **Dependencies**: Which predicates depend on others (shown by evaluation order)\n\n## Output Format\n\n### Verbal Explanation Structure\n\nGenerate a single markdown document with these sections in order:\n\n1. **Query Overview** \u2014 2-3 sentence summary of what the query detects and why it matters.\n2. **Query Metadata** \u2014 Table with: Name, Description, Kind, ID, Tags, Precision, Severity (from `@` annotations).\n3. **What This Query Detects** \u2014 Security implications (CWE/OWASP if applicable), why the pattern is problematic, real-world attack scenarios.\n4. **How the Query Works** \u2014 Two subsections:\n - **Bottom-Up Evaluation Order**: Evaluation timeline table (Order, Predicate/Pipeline, Time ms, Tuples) derived from profiler data. Explain that CodeQL evaluates bottom-up.\n - **Key Components**: Imports, classes and characteristic predicates, helper predicates, data flow configuration (sources, sinks, sanitizers, additional flow steps), main query `from`/`where`/`select`.\n5. **Test Code Analysis** (if database was available) \u2014 AST structure insights from PrintAST, control flow insights from PrintCFG.\n6. **Example Patterns** \u2014 Positive test cases (should match) and negative test cases (should not match) with explanations.\n7. **Performance Characteristics** (if profiler data available) \u2014 Most expensive predicates, highest tuple counts, optimization opportunities.\n8. **Limitations and Edge Cases** \u2014 Patterns the query might miss, known false positive scenarios.\n\n### Visual Explanation: Mermaid Evaluation Diagram\n\nGenerate a `mermaid` `flowchart BU` (bottom-up) diagram showing the evaluation order derived from profiler data. Guidelines:\n\n- Use subgraphs to group predicates by evaluation phase (base, intermediate, flow analysis, final select)\n- Label nodes with actual predicate/class names from the query\n- Show dependency edges between predicates\n- Annotate expensive operations with timing (e.g., `[500ms]`)\n- Direction must be `BU` to reflect bottom-up evaluation\n\n## Important Notes\n\n- **Always use tools first**: Do not generate explanations based only on query source code. Use the MCP tools to gather actual runtime data.\n- **Use the profiler tool for evaluator logs**: Evaluator logs can be huge. Use #profile_codeql_query_from_logs which returns compact JSON with per-predicate metrics and a line-indexed detail file. Use `read_file` with the `detailLines` ranges from the response to access full RA operations and tuple progressions for any predicate \u2014 do not use CLI grep or read log files directly.\n- **Evaluation order matters**: CodeQL evaluates bottom-up, not top-down. The profiler output reveals the true execution order.\n- **Focus on learning**: This is for workshop content, so include educational context and explanations suitable for CodeQL learners.\n- **Visual diagrams**: Always include a mermaid diagram showing evaluation order.\n- **Reference documentation**: For actual QL evaluation semantics, see [Evaluation of QL programs](https://codeql.github.com/docs/ql-language-reference/evaluation-of-ql-programs/)\n';
|
|
63450
64267
|
|
|
63451
64268
|
// src/prompts/ql-lsp-iterative-development.prompt.md
|
|
63452
|
-
var ql_lsp_iterative_development_prompt_default = '---\nagent: agent\n---\n\n# Iterative CodeQL Development with LSP Tools\n\nUse the MCP server tools from this prompt to iteratively develop and refine CodeQL queries using the LSP-powered tools.\nThese "iterative" tools work entirely through file paths and numeric positions.\nEvery operation is expressible as a tool call with explicit `file_path`, `line`, and `character` parameters.\nThus, this prompt can be used in any environment where the query files are on disk, and it does not require any special editor integration.\n\n## Use This Prompt When\n\n- Exploring unfamiliar CodeQL libraries to discover available classes and predicates\n- Incrementally building a query clause-by-clause with real-time feedback\n- Navigating from a type usage to its definition to understand its API\n- Finding all usages of a predicate to learn patterns from existing queries\n- Validating query fragments before assembling a complete query\n- Debugging individual predicates by evaluating them in isolation against a database\n\n## Prerequisites\n\n1. A CodeQL pack with `codeql-pack.yml` on disk\n2. Dependencies installed via #codeql_pack_install (pointing at the pack directory)\n3. Query files saved to disk (LSP tools operate on files, not inline strings)\n\n## Key Concept: Positions Are File Path + Line + Character\n\nAll LSP tools identify locations using three values:\n\n- `file_path`: absolute path to a `.ql` or `.qll` file\n- `line`: **0-based** line number (line 1 in the file = `line: 0`)\n- `character`: **0-based** column offset within that line\n\nThe `workspace_uri` parameter must point to the **pack root directory** (the folder\ncontaining `codeql-pack.yml`) for import resolution to work. Without it, completions\nand definitions for imported libraries will be empty.\n\n> **Critical**: LSP line/character positions are 0-based, but `read_file`,\n> #find_predicate_position, and #find_class_position return 1-based positions.\n> Always subtract 1 when passing their output to LSP tools.\n\n## Step 1: Discover Available Types with Completions\n\nUse #codeql_lsp_completion to explore what types and predicates are available at any\nposition in a query file. This replaces manual documentation browsing.\n\n**Example**: To see what classes are available in a `from` clause after `import javascript`:\n\n```text\nTool: codeql_lsp_completion\nParameters:\n file_path: /path/to/your/query.ql\n line: 9 # 0-based line of the `from` clause\n character: 5 # position after `from ` where you want completions\n workspace_uri: /path/to/pack-root # directory containing codeql-pack.yml\n```\n\nCompletions include class names with full documentation. For example, requesting\ncompletions in a JavaScript query\'s `from` clause returns 150+ types like\n`CallNode`, `PropWrite`, `RemoteFlowSource`, etc., each with docstrings.\n\n**Exploring member predicates**: To see what methods a variable offers, request\ncompletions after the dot. For example, if `pw` is typed as `DataFlow::PropWrite`,\nrequesting completions at the position after `pw.` returns all member predicates\nlike `getPropertyName()`, `getRhs()`, `getBase()`, `writes(base, prop, rhs)`,\neach with full signature and documentation.\n\n## Step 2: Navigate to Definitions\n\nUse #codeql_lsp_definition to find where a class, predicate, or module is defined.\nThis returns the file URI and line range of the definition \u2014 even into library pack\nfiles you haven\'t opened.\n\n```text\nTool: codeql_lsp_definition\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line containing the symbol\n character: 30 # 0-based column within the symbol name\n workspace_uri: /path/to/pack-root\n```\n\n**Example**: Navigating to `RemoteFlowSource` at line 12, character 30 returns:\n\n```text\nuri: file:///.../.codeql/packages/codeql/javascript-all/2.6.19/\n semmle/javascript/security/dataflow/RemoteFlowSources.qll\nstartLine: 14, startCharacter: 17\n```\n\nYou can then read that file to understand the class\'s API. This is how you discover\nwhat predicates a type offers without documentation \u2014 go to the definition and read\nthe source.\n\n## Step 3: Find All References\n\nUse #codeql_lsp_references to find how a symbol is used across the workspace.\n\n```text\nTool: codeql_lsp_references\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line\n character: 30 # 0-based column within the symbol\n workspace_uri: /path/to/pack-root\n```\n\n> **Scope note**: References are scoped to the pack identified by `workspace_uri`.\n> To find usages in library code, point `workspace_uri` to the library pack root.\n> For usages within your own pack only, point it to your pack root.\n\nThis is invaluable for learning how experienced query authors use a predicate \u2014\nfind real usage examples instead of guessing from documentation.\n\n## Step 4: Locate Symbols with Position Finders\n\nUse #find_predicate_position and #find_class_position to locate where a specific\nsymbol is defined in a file. These return **1-based** line/column positions.\n\n```text\nTool: find_predicate_position\nParameters:\n file: /path/to/your/query.ql\n name: isSource\nReturns: { start_line: 12, start_col: 13, end_line: 12, end_col: 20 }\n```\n\n> **Note**: #find_class_position finds `class` definitions only \u2014 it does not find\n> `module` definitions. Use #find_predicate_position for predicates inside modules.\n\n**Combining with LSP tools**: To navigate to a predicate\'s definition in library code:\n\n1. Use #find_predicate_position to get its 1-based position\n2. Subtract 1 from line/col to convert to 0-based\n3. Pass to #codeql_lsp_definition to jump to the underlying type\n\n## Step 5: Quick-Evaluate Individual Predicates\n\nUse #quick_evaluate to evaluate a single predicate or class against a database\nwithout running the full query. This is the fastest way to debug whether a predicate\nmatches what you expect.\n\n```text\nTool: quick_evaluate\nParameters:\n file: /path/to/your/query.ql\n db: /path/to/test-database.testproj\n symbol: isSink\n output_path: /tmp/quickeval-results # optional, for inspecting bqrs output\n```\n\nThe tool evaluates just that symbol (predicate or class) and returns the result path.\nUse #codeql_bqrs_decode on the output to inspect results in CSV or JSON format.\n\n## Step 6: Validate at Multiple Levels\n\nUse the right validation tool for each situation:\n\n| Tool | Use When | Input | Resolves Imports? |\n| ----------------------- | --------------------------------------- | ------------------ | ------------------- |\n| #validate_codeql_query | Quick structural check | Inline QL string | No (heuristic only) |\n| #codeql_lsp_diagnostics | Syntax/semantic validation of fragments | Inline QL string | No |\n| #codeql_query_compile | Full compilation check | On-disk `.ql` file | Yes |\n| #codeql_test_run | End-to-end result validation | Test directory | Yes |\n\n**#codeql_lsp_diagnostics** validates QL syntax and semantics for inline code snippets,\nbut **cannot resolve `import` statements** (like `import javascript`). Use it for:\n\n- Checking predicate signatures and QL syntax\n- Verifying `from`/`where`/`select` clause structure\n- Catching type errors in import-free QL fragments\n\nFor queries with imports, always use #codeql_query_compile on the saved file.\n\n## Iterative Development Loop\n\n```text\n1. Write/modify a clause in the query file (save to disk)\n \u2193\n2. codeql_lsp_completion \u2192 verify context is valid (non-empty = good)\n \u2193\n3. codeql_query_compile \u2192 check for compilation errors\n \u2193\n4. codeql_test_run \u2192 validate against expected results\n \u2193\n5. If unexpected results: quick_evaluate on individual predicates\n \u2193\n6. If predicate is wrong: codeql_lsp_completion to explore the API\n \u2193\n7. If types are unclear: codeql_lsp_definition to read the source\n \u2193\n8. If stuck: codeql_lsp_references to find usage examples\n \u2193\n9. Repeat from step 1\n```\n\n## Worked Example: Building a Taint-Tracking Query\n\nThis example shows the tools in action for building a JavaScript XSS query.\n\n### 1. Create the query file and install dependencies\n\nWrite a `.ql` file with `import javascript` and a skeleton `from`/`where`/`select`.\nRun #codeql_pack_install on the pack directory.\n\n### 2. Explore sink types\n\nRequest completions in the `from` clause to discover `DataFlow::PropWrite`:\n\n```text\ncodeql_lsp_completion(file_path=..., line=9, character=5, workspace_uri=pack_root)\n\u2192 155 completions including PropWrite, CallNode, MethodCallNode, ...\n```\n\n### 3. Explore `PropWrite` member predicates\n\nAfter typing `pw.` in the `where` clause, request completions:\n\n```text\ncodeql_lsp_completion(file_path=..., line=12, character=9, workspace_uri=pack_root)\n\u2192 43 predicates: getPropertyName(), getRhs(), getBase(), writes(), ...\n```\n\n### 4. Navigate to `RemoteFlowSource` definition\n\n```text\ncodeql_lsp_definition(file_path=..., line=11, character=30, workspace_uri=pack_root)\n\u2192 RemoteFlowSources.qll line 14 in codeql/javascript-all\n```\n\n### 5. Compile and test incrementally\n\n```text\ncodeql_query_compile(query=file_path) \u2192 check for errors\ncodeql_test_run(tests=[test_dir], learn=true) \u2192 populate .expected files\n```\n\n### 6. Debug a predicate in isolation\n\n```text\nfind_predicate_position(file=..., name="isSink") \u2192 line 16, col 13\nquick_evaluate(file=..., db=test.testproj, symbol="isSink") \u2192 inspect results\n```\n\n## Important Notes\n\n- **All LSP tools use 0-based positions**. #find_class_position and\n #find_predicate_position return 1-based positions. Convert before combining.\n- **`workspace_uri` must be the pack root** (the directory containing\n `codeql-pack.yml`). Without it, completions and definitions will be empty.\n- **Run #codeql_pack_install first**. LSP tools require resolved dependencies.\n- **#codeql_lsp_diagnostics cannot resolve imports**. For `import javascript`\n and similar, use #codeql_query_compile on the on-disk file instead.\n- **#find_class_position finds `class` only**, not `module` definitions.\n Use grep or #find_predicate_position for predicates inside modules.\n- **#codeql_lsp_references scope** depends on `workspace_uri`. Point it at\n a library pack root to find usages across library code.\n';
|
|
64269
|
+
var ql_lsp_iterative_development_prompt_default = '---\nagent: agent\n---\n\n# Iterative CodeQL Development with LSP Tools\n\nUse the MCP server tools from this prompt to iteratively develop and refine CodeQL queries using the LSP-powered tools.\nThese "iterative" tools work entirely through file paths and numeric positions.\nEvery operation is expressible as a tool call with explicit `file_path`, `line`, and `character` parameters.\nThus, this prompt can be used in any environment where the query files are on disk, and it does not require any special editor integration.\n\n## Use This Prompt When\n\n- Exploring unfamiliar CodeQL libraries to discover available classes and predicates\n- Incrementally building a query clause-by-clause with real-time feedback\n- Navigating from a type usage to its definition to understand its API\n- Finding all usages of a predicate to learn patterns from existing queries\n- Validating query fragments before assembling a complete query\n- Debugging individual predicates by evaluating them in isolation against a database\n\n## Prerequisites\n\n1. A CodeQL pack with `codeql-pack.yml` on disk\n2. Dependencies installed via #codeql_pack_install (pointing at the pack directory)\n3. Query files saved to disk (LSP tools operate on files, not inline strings)\n\n## Key Concept: Positions Are File Path + Line + Character\n\nAll LSP tools identify locations using three values:\n\n- `file_path`: absolute path to a `.ql` or `.qll` file\n- `line`: **0-based** line number (line 1 in the file = `line: 0`)\n- `character`: **0-based** column offset within that line\n\nThe `workspace_uri` parameter must point to the **pack root directory** (the folder\ncontaining `codeql-pack.yml`) for import resolution to work. Without it, completions\nand definitions for imported libraries will be empty.\n\n> **Critical**: LSP line/character positions are 0-based, but `read_file`,\n> #find_predicate_position, and #find_class_position return 1-based positions.\n> Always subtract 1 when passing their output to LSP tools.\n\n## Step 1: Discover Available Types with Completions\n\nUse #codeql_lsp_completion to explore what types and predicates are available at any\nposition in a query file. This replaces manual documentation browsing.\n\n**Example**: To see what classes are available in a `from` clause after `import javascript`:\n\n```text\nTool: codeql_lsp_completion\nParameters:\n file_path: /path/to/your/query.ql\n line: 9 # 0-based line of the `from` clause\n character: 5 # position after `from ` where you want completions\n workspace_uri: /path/to/pack-root # directory containing codeql-pack.yml\n```\n\nCompletions include class names with full documentation. For example, requesting\ncompletions in a JavaScript query\'s `from` clause returns 150+ types like\n`CallNode`, `PropWrite`, `RemoteFlowSource`, etc., each with docstrings.\n\n**Exploring member predicates**: To see what methods a variable offers, request\ncompletions after the dot. For example, if `pw` is typed as `DataFlow::PropWrite`,\nrequesting completions at the position after `pw.` returns all member predicates\nlike `getPropertyName()`, `getRhs()`, `getBase()`, `writes(base, prop, rhs)`,\neach with full signature and documentation.\n\n## Step 2: Navigate to Definitions\n\nUse #codeql_lsp_definition to find where a class, predicate, or module is defined.\nThis returns the file URI and line range of the definition \u2014 even into library pack\nfiles you haven\'t opened.\n\n```text\nTool: codeql_lsp_definition\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line containing the symbol\n character: 30 # 0-based column within the symbol name\n workspace_uri: /path/to/pack-root\n```\n\n**Example**: Navigating to `RemoteFlowSource` at line 12, character 30 returns:\n\n```text\nuri: file:///.../.codeql/packages/codeql/javascript-all/2.6.19/\n semmle/javascript/security/dataflow/RemoteFlowSources.qll\nstartLine: 14, startCharacter: 17\n```\n\nYou can then read that file to understand the class\'s API. This is how you discover\nwhat predicates a type offers without documentation \u2014 go to the definition and read\nthe source.\n\n## Step 3: Find All References\n\nUse #codeql_lsp_references to find how a symbol is used across the workspace.\n\n```text\nTool: codeql_lsp_references\nParameters:\n file_path: /path/to/your/query.ql\n line: 11 # 0-based line\n character: 30 # 0-based column within the symbol\n workspace_uri: /path/to/pack-root\n```\n\n> **Scope note**: References are scoped to the pack identified by `workspace_uri`.\n> To find usages in library code, point `workspace_uri` to the library pack root.\n> For usages within your own pack only, point it to your pack root.\n\nThis is invaluable for learning how experienced query authors use a predicate \u2014\nfind real usage examples instead of guessing from documentation.\n\n## Step 4: Locate Symbols with Position Finders\n\nUse #find_predicate_position and #find_class_position to locate where a specific\nsymbol is defined in a file. These return **1-based** line/column positions.\n\n```text\nTool: find_predicate_position\nParameters:\n file: /path/to/your/query.ql\n name: isSource\nReturns: { start_line: 12, start_col: 13, end_line: 12, end_col: 20 }\n```\n\n> **Note**: #find_class_position finds `class` definitions only \u2014 it does not find\n> `module` definitions. Use #find_predicate_position for predicates inside modules,\n> or use #search_ql_code to search across QL files by text or regex pattern.\n\n**Combining with LSP tools**: To navigate to a predicate\'s definition in library code:\n\n1. Use #find_predicate_position to get its 1-based position\n2. Subtract 1 from line/col to convert to 0-based\n3. Pass to #codeql_lsp_definition to jump to the underlying type\n\n## Step 5: Quick-Evaluate Individual Predicates\n\nUse #quick_evaluate to evaluate a single predicate or class against a database\nwithout running the full query. This is the fastest way to debug whether a predicate\nmatches what you expect.\n\n```text\nTool: quick_evaluate\nParameters:\n file: /path/to/your/query.ql\n db: /path/to/test-database.testproj\n symbol: isSink\n output_path: /tmp/quickeval-results # optional, for inspecting bqrs output\n```\n\nThe tool evaluates just that symbol (predicate or class) and returns the result path.\nUse #codeql_bqrs_decode on the output to inspect results in CSV or JSON format.\n\n## Step 6: Validate at Multiple Levels\n\nUse the right validation tool for each situation:\n\n| Tool | Use When | Input | Resolves Imports? |\n| ----------------------- | --------------------------------------- | ------------------ | ------------------- |\n| #validate_codeql_query | Quick structural check | Inline QL string | No (heuristic only) |\n| #codeql_lsp_diagnostics | Syntax/semantic validation of fragments | Inline QL string | No |\n| #codeql_query_compile | Full compilation check | On-disk `.ql` file | Yes |\n| #codeql_test_run | End-to-end result validation | Test directory | Yes |\n\n**#codeql_lsp_diagnostics** validates QL syntax and semantics for inline code snippets,\nbut **cannot resolve `import` statements** (like `import javascript`). Use it for:\n\n- Checking predicate signatures and QL syntax\n- Verifying `from`/`where`/`select` clause structure\n- Catching type errors in import-free QL fragments\n\nFor queries with imports, always use #codeql_query_compile on the saved file.\n\n## Iterative Development Loop\n\n```text\n1. Write/modify a clause in the query file (save to disk)\n \u2193\n2. codeql_lsp_completion \u2192 verify context is valid (non-empty = good)\n \u2193\n3. codeql_query_compile \u2192 check for compilation errors\n \u2193\n4. codeql_test_run \u2192 validate against expected results\n \u2193\n5. If unexpected results: quick_evaluate on individual predicates\n \u2193\n6. If predicate is wrong: codeql_lsp_completion to explore the API\n \u2193\n7. If types are unclear: codeql_lsp_definition to read the source\n \u2193\n8. If stuck: codeql_lsp_references to find usage examples\n \u2193\n9. Repeat from step 1\n```\n\n## Worked Example: Building a Taint-Tracking Query\n\nThis example shows the tools in action for building a JavaScript XSS query.\n\n### 1. Create the query file and install dependencies\n\nWrite a `.ql` file with `import javascript` and a skeleton `from`/`where`/`select`.\nRun #codeql_pack_install on the pack directory.\n\n### 2. Explore sink types\n\nRequest completions in the `from` clause to discover `DataFlow::PropWrite`:\n\n```text\ncodeql_lsp_completion(file_path=..., line=9, character=5, workspace_uri=pack_root)\n\u2192 155 completions including PropWrite, CallNode, MethodCallNode, ...\n```\n\n### 3. Explore `PropWrite` member predicates\n\nAfter typing `pw.` in the `where` clause, request completions:\n\n```text\ncodeql_lsp_completion(file_path=..., line=12, character=9, workspace_uri=pack_root)\n\u2192 43 predicates: getPropertyName(), getRhs(), getBase(), writes(), ...\n```\n\n### 4. Navigate to `RemoteFlowSource` definition\n\n```text\ncodeql_lsp_definition(file_path=..., line=11, character=30, workspace_uri=pack_root)\n\u2192 RemoteFlowSources.qll line 14 in codeql/javascript-all\n```\n\n### 5. Compile and test incrementally\n\n```text\ncodeql_query_compile(query=file_path) \u2192 check for errors\ncodeql_test_run(tests=[test_dir], learn=true) \u2192 populate .expected files\n```\n\n### 6. Debug a predicate in isolation\n\n```text\nfind_predicate_position(file=..., name="isSink") \u2192 line 16, col 13\nquick_evaluate(file=..., db=test.testproj, symbol="isSink") \u2192 inspect results\n```\n\n## Important Notes\n\n- **All LSP tools use 0-based positions**. #find_class_position and\n #find_predicate_position return 1-based positions. Convert before combining.\n- **`workspace_uri` must be the pack root** (the directory containing\n `codeql-pack.yml`). Without it, completions and definitions will be empty.\n- **Run #codeql_pack_install first**. LSP tools require resolved dependencies.\n- **#codeql_lsp_diagnostics cannot resolve imports**. For `import javascript`\n and similar, use #codeql_query_compile on the on-disk file instead.\n- **#find_class_position finds `class` only**, not `module` definitions.\n Use #search_ql_code or #find_predicate_position for predicates inside modules.\n- **#codeql_lsp_references scope** depends on `workspace_uri`. Point it at\n a library pack root to find usages across library code.\n';
|
|
63453
64270
|
|
|
63454
64271
|
// src/prompts/ql-tdd-advanced.prompt.md
|
|
63455
|
-
var ql_tdd_advanced_prompt_default = '---\nagent: agent\n---\n\n# Advanced Test-Driven CodeQL Query Development\n\nThis advanced guide builds on the basic TDD methodology with powerful MCP server tools for deeper code analysis. Use this when developing complex queries that require understanding AST structure, control flow, and call relationships.\n\nFor basic TDD workflow, see: `codeql://prompts/ql-tdd-basic`\n\n## When to Use This Advanced Guide\n\n- **Complex AST patterns**: When you need to understand how CodeQL represents specific language constructs\n- **Control flow queries**: When analyzing program flow, branching, or loop structures\n- **Call graph analysis**: When tracing function calls or method invocations\n- **Iterative refinement**: When debugging queries that don\'t produce expected results\n- **Performance optimization**: When understanding query evaluation patterns\n\n## Core Advanced Tools\n\n### 1. AST/CFG Visualization with #codeql_query_run\n\nUse the bundled tools queries to visualize code structure:\n\n```typescript\n// Generate Abstract Syntax Tree for test code\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java", // or "javascript", "python", "cpp", etc.\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output.txt"\n}\n\n// Generate Control Flow Graph\ncodeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg-output.txt"\n}\n\n// Analyze outbound calls from a function\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "myFunction",\n format: "sarif-latest"\n}\n\n// Analyze inbound calls to a function\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "targetMethod",\n format: "sarif-latest"\n}\n```\n\n**Critical**: Always verify that tools queries return **non-empty output** with actual nodes/edges, not just headers.\n\n### 2. Quick Evaluation with #quick_evaluate\n\nUse #quick_evaluate for rapid iteration on specific predicates or classes:\n\n```typescript\n// First, find the position of a predicate\nfind_predicate_position: {\n file: "/path/to/Query.ql",\n name: "isVulnerableSink"\n}\n\n// Then evaluate just that predicate\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "isVulnerableSink",\n output_path: "/tmp/quickeval.bqrs"\n}\n\n// Or evaluate a specific class\n// NOTE: find_class_position finds `class` definitions only, not `module` definitions\nfind_class_position: {\n file: "/path/to/Query.ql",\n name: "ThrowingMethodCall"\n}\n\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "ThrowingMethodCall"\n}\n```\n\n### 3. LSP-Powered Code Navigation\n\nUse the LSP tools for real-time code exploration during query development:\n\n```typescript\n// Discover available types after `import javascript`\ncodeql_lsp_completion: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line with `from` clause\n character: 5, // 0-based column position\n workspace_uri: "/path/to/pack-root" // REQUIRED: directory containing codeql-pack.yml\n}\n\n// Navigate to a class definition to see its predicates\ncodeql_lsp_definition: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line containing the class name\n character: 10, // 0-based column on the class name\n workspace_uri: "/path/to/pack-root"\n}\n\n// Find all usages of a predicate across the pack\ncodeql_lsp_references: {\n file_path: "/path/to/Query.ql",\n line: 8,\n character: 5,\n workspace_uri: "/path/to/pack-root"\n}\n```\n\n**Important LSP tool notes**:\n\n- `workspace_uri` must be a **plain directory path** (not a `file://` URI) pointing to the pack root containing `codeql-pack.yml`\n- All LSP tools use **0-based** line/character positions\n- #find_predicate_position and #find_class_position return **1-based** positions \u2014 subtract 1 before passing to LSP tools\n- Run #codeql_pack_install before using LSP tools \u2014 they require resolved dependencies\n- Request completions **after a dot** (e.g., `pw.`) to see all member predicates with full documentation\n\n### 4. Query File Discovery with #find_codeql_query_files\n\nUse this tool frequently to understand query dependencies and test structure:\n\n```typescript\nfind_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n}\n// Returns: query file, test directory, test files, metadata, dependencies\n```\n\n## Advanced TDD Workflow\n\n### Phase 0: Test Environment Setup (Critical for Java)\n\nFor Java tests that depend on external libraries (JUnit, etc.), create an `options` file in each test directory:\n\n```text\n//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.13:${testdir}/../../stubs/junit-jupiter-api-5.2.0\n```\n\n**Key points**:\n\n- `${testdir}` is relative to the test directory containing the `options` file\n- Use `:` (colon) to separate multiple classpath entries\n- Stub files must contain minimal class/interface definitions for compilation\n\n### Phase 1: Deep Code Analysis\n\nBefore writing any query logic:\n\n1. **Extract test database**:\n\n ```typescript\n codeql_test_extract: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n2. **Generate and study the AST**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast.txt"\n }\n ```\n\n3. **Identify key AST classes and predicates** from the output:\n - Note the class names (e.g., `MethodCall`, `TryStmt`, `LambdaExpr`)\n - Note parent-child relationships\n - Identify which nodes correspond to your test cases\n\n4. **Generate CFG if analyzing control flow**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg.txt"\n }\n ```\n\n### Phase 2: Iterative Predicate Development\n\nInstead of writing the full query at once:\n\n1. **Start with a single class or predicate**:\n\n ```ql\n class MyPattern extends MethodCall {\n MyPattern() {\n this.getMethod().hasName("targetMethod")\n }\n }\n ```\n\n2. **Use #quick_evaluate to test it**:\n\n ```typescript\n quick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "MyPattern"\n }\n ```\n\n3. **Refine based on results**:\n - Too many results? Add constraints\n - Too few results? Relax constraints\n - Wrong results? Study AST output again\n\n4. **Repeat for each component** before combining\n\n### Phase 3: Incremental Query Assembly\n\n1. **Combine validated predicates** into the main query\n2. **Run full tests** after each combination:\n\n ```typescript\n codeql_test_run: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n3. **Use #find_codeql_query_files** to track all related files:\n\n ```typescript\n find_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n }\n ```\n\n## Common Advanced Patterns\n\n### Pattern: Understanding Nested Structures\n\nWhen your query involves nested constructs (e.g., lambdas inside method calls):\n\n```ql\n// First, find the outer construct\nclass OuterPattern extends MethodCall {\n OuterPattern() {\n this.getMethod().hasName("assertThrows")\n }\n\n // Navigate to inner construct\n Expr getLambdaBody() {\n exists(LambdaExpr le |\n le = this.getAChildExpr() and\n result = le.getExprBody()\n )\n }\n}\n```\n\nUse `PrintAST` to understand the parent-child relationships.\n\n### Pattern: Control Flow Dependencies\n\nWhen your query needs to understand execution order:\n\n```ql\n// Use CFG to understand which statements precede others\npredicate precedesInBlock(Stmt s1, Stmt s2) {\n exists(BasicBlock bb |\n s1.getBasicBlock() = bb and\n s2.getBasicBlock() = bb and\n s1.getLocation().getStartLine() < s2.getLocation().getStartLine()\n )\n}\n```\n\nUse `PrintCFG` to verify the control flow structure.\n\n### Pattern: Call Chain Analysis\n\nWhen tracing calls through multiple functions:\n\n```typescript\n// First, understand the call graph from your entry point\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "entryPoint"\n}\n\n// Then trace back from your target\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "sensitiveOperation"\n}\n```\n\n## Debugging Tips\n\n### When Results Are Empty\n\n1. **Check AST first**: Run `PrintAST` to verify the code structure matches expectations\n2. **Simplify the query**: Remove constraints one by one using #quick_evaluate\n3. **Check enclosing callables**: Lambda bodies may have different `getEnclosingCallable()` than expected\n4. **Verify test database extraction**: Ensure the `.testproj` directory was created successfully\n\n### When Results Are Incorrect\n\n1. **Quick evaluate individual predicates**: Isolate which part is wrong\n2. **Compare with AST output**: Verify your understanding of the structure\n3. **Check for missing cases**: Your pattern may not cover all code variations\n\n### When Compilation Fails with "override" Error\n\nIf you see `annotation \'override\' missing on predicate`, you\'ve accidentally created a predicate with the same name as one in the parent class. **Rename your predicate** to avoid the conflict:\n\n```ql\n// BAD: Method already has getAThrownExceptionType()\nclass ThrowingMethod extends Method {\n RefType getAThrownExceptionType() { ... } // Error!\n}\n\n// GOOD: Use a distinct name\nclass ThrowingMethod extends Method {\n RefType getDeclaredExceptionType() { ... } // Works\n}\n```\n\n### When Query Is Slow\n\n1. **Enable evaluator logs**:\n\n ```typescript\n codeql_query_run: {\n query: "/path/to/Query.ql",\n database: "/path/to/db",\n "evaluator-log": "/path/to/log.json",\n "evaluator-log-level": 5\n }\n ```\n\n2. **Generate log summary**:\n\n ```typescript\n codeql_generate_log_summary: {\n inputLog: "/path/to/log.json",\n format: "text"\n }\n ```\n\n3. **Profile from evaluator logs** (after step 1 produces a log file):\n\n ```typescript\n profile_codeql_query_from_logs: {\n evaluatorLog: \'/path/to/log.json\';\n }\n ```\n\n## Checklist for Complex Queries\n\n### Before Starting\n\n- [ ] Test database extracted successfully\n- [ ] `PrintAST` output reviewed and understood\n- [ ] Key AST classes identified\n- [ ] Test cases cover positive, negative, and edge cases\n\n### During Development\n\n- [ ] Each predicate/class tested with #quick_evaluate\n- [ ] #find_codeql_query_files used to track dependencies\n- [ ] CFG consulted for control flow patterns\n- [ ] Call graphs generated for cross-function analysis\n\n### After Each Change\n\n- [ ] Query compiles with #codeql_query_compile\n- [ ] Quick evaluation shows expected results\n- [ ] Full tests pass with #codeql_test_run\n- [ ] No duplicate or missing results\n\n### Final Validation\n\n- [ ] All test cases pass\n- [ ] No false positives in results\n- [ ] No false negatives (all expected cases caught)\n- [ ] Query formatted with #codeql_query_format\n- [ ] Performance acceptable (check with #profile_codeql_query_from_logs)\n\n## Test Acceptance Workflow\n\nWhen your query produces correct results but differs from the `.expected` file:\n\n1. **Review the `.actual` file** to verify results are correct\n2. **Accept the results** to update the expected baseline:\n\n ```typescript\n codeql_test_accept: {\n tests: [\'/path/to/test/QueryTest\'];\n }\n ```\n\n3. **Re-run tests** to confirm they now pass\n\n**Warning**: Only accept results after careful review. Don\'t blindly accept to make tests pass.\n\n## Tool Reference\n\n| Tool | Purpose | When to Use |\n| ------------------------------- | --------------------------------- | ------------------------------- |\n| #codeql_query_run (PrintAST) | Visualize AST structure | Start of development, debugging |\n| #codeql_query_run (PrintCFG) | Visualize control flow | Control flow queries |\n| #codeql_query_run (CallGraph\\*) | Analyze call relationships | Cross-function queries |\n| #codeql_bqrs_interpret | Convert BQRS to readable format | After running graph queries |\n| #quick_evaluate | Test individual predicates | Iterative development |\n| #find_predicate_position | Locate predicate for quickeval | Before quick_evaluate |\n| #find_class_position | Locate class for quickeval | Before quick_evaluate |\n| #find_codeql_query_files | Discover related files | Planning, tracking changes |\n| #codeql_test_accept | Accept actual results as expected | After verifying correct output |\n| #profile_codeql_query_from_logs | Performance analysis | Optimization |\n\n## Interpreting Graph Query Results\n\nWhen running `PrintAST` or `PrintCFG`, the results are stored in BQRS format. To convert to readable text:\n\n```typescript\n// After codeql_query_run produces results.bqrs\ncodeql_bqrs_interpret: {\n file: "/path/to/results.bqrs",\n format: "graphtext",\n output: "/path/to/output.txt",\n t: ["kind=graph", "id=java/tools/print-ast"]\n}\n```\n\n**Note**: The output may create a directory structure (e.g., `output.txt/java/tools/print-ast.txt`) rather than a single file.\n\n## Example: Workshop Development\n\nWhen creating CodeQL workshops, this advanced methodology is essential:\n\n1. **Analyze production query** with #find_codeql_query_files\n2. **Generate AST/CFG** for workshop test code\n3. **Decompose query** into stages, validating each with #quick_evaluate\n4. **Create exercises** with scaffolding based on AST understanding\n5. **Validate solutions** ensure each stage produces correct results\n\n### Exercise Design Tips\n\nWhen creating exercise stubs from solutions:\n\n```ql\n// Use none() as placeholder in characteristic predicates\nclass MyPattern extends MethodCall {\n MyPattern() {\n // TODO: Implement - check for methods named "targetMethod"\n // Hint: Use this.getMethod().hasName(...)\n none()\n }\n}\n```\n\n- **Include TODO comments** with specific hints\n- **Reference AST class names** students should look for\n- **Build incrementally** - each exercise should build on the previous\n- **Test both exercises and solutions** to ensure expected files are accurate\n\nSee the `create-codeql-query-development-workshop` skill for complete workshop creation guidance.\n\n## Related Resources\n\n- **Basic TDD**: `codeql://prompts/ql-tdd-basic`\n- **AST Reference**: `codeql://languages/{language}/ast`\n- **Security Patterns**: `codeql://languages/{language}/security`\n- **Performance Guide**: `codeql://patterns/performance`\n- **Workshop Skill**: `.github/skills/create-codeql-query-development-workshop/SKILL.md`\n- **Tools Validation**: `.github/skills/validate-ql-mcp-server-tools-queries/SKILL.md`\n';
|
|
64272
|
+
var ql_tdd_advanced_prompt_default = '---\nagent: agent\n---\n\n# Advanced Test-Driven CodeQL Query Development\n\nThis advanced guide builds on the basic TDD methodology with powerful MCP server tools for deeper code analysis. Use this when developing complex queries that require understanding AST structure, control flow, and call relationships.\n\nFor basic TDD workflow, see: `codeql://prompts/ql-tdd-basic`\n\n## When to Use This Advanced Guide\n\n- **Complex AST patterns**: When you need to understand how CodeQL represents specific language constructs\n- **Control flow queries**: When analyzing program flow, branching, or loop structures\n- **Call graph analysis**: When tracing function calls or method invocations\n- **Iterative refinement**: When debugging queries that don\'t produce expected results\n- **Performance optimization**: When understanding query evaluation patterns\n\n## Core Advanced Tools\n\n### 1. AST/CFG Visualization with #codeql_query_run\n\nUse the bundled tools queries to visualize code structure:\n\n```typescript\n// Generate Abstract Syntax Tree for test code\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java", // or "javascript", "python", "cpp", etc.\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output.txt"\n}\n\n// Generate Control Flow Graph\ncodeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg-output.txt"\n}\n\n// Analyze outbound calls from a function\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "myFunction",\n format: "sarif-latest"\n}\n\n// Analyze inbound calls to a function\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "targetMethod",\n format: "sarif-latest"\n}\n```\n\n**Critical**: Always verify that tools queries return **non-empty output** with actual nodes/edges, not just headers.\n\n### 2. Quick Evaluation with #quick_evaluate\n\nUse #quick_evaluate for rapid iteration on specific predicates or classes:\n\n```typescript\n// First, find the position of a predicate\nfind_predicate_position: {\n file: "/path/to/Query.ql",\n name: "isVulnerableSink"\n}\n\n// Then evaluate just that predicate\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "isVulnerableSink",\n output_path: "/tmp/quickeval.bqrs"\n}\n\n// Or evaluate a specific class\n// NOTE: find_class_position finds `class` definitions only, not `module` definitions.\n// Use search_ql_code to find module definitions or other patterns across QL files.\nfind_class_position: {\n file: "/path/to/Query.ql",\n name: "ThrowingMethodCall"\n}\n\nquick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "ThrowingMethodCall"\n}\n```\n\n### 3. LSP-Powered Code Navigation\n\nUse the LSP tools for real-time code exploration during query development:\n\n```typescript\n// Discover available types after `import javascript`\ncodeql_lsp_completion: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line with `from` clause\n character: 5, // 0-based column position\n workspace_uri: "/path/to/pack-root" // REQUIRED: directory containing codeql-pack.yml\n}\n\n// Navigate to a class definition to see its predicates\ncodeql_lsp_definition: {\n file_path: "/path/to/Query.ql",\n line: 5, // 0-based line containing the class name\n character: 10, // 0-based column on the class name\n workspace_uri: "/path/to/pack-root"\n}\n\n// Find all usages of a predicate across the pack\ncodeql_lsp_references: {\n file_path: "/path/to/Query.ql",\n line: 8,\n character: 5,\n workspace_uri: "/path/to/pack-root"\n}\n```\n\n**Important LSP tool notes**:\n\n- `workspace_uri` must be a **plain directory path** (not a `file://` URI) pointing to the pack root containing `codeql-pack.yml`\n- All LSP tools use **0-based** line/character positions\n- #find_predicate_position and #find_class_position return **1-based** positions \u2014 subtract 1 before passing to LSP tools\n- Run #codeql_pack_install before using LSP tools \u2014 they require resolved dependencies\n- Request completions **after a dot** (e.g., `pw.`) to see all member predicates with full documentation\n\n### 4. Query File Discovery with #find_codeql_query_files\n\nUse this tool frequently to understand query dependencies and test structure:\n\n```typescript\nfind_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n}\n// Returns: query file, test directory, test files, metadata, dependencies\n```\n\n## Advanced TDD Workflow\n\n### Phase 0: Test Environment Setup (Critical for Java)\n\nFor Java tests that depend on external libraries (JUnit, etc.), create an `options` file in each test directory:\n\n```text\n//semmle-extractor-options: --javac-args -cp ${testdir}/../../stubs/junit-4.13:${testdir}/../../stubs/junit-jupiter-api-5.2.0\n```\n\n**Key points**:\n\n- `${testdir}` is relative to the test directory containing the `options` file\n- Use `:` (colon) to separate multiple classpath entries\n- Stub files must contain minimal class/interface definitions for compilation\n\n### Phase 1: Deep Code Analysis\n\nBefore writing any query logic:\n\n1. **Extract test database**:\n\n ```typescript\n codeql_test_extract: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n2. **Generate and study the AST**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast.txt"\n }\n ```\n\n3. **Identify key AST classes and predicates** from the output:\n - Note the class names (e.g., `MethodCall`, `TryStmt`, `LambdaExpr`)\n - Note parent-child relationships\n - Identify which nodes correspond to your test cases\n\n4. **Generate CFG if analyzing control flow**:\n\n ```typescript\n codeql_query_run: {\n queryName: "PrintCFG",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/cfg.txt"\n }\n ```\n\n### Phase 2: Iterative Predicate Development\n\nInstead of writing the full query at once:\n\n1. **Start with a single class or predicate**:\n\n ```ql\n class MyPattern extends MethodCall {\n MyPattern() {\n this.getMethod().hasName("targetMethod")\n }\n }\n ```\n\n2. **Use #quick_evaluate to test it**:\n\n ```typescript\n quick_evaluate: {\n file: "/path/to/Query.ql",\n db: "/path/to/test.testproj",\n symbol: "MyPattern"\n }\n ```\n\n3. **Refine based on results**:\n - Too many results? Add constraints\n - Too few results? Relax constraints\n - Wrong results? Study AST output again\n\n4. **Repeat for each component** before combining\n\n### Phase 3: Incremental Query Assembly\n\n1. **Combine validated predicates** into the main query\n2. **Run full tests** after each combination:\n\n ```typescript\n codeql_test_run: {\n testPath: "/path/to/test/QueryTest",\n searchPath: "/path/to/pack"\n }\n ```\n\n3. **Use #find_codeql_query_files** to track all related files:\n\n ```typescript\n find_codeql_query_files: {\n queryPath: \'/path/to/Query.ql\';\n }\n ```\n\n## Common Advanced Patterns\n\n### Pattern: Understanding Nested Structures\n\nWhen your query involves nested constructs (e.g., lambdas inside method calls):\n\n```ql\n// First, find the outer construct\nclass OuterPattern extends MethodCall {\n OuterPattern() {\n this.getMethod().hasName("assertThrows")\n }\n\n // Navigate to inner construct\n Expr getLambdaBody() {\n exists(LambdaExpr le |\n le = this.getAChildExpr() and\n result = le.getExprBody()\n )\n }\n}\n```\n\nUse `PrintAST` to understand the parent-child relationships.\n\n### Pattern: Control Flow Dependencies\n\nWhen your query needs to understand execution order:\n\n```ql\n// Use CFG to understand which statements precede others\npredicate precedesInBlock(Stmt s1, Stmt s2) {\n exists(BasicBlock bb |\n s1.getBasicBlock() = bb and\n s2.getBasicBlock() = bb and\n s1.getLocation().getStartLine() < s2.getLocation().getStartLine()\n )\n}\n```\n\nUse `PrintCFG` to verify the control flow structure.\n\n### Pattern: Call Chain Analysis\n\nWhen tracing calls through multiple functions:\n\n```typescript\n// First, understand the call graph from your entry point\ncodeql_query_run: {\n queryName: "CallGraphFrom",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n sourceFunction: "entryPoint"\n}\n\n// Then trace back from your target\ncodeql_query_run: {\n queryName: "CallGraphTo",\n queryLanguage: "java",\n database: "/path/to/test.testproj",\n targetFunction: "sensitiveOperation"\n}\n```\n\n## Debugging Tips\n\n### When Results Are Empty\n\n1. **Check AST first**: Run `PrintAST` to verify the code structure matches expectations\n2. **Simplify the query**: Remove constraints one by one using #quick_evaluate\n3. **Check enclosing callables**: Lambda bodies may have different `getEnclosingCallable()` than expected\n4. **Verify test database extraction**: Ensure the `.testproj` directory was created successfully\n\n### When Results Are Incorrect\n\n1. **Quick evaluate individual predicates**: Isolate which part is wrong\n2. **Compare with AST output**: Verify your understanding of the structure\n3. **Check for missing cases**: Your pattern may not cover all code variations\n\n### When Compilation Fails with "override" Error\n\nIf you see `annotation \'override\' missing on predicate`, you\'ve accidentally created a predicate with the same name as one in the parent class. **Rename your predicate** to avoid the conflict:\n\n```ql\n// BAD: Method already has getAThrownExceptionType()\nclass ThrowingMethod extends Method {\n RefType getAThrownExceptionType() { ... } // Error!\n}\n\n// GOOD: Use a distinct name\nclass ThrowingMethod extends Method {\n RefType getDeclaredExceptionType() { ... } // Works\n}\n```\n\n### When Query Is Slow\n\n1. **Enable evaluator logs**:\n\n ```typescript\n codeql_query_run: {\n query: "/path/to/Query.ql",\n database: "/path/to/db",\n "evaluator-log": "/path/to/log.json",\n "evaluator-log-level": 5\n }\n ```\n\n2. **Profile from evaluator logs** (primary tool \u2014 returns compact JSON metrics plus a line-indexed detail file for targeted `read_file` access to RA operations and tuple progressions):\n\n ```typescript\n profile_codeql_query_from_logs: {\n evaluatorLog: \'/path/to/log.json\';\n }\n ```\n\n## Checklist for Complex Queries\n\n### Before Starting\n\n- [ ] Test database extracted successfully\n- [ ] `PrintAST` output reviewed and understood\n- [ ] Key AST classes identified\n- [ ] Test cases cover positive, negative, and edge cases\n\n### During Development\n\n- [ ] Each predicate/class tested with #quick_evaluate\n- [ ] #find_codeql_query_files used to track dependencies\n- [ ] CFG consulted for control flow patterns\n- [ ] Call graphs generated for cross-function analysis\n\n### After Each Change\n\n- [ ] Query compiles with #codeql_query_compile\n- [ ] Quick evaluation shows expected results\n- [ ] Full tests pass with #codeql_test_run\n- [ ] No duplicate or missing results\n\n### Final Validation\n\n- [ ] All test cases pass\n- [ ] No false positives in results\n- [ ] No false negatives (all expected cases caught)\n- [ ] Query formatted with #codeql_query_format\n- [ ] Performance acceptable (check with #profile_codeql_query_from_logs)\n\n## Test Acceptance Workflow\n\nWhen your query produces correct results but differs from the `.expected` file:\n\n1. **Review the `.actual` file** to verify results are correct\n2. **Accept the results** to update the expected baseline:\n\n ```typescript\n codeql_test_accept: {\n tests: [\'/path/to/test/QueryTest\'];\n }\n ```\n\n3. **Re-run tests** to confirm they now pass\n\n**Warning**: Only accept results after careful review. Don\'t blindly accept to make tests pass.\n\n## Tool Reference\n\n| Tool | Purpose | When to Use |\n| ------------------------------- | --------------------------------- | ------------------------------- |\n| #codeql_query_run (PrintAST) | Visualize AST structure | Start of development, debugging |\n| #codeql_query_run (PrintCFG) | Visualize control flow | Control flow queries |\n| #codeql_query_run (CallGraph\\*) | Analyze call relationships | Cross-function queries |\n| #codeql_bqrs_interpret | Convert BQRS to readable format | After running graph queries |\n| #quick_evaluate | Test individual predicates | Iterative development |\n| #find_predicate_position | Locate predicate for quickeval | Before quick_evaluate |\n| #find_class_position | Locate class for quickeval | Before quick_evaluate |\n| #find_codeql_query_files | Discover related files | Planning, tracking changes |\n| #search_ql_code | Search QL files for patterns | Finding classes, predicates |\n| #codeql_resolve_files | Find QL files by name/extension | Discovering library pack files |\n| #codeql_test_accept | Accept actual results as expected | After verifying correct output |\n| #profile_codeql_query_from_logs | Performance analysis | Optimization |\n\n## Interpreting Graph Query Results\n\nWhen running `PrintAST` or `PrintCFG`, the results are stored in BQRS format. To convert to readable text:\n\n```typescript\n// After codeql_query_run produces results.bqrs\ncodeql_bqrs_interpret: {\n file: "/path/to/results.bqrs",\n format: "graphtext",\n output: "/path/to/output.txt",\n t: ["kind=graph", "id=java/tools/print-ast"]\n}\n```\n\n**Note**: The output may create a directory structure (e.g., `output.txt/java/tools/print-ast.txt`) rather than a single file.\n\n## Example: Workshop Development\n\nWhen creating CodeQL workshops, this advanced methodology is essential:\n\n1. **Analyze production query** with #find_codeql_query_files\n2. **Generate AST/CFG** for workshop test code\n3. **Decompose query** into stages, validating each with #quick_evaluate\n4. **Create exercises** with scaffolding based on AST understanding\n5. **Validate solutions** ensure each stage produces correct results\n\n### Exercise Design Tips\n\nWhen creating exercise stubs from solutions:\n\n```ql\n// Use none() as placeholder in characteristic predicates\nclass MyPattern extends MethodCall {\n MyPattern() {\n // TODO: Implement - check for methods named "targetMethod"\n // Hint: Use this.getMethod().hasName(...)\n none()\n }\n}\n```\n\n- **Include TODO comments** with specific hints\n- **Reference AST class names** students should look for\n- **Build incrementally** - each exercise should build on the previous\n- **Test both exercises and solutions** to ensure expected files are accurate\n\nSee the `create-codeql-query-development-workshop` skill for complete workshop creation guidance.\n\n## Related Resources\n\n- **Basic TDD**: `codeql://prompts/ql-tdd-basic`\n- **AST Reference**: `codeql://languages/{language}/ast`\n- **Security Patterns**: `codeql://languages/{language}/security`\n- **Performance Guide**: `codeql://patterns/performance`\n- **Workshop Skill**: `.github/skills/create-codeql-query-development-workshop/SKILL.md`\n- **Tools Validation**: `.github/skills/validate-ql-mcp-server-tools-queries/SKILL.md`\n';
|
|
63456
64273
|
|
|
63457
64274
|
// src/prompts/ql-tdd-basic.prompt.md
|
|
63458
|
-
var ql_tdd_basic_prompt_default = '---\nagent: agent\n---\n\n# Test-Driven CodeQL Query Development Checklist\n\nUse this checklist to guide test-driven development of CodeQL queries. Follow the TDD cycle: write tests first, implement query logic, and iterate until tests pass.\n\nFor advanced techniques including AST/CFG visualization, see: `codeql://prompts/ql-tdd-advanced`\nFor detailed guidance, reference the MCP resource: `codeql://learning/test-driven-development`\n\n## TDD Workflow Checklist\n\n### Phase 1: Project Setup\n\n- [ ] **Create Query Structure**\n - Tool: #create_codeql_query\n - Specify: basePath, queryName, language, description (optional)\n - Creates: src/QueryName/QueryName.ql, test/QueryName/QueryName.qlref, test/QueryName/test-code-file\n - The .qlref file will contain the relative path: `QueryName/QueryName.ql`\n - Verify: directory structure follows CodeQL conventions with intermediate directories\n\n- [ ] **Install Pack Dependencies**\n - Tool: #codeql_pack_install\n - Install src pack dependencies\n - Install test pack dependencies\n - Verify: imports resolve without errors\n\n### Phase 2: Test Design (Red Phase)\n\n- [ ] **Design Test Cases**\n - Create positive test cases (should match)\n - Create negative test cases (should not match)\n - Create edge case tests\n - Document expected behavior in comments\n\n- [ ] **Define Expected Results**\n - Create .expected file with anticipated matches\n - Specify exact match locations (file, line, column)\n - Include expected alert messages\n\n- [ ] **Extract Test Database**\n - Tool: #codeql_test_extract\n - Extract database from test code\n - Verify: .testproj directory created\n\n### Phase 3: Analysis and Understanding\n\n- [ ] **Analyze Test Code AST**\n - Tool: #codeql_query_run with queryName: "PrintAST"\n - Use format: "graphtext" for @kind graph queries\n - Review AST structure and identify relevant classes\n\n- [ ] **Explore Available Classes and Predicates**\n - Tool: #codeql_lsp_completion at the position in the `from` clause\n - Parameters: `file_path`, `line` (0-based), `character` (0-based)\n - Set `workspace_uri` to the pack root directory (containing `codeql-pack.yml`)\n - Request completions after a dot (e.g., `pw.`) to see member predicates with docs\n - Tip: Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Navigate to Type Definitions**\n - Tool: #codeql_lsp_definition on a class or predicate name\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri`\n - Returns file URI and line range \u2014 even into library pack files\n - Read the definition source to understand available member predicates\n - Tool: #codeql_lsp_references to find usage examples across the pack\n\n For the full iterative LSP workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n\n- [ ] **Reference Language Documentation**\n - Resource: `codeql://languages/{language}/ast`\n - Resource: `codeql://languages/{language}/security` (if applicable)\n - Identify AST classes and predicates needed\n\n### Phase 4: Implementation (Green Phase)\n\n- [ ] **Write Query Metadata**\n - Add @name annotation\n - Add @description annotation\n - Add @kind annotation (problem, path-problem, graph, etc.)\n - Add @id and other required metadata\n\n- [ ] **Implement Query Logic**\n - Import required libraries\n - Define necessary classes (if any)\n - Define helper predicates\n - Implement main query clause\n\n- [ ] **Compile Query**\n - Tool: #codeql_query_compile\n - Fix any compilation errors\n - Verify: query compiles successfully\n\n- [ ] **Run Tests**\n - Tool: #codeql_test_run\n - Compare actual vs expected results\n - If tests fail: adjust query logic and recompile\n - If tests pass: proceed to validation\n\n### Phase 5: Validation and Acceptance\n\n- [ ] **Verify Test Results**\n - Review all test matches\n - Confirm no false positives\n - Confirm no false negatives\n - Check edge cases behave correctly\n\n- [ ] **Accept Test Results** (only when correct)\n - Tool: #codeql_test_accept\n - Update .expected files\n - Commit accepted results\n\n### Phase 6: Refactoring and Enhancement\n\n- [ ] **Refactor Query**\n - Improve code clarity\n - Extract common logic to predicates\n - Add code comments and documentation\n - Tool: #codeql_query_format for consistent formatting\n\n- [ ] **Optimize Performance** (if needed)\n - Run with evaluator-log enabled\n - Tool: #
|
|
64275
|
+
var ql_tdd_basic_prompt_default = '---\nagent: agent\n---\n\n# Test-Driven CodeQL Query Development Checklist\n\nUse this checklist to guide test-driven development of CodeQL queries. Follow the TDD cycle: write tests first, implement query logic, and iterate until tests pass.\n\nFor advanced techniques including AST/CFG visualization, see: `codeql://prompts/ql-tdd-advanced`\nFor detailed guidance, reference the MCP resource: `codeql://learning/test-driven-development`\n\n## TDD Workflow Checklist\n\n### Phase 1: Project Setup\n\n- [ ] **Create Query Structure**\n - Tool: #create_codeql_query\n - Specify: basePath, queryName, language, description (optional)\n - Creates: src/QueryName/QueryName.ql, test/QueryName/QueryName.qlref, test/QueryName/test-code-file\n - The .qlref file will contain the relative path: `QueryName/QueryName.ql`\n - Verify: directory structure follows CodeQL conventions with intermediate directories\n\n- [ ] **Install Pack Dependencies**\n - Tool: #codeql_pack_install\n - Install src pack dependencies\n - Install test pack dependencies\n - Verify: imports resolve without errors\n\n### Phase 2: Test Design (Red Phase)\n\n- [ ] **Design Test Cases**\n - Create positive test cases (should match)\n - Create negative test cases (should not match)\n - Create edge case tests\n - Document expected behavior in comments\n\n- [ ] **Define Expected Results**\n - Create .expected file with anticipated matches\n - Specify exact match locations (file, line, column)\n - Include expected alert messages\n\n- [ ] **Extract Test Database**\n - Tool: #codeql_test_extract\n - Extract database from test code\n - Verify: .testproj directory created\n\n### Phase 3: Analysis and Understanding\n\n- [ ] **Analyze Test Code AST**\n - Tool: #codeql_query_run with queryName: "PrintAST"\n - Use format: "graphtext" for @kind graph queries\n - Review AST structure and identify relevant classes\n\n- [ ] **Explore Available Classes and Predicates**\n - Tool: #codeql_lsp_completion at the position in the `from` clause\n - Parameters: `file_path`, `line` (0-based), `character` (0-based)\n - Set `workspace_uri` to the pack root directory (containing `codeql-pack.yml`)\n - Request completions after a dot (e.g., `pw.`) to see member predicates with docs\n - Tip: Run #codeql_pack_install first \u2014 LSP tools require resolved dependencies\n\n- [ ] **Navigate to Type Definitions**\n - Tool: #codeql_lsp_definition on a class or predicate name\n - Parameters: `file_path`, `line` (0-based), `character` (0-based), `workspace_uri`\n - Returns file URI and line range \u2014 even into library pack files\n - Read the definition source to understand available member predicates\n - Tool: #codeql_lsp_references to find usage examples across the pack\n\n For the full iterative LSP workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n\n- [ ] **Reference Language Documentation**\n - Resource: `codeql://languages/{language}/ast`\n - Resource: `codeql://languages/{language}/security` (if applicable)\n - Identify AST classes and predicates needed\n\n### Phase 4: Implementation (Green Phase)\n\n- [ ] **Write Query Metadata**\n - Add @name annotation\n - Add @description annotation\n - Add @kind annotation (problem, path-problem, graph, etc.)\n - Add @id and other required metadata\n\n- [ ] **Implement Query Logic**\n - Import required libraries\n - Define necessary classes (if any)\n - Define helper predicates\n - Implement main query clause\n\n- [ ] **Compile Query**\n - Tool: #codeql_query_compile\n - Fix any compilation errors\n - Verify: query compiles successfully\n\n- [ ] **Run Tests**\n - Tool: #codeql_test_run\n - Compare actual vs expected results\n - If tests fail: adjust query logic and recompile\n - If tests pass: proceed to validation\n\n### Phase 5: Validation and Acceptance\n\n- [ ] **Verify Test Results**\n - Review all test matches\n - Confirm no false positives\n - Confirm no false negatives\n - Check edge cases behave correctly\n\n- [ ] **Accept Test Results** (only when correct)\n - Tool: #codeql_test_accept\n - Update .expected files\n - Commit accepted results\n\n### Phase 6: Refactoring and Enhancement\n\n- [ ] **Refactor Query**\n - Improve code clarity\n - Extract common logic to predicates\n - Add code comments and documentation\n - Tool: #codeql_query_format for consistent formatting\n\n- [ ] **Optimize Performance** (if needed)\n - Run with evaluator-log enabled\n - Tool: #profile_codeql_query_from_logs\n - Resource: `codeql://patterns/performance`\n - Optimize expensive operations\n\n- [ ] **Generate Documentation**\n - Tool: #codeql_generate_query_help\n - Review and enhance QLDoc comments\n - Document query purpose and limitations\n\n### Phase 7: Additional Testing\n\n- [ ] **Add More Test Cases**\n - Identify additional scenarios\n - Add tests for new edge cases\n - Extract new test databases\n - Run expanded test suite\n\n- [ ] **Validate Against Real Code** (optional)\n - Tool: #codeql_database_create for real codebase\n - Tool: #codeql_query_run against real database\n - Review results for false positives/negatives\n\n## Quick Command Reference\n\n### Essential Tools\n\n```typescript\n// Create query structure\ncreate_codeql_query: {\n basePath: "/path/to/query/base",\n queryName: "MySecurityQuery",\n language: "javascript",\n description: "Detects security vulnerability X"\n}\n\n// Install dependencies\ncodeql_pack_install: {\n packPath: "/path/to/pack"\n}\n\n// Extract test database\ncodeql_test_extract: {\n testPath: "/path/to/test/QueryName",\n searchPath: "/path/to/base"\n}\n\n// Analyze AST (for @kind graph queries)\ncodeql_query_run: {\n queryName: "PrintAST",\n queryLanguage: "javascript",\n database: "/path/to/test.testproj",\n format: "graphtext",\n interpretedOutput: "/path/to/ast-output/"\n}\n\n// Compile query\ncodeql_query_compile: {\n query: "/path/to/Query.ql",\n searchPath: "/path/to/base",\n checkOnly: true\n}\n\n// Run tests\ncodeql_test_run: {\n testPath: "/path/to/test/Query.qlref",\n searchPath: "/path/to/base"\n}\n\n// Accept results\ncodeql_test_accept: {\n testPath: "/path/to/test/Query",\n searchPath: "/path/to/base"\n}\n```\n\n## TDD Principles to Remember\n\n1. **Red \u2192 Green \u2192 Refactor**: Always start with failing tests\n2. **Test First**: Write tests before implementation\n3. **Small Steps**: Make minimal changes to pass each test\n4. **Frequent Testing**: Run tests after each change\n5. **One Concept Per Test**: Each test should verify one behavior\n6. **Keep Tests Simple**: Test code should be easy to understand\n7. **Refactor Confidently**: Tests enable safe refactoring\n\n## Common Pitfalls to Avoid\n\n- \u274C Writing query before tests\n- \u274C Accepting test results without verification\n- \u274C Skipping compilation step\n- \u274C Not using PrintAST to understand test code\n- \u274C Not using #codeql_lsp_completion to discover available types\n- \u274C Not setting `workspace_uri` when using LSP tools (completions will be empty)\n- \u274C Creating tests that are too complex\n- \u274C Ignoring false positives in results\n- \u274C Not refactoring after tests pass\n\n## Success Criteria\n\nYour query development is complete when:\n\n- \u2705 All tests pass\n- \u2705 No false positives in test results\n- \u2705 No false negatives (all expected cases caught)\n- \u2705 Query compiles without errors or warnings\n- \u2705 Code is well-documented with QLDoc comments\n- \u2705 Performance is acceptable\n- \u2705 Edge cases are covered by tests\n- \u2705 Query follows CodeQL best practices\n\n## Next Steps After Completion\n\n1. **Integration Testing**: Test against real codebases\n2. **Peer Review**: Have another developer review the query\n3. **Documentation**: Update project documentation\n4. **Regression Testing**: Add to CI/CD pipeline\n5. **Monitor Performance**: Track query performance over time\n';
|
|
63459
64276
|
|
|
63460
64277
|
// src/prompts/run-query-and-summarize-false-positives.prompt.md
|
|
63461
64278
|
var run_query_and_summarize_false_positives_prompt_default = '---\nagent: agent\n---\n\n# Run a query and describe its false positives\n\n## Task\n\nHelp a developer discover what kinds of false positives are produced by their current CodeQL query, and which of those false positive cases are most common.\n\n### Task steps:\n\n1. Read the provided CodeQL query to understand what patterns it is designed to detect.\n2. Discover the results of this query on a real database, by:\n - Running the tool #list_query_run_results to find existing runs for this query\n - If no existing runs are found, run the query on a relevant database using #codeql_query_run tool\n3. Analyze and group the results into what appear to be similar types of results. This may mean:\n - Grouping results in the same file\n - Grouping results that reference the same elements\n - Grouping results with similar messages\n4. For each group, explore the actual code for a sample of alerts in that group, using the #read_database_source tool to triage the results and determine which groups appear to be false positives\n5. For each false positive case discovered in this exploration, group them into categories of similar root causes. For example, a query might not properly account for unreachable code, or there may be a commonly used library that violates the query\'s assumptions but is actually safe.\n6. Explain these results to the user in order of most common to least common, so they can understand where their query may need improvement to reduce false positives.\n\n## Input Context\n\nYou will be provided with:\n\n- **Query Path**: The path to the CodeQL query\n\n## Analysis Guidelines\n\n### Exploring code paths\n\nThe tool #read_database_source can be used to read the code of a particular finding. A good strategy to explore the code paths of a finding is:\n\n1. Read in the immediate context of the violation.\n - Some queries may depend on later context (e.g., an "unused variable" may only be used after its declaration)\n - Some queries may depend on earlier context (e.g., "mutex not initialized" requires observing code that ran before the violation)\n - Some queries may rely on exploring other function calls.\n2. Read the interprocedural context of the violation.\n - If understanding a violation requires checking other source locations, read the beginning of the file to find what it imports, and then read those imported files to find the relevant code.\n - Selectively scan interprocedural paths. A false positive that requires tremendous code exploration to verify is less problematic than a false positive that only requires checking a small amount of code to verify.\n3. Stop early.\n - Grouping the potential false positive cases is more important than exhaustively verifying every single finding.\n - A common false positive likely introduces some false positives that are very hard to verify, so it is usually better to focus on simple cases first.\n - Truly hard-to-verify false positive cases are often in code that users don\'t expect to be conducive to static analysis, and query authors often don\'t expect their queries to work well in those cases.\n - Suggest a chainsaw approach rather than a scalpel - if a result may be a false positive, identify some simple heuristics to eliminate all such complex cases, even if such a heuristic could introduce false negatives.\n\n### What Makes a Result Likely to be a False Positive?\n\n1. **Pattern Mismatches**\n - Query pattern doesn\'t accurately match the actual code behavior\n - Missing context that would show the code is safe\n - Overly broad query logic catching benign variations\n\n2. **Safe Code Patterns**\n - Code includes proper validation before the flagged operation\n - Results in test code, example code, or mock implementations\n - Variable/function names suggesting test/example context (e.g., `testFunc`, `exampleVar`, `mockData`)\n - Defensive programming patterns present but not recognized by query\n\n3. **Context Indicators**\n - File paths suggesting test/example files (e.g., `test/`, `examples/`, `mock/`)\n - Comments indicating intentional patterns or safe usage\n - Framework-specific patterns that are safe in context\n\n4. **Technical Factors**\n - Type mismatches that make the vulnerability impossible\n - Control flow that prevents exploitation\n - Data flow interrupted by sanitization not captured in query\n\n### Important Constraints\n\n- **Be objective**: Don\'t be influenced by variable/function naming suggesting importance (e.g., "prodOnly" vs "test")\n- **Require evidence**: Base conclusions on actual code patterns, not assumptions\n- **Mark uncertainty**: Use lower confidence scores when code snippets are missing\n- **Avoid false confidence**: If you cannot determine FP status, mark confidence as low\n\n## Output Format\n\nReturn a JSON array of false-positive _groups_, ordered by the estimated prevalence or importance of the false-positive pattern (highest first):\n\n```json\n[\n {\n "groupLabel": "Test and example code with safe validation",\n "patternSummary": "Results where the flagged operation occurs in test/example files and is always preceded by input validation.",\n "resultCount": 23,\n "estimatedFpProportion": 0.9,\n "confidence": 0.85,\n "commonRootCause": "The query does not recognize common test/example locations or custom validation helpers as making the pattern safe.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 42,\n "ruleId": "query-id",\n "message": { "text": "original result message" },\n "locations": []\n }\n ],\n "reasoning": "Based on manual inspection of several alerts in this group: (1) results are consistently located under \'test/\' or \'examples/\' directories, (2) there is clear validation before the flagged operation, and (3) the query does not model the custom validation helpers used in these files."\n }\n]\n```\n\n### Field Descriptions\n\n- **groupLabel**: Short human-readable name for the false-positive category.\n- **patternSummary**: One-sentence description of the common pattern shared by results in this group.\n- **resultCount**: Number of SARIF results that belong to this group.\n- **estimatedFpProportion**: Estimated proportion of results in this group that are false positives (0.0\u20131.0).\n- **confidence**: Confidence in the group-level assessment (see guidelines below).\n- **commonRootCause**: Why the query produces false positives for this pattern.\n- **sampleResults**: A small representative sample of results illustrating the pattern.\n- **reasoning**: Detailed explanation of how the FP determination was made.\n\n### Confidence Score Guidelines\n\n- **0.8-1.0**: Strong evidence of FP (e.g., test code with clear safety patterns)\n- **0.6-0.8**: Good evidence of FP (e.g., defensive patterns present)\n- **0.4-0.6**: Moderate evidence of FP (e.g., context suggests safety but not conclusive)\n- **0.2-0.4**: Weak evidence of FP (e.g., minor indicators, missing code snippets)\n- **0.0-0.2**: Minimal evidence (uncertain, need more information)\n\n## Examples\n\n### High-Confidence FP Group Example\n\n```json\n{\n "groupLabel": "Sanitised inputs in test harnesses",\n "patternSummary": "Results in test files where sanitizeInput() is called before the database query.",\n "resultCount": 15,\n "estimatedFpProportion": 0.95,\n "confidence": 0.9,\n "commonRootCause": "Query does not model sanitizeInput() as a sanitizer.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 7,\n "ruleId": "js/sql-injection",\n "message": { "text": "Potential SQL injection" },\n "locations": []\n }\n ],\n "reasoning": "False positive group: (1) File paths like \'test/unit/database-mock.test.js\' indicate test code, (2) Query doesn\'t recognize that \'sanitizeInput()\' is called before database query, (3) All 15 results share this pattern."\n}\n```\n\n### Low-Confidence FP Group Example\n\n```json\n{\n "groupLabel": "File utility handlers with unclear validation",\n "patternSummary": "Results in src/utils/ files where path validation may or may not be present.",\n "resultCount": 4,\n "estimatedFpProportion": 0.5,\n "confidence": 0.3,\n "commonRootCause": "Unclear whether custom path validation is sufficient.",\n "sampleResults": [\n {\n "sourceFile": "results-1.sarif",\n "resultIndex": 22,\n "ruleId": "js/path-injection",\n "message": { "text": "Potential path traversal" },\n "locations": []\n }\n ],\n "reasoning": "Possibly false positive: (1) No code snippets available in SARIF, (2) File path \'src/utils/fileHandler.js\' doesn\'t indicate test code, (3) Cannot verify if proper path validation exists. Low confidence due to missing context."\n}\n```\n\n## Processing Instructions\n\n1. **Review SARIF results** and group them by common patterns\n2. **Analyze available context** (code snippets, file paths, messages) for each group\n3. **Compare against query logic** to understand what pattern was detected\n4. **Identify FP indicators** based on guidelines above\n5. **Assign group-level confidence scores** reflecting evidence strength\n6. **Write clear reasoning** for each group explaining the assessment\n7. **Sort groups** by estimated prevalence / importance (descending)\n\n## Important Notes\n\n- A result should belong to at most one FP group\n- When in doubt, prefer lower confidence scores\n- Missing code snippets should always reduce confidence\n- Test/example code is more likely to be FP but not always\n- Focus on technical evidence, not code naming conventions\n';
|
|
@@ -63467,7 +64284,7 @@ var sarif_rank_false_positives_prompt_default = '---\nagent: agent\n---\n\n# Eva
|
|
|
63467
64284
|
var sarif_rank_true_positives_prompt_default = '---\nagent: agent\n---\n\n# Evaluate SARIF Results for True Positives\n\n## Task\n\nAnalyze SARIF results from a CodeQL query and identify the most likely **True Positives (TPs)** - results that correctly identify real security vulnerabilities or code quality issues.\n\n## Input Context\n\nYou will be provided with:\n\n- **Query ID**: The CodeQL query/rule identifier\n- **Query Name**: Human-readable name of the query\n- **Query Content**: Full CodeQL query implementation\n- **SARIF Results**: Array of results to analyze\n- **Code Snippets**: When available, code snippets from SARIF physical locations\n\n## Analysis Guidelines\n\n### What Makes a Result Likely to be a True Positive?\n\n1. **Pattern Matches**\n - Query pattern accurately identifies the problematic code behavior\n - Result shows clear evidence of the vulnerability or issue\n - Code matches the exact pattern the query was designed to detect\n\n2. **Vulnerable Code Patterns**\n - User input flows to dangerous sink without proper sanitization\n - Missing security checks or validation\n - Incorrect use of security-sensitive APIs\n - Clear violation of security best practices\n\n3. **Production Code Context**\n - File paths suggesting production code (e.g., `src/`, `lib/`, `app/`)\n - NOT in test/example directories\n - Function/variable names suggesting real business logic\n - Code appears to be part of actual application functionality\n\n4. **Technical Factors**\n - Data flow from untrusted source to dangerous operation\n - Missing or insufficient sanitization\n - Exploitable control flow\n - Real security or quality implications\n\n### Important Constraints\n\n- **Be objective**: Don\'t be influenced by variable/function naming suggesting importance\n- **Require evidence**: Base conclusions on actual vulnerability patterns, not assumptions\n- **Mark uncertainty**: Use lower confidence scores when code snippets are missing\n- **Avoid false confidence**: If you cannot determine TP status, mark confidence as low\n- **Consider false positives**: Be skeptical - real vulnerabilities often have subtle mitigations\n\n### When Code Snippets Are Missing\n\nIf SARIF results lack `physicalLocation.region.snippet` or `contextRegion`:\n\n- **Lower confidence scores** (typically 0.3-0.5 instead of 0.6-0.9)\n- **Note the limitation** in reasoning\n- **Rely more on**:\n - Result message text\n - File path analysis\n - Query logic understanding\n\n## Output Format\n\nReturn a JSON array of ranked results, ordered by TP likelihood (highest first):\n\n```json\n[\n {\n "ruleId": "query-id",\n "message": { "text": "original result message" },\n "locations": [...],\n "confidence": 0.85,\n "reasoning": "This appears to be a true positive because: (1) the file path \'src/api/user-controller.js\' indicates production code, (2) user input from request parameter flows directly to SQL query without sanitization, (3) no validation or prepared statement usage detected.",\n "sourceFile": "results-1.sarif",\n "resultIndex": 15\n }\n]\n```\n\n### Confidence Score Guidelines\n\n- **0.8-1.0**: Strong evidence of TP (e.g., clear vulnerability with exploit path)\n- **0.6-0.8**: Good evidence of TP (e.g., production code with problematic pattern)\n- **0.4-0.6**: Moderate evidence of TP (e.g., pattern matches but context unclear)\n- **0.2-0.4**: Weak evidence of TP (e.g., possible issue but missing context)\n- **0.0-0.2**: Minimal evidence (uncertain, need more information)\n\n## Examples\n\n### High-Confidence TP Example\n\n```json\n{\n "ruleId": "js/sql-injection",\n "message": { "text": "Unsanitized user input in SQL query" },\n "confidence": 0.9,\n "reasoning": "True positive: (1) File path \'src/controllers/UserController.js\' indicates production code, (2) User input from req.query.userId flows directly to SQL query string concatenation, (3) No prepared statements or sanitization visible in code snippet, (4) Classic SQL injection pattern. Confidence is 0.9 not 1.0 due to possibility of sanitization elsewhere in call chain."\n}\n```\n\n### Moderate-Confidence TP Example\n\n```json\n{\n "ruleId": "js/path-injection",\n "message": { "text": "Potential path traversal vulnerability" },\n "confidence": 0.6,\n "reasoning": "Likely true positive: (1) File path \'src/utils/fileHandler.js\' suggests production utility code, (2) User-controlled filename parameter used in fs.readFile(), (3) No visible path validation, but code snippet is limited. Moderate confidence due to incomplete context - may have validation in calling code."\n}\n```\n\n### Low-Confidence TP Example (Missing Snippets)\n\n```json\n{\n "ruleId": "java/unsafe-deserialization",\n "message": { "text": "Unsafe deserialization of user data" },\n "confidence": 0.4,\n "reasoning": "Possibly a true positive: (1) File path \'src/main/java/com/app/handlers/DataHandler.java\' indicates production code, (2) Message suggests unsafe deserialization pattern, (3) No code snippets available in SARIF to verify actual vulnerability or confirm absence of mitigations. Confidence is low due to missing context."\n}\n```\n\n## Processing Instructions\n\n1. **Review each SARIF result** in the provided array\n2. **Analyze available context** (code snippets, file paths, messages)\n3. **Compare against query logic** to understand what pattern was detected\n4. **Identify TP indicators** based on guidelines above\n5. **Look for counter-evidence** (mitigations, safe patterns) that would make it an FP\n6. **Assign confidence score** reflecting evidence strength\n7. **Write clear reasoning** explaining your assessment\n8. **Sort results** by confidence score (descending)\n9. **Return top N results** as requested (or all if N not specified)\n\n## Important Notes\n\n- A result should never appear in both FP and TP rankings\n- When in doubt, prefer lower confidence scores\n- Missing code snippets should always reduce confidence\n- Production code location increases TP likelihood but is not conclusive\n- Focus on technical vulnerability evidence, not code naming conventions\n- Consider that even production code can have intentional patterns that look vulnerable but are safe\n';
|
|
63468
64285
|
|
|
63469
64286
|
// src/prompts/tools-query-workflow.prompt.md
|
|
63470
|
-
var tools_query_workflow_prompt_default = '---\nagent: agent\n---\n\n# Using CodeQL Development MCP Server Tools Queries\n\nThis guide helps you use the built-in "tools" queries (`PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`) that ship with the CodeQL Development MCP Server to understand code structure before writing detection queries.\n\n## Why Use Tools Queries?\n\nTools queries provide essential insights into how CodeQL represents your source code:\n\n| Query | Purpose | Use When |\n| --------------- | ------------------------------------------------ | ----------------------------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree | Understanding code structure, finding AST nodes |\n| `PrintCFG` | Visualize Control Flow Graphs | Understanding execution paths, loop/branch flow |\n| `CallGraphFrom` | Find all functions called by a specific function | Tracing data flow through call chains |\n| `CallGraphTo` | Find all functions that call a specific function | Understanding function usage patterns |\n\n## Supported Languages\n\nTools queries are available for: `actions`, `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `swift`\n\n## Prerequisites\n\nBefore using tools queries, you need:\n\n1. **A CodeQL database** - Either create one or use an existing database\n2. **Source files to analyze** - The tools queries filter output to specific files\n\n## Workflow Checklist\n\n### Step 1: Identify or Create Database\n\n- [ ] **Option A: Use existing database**\n - Tool: #codeql_resolve_database\n - Verify database is valid and note the language\n\n- [ ] **Option B: Create new database**\n - Tool: #codeql_database_create\n - Parameters: `database`, `language`, `source-root`\n\n### Step 2: Run PrintAST Query\n\nThe PrintAST query outputs a hierarchical tree of AST nodes with labels.\n\n- [ ] **Execute PrintAST**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"javascript"`, `"python"`, `"cpp"`)\n - `sourceFiles`: Comma-separated file names to analyze (e.g., `"main.js,utils.js"`)\n - `format`: `"graphtext"` (for human-readable output)\n\n- [ ] **Verify output contains AST nodes**\n - Look for hierarchical structure with indentation\n - Confirm nodes have `semmle.label` with class names\n - Identify relevant AST classes for your query\n\n**Example AST output structure:**\n\n```text\nTopLevelFunction\n\u251C\u2500\u2500 FunctionDeclarationEntry\n\u251C\u2500\u2500 Block\n\u2502 \u251C\u2500\u2500 DeclStmt\n\u2502 \u2502 \u2514\u2500\u2500 LocalVariable\n\u2502 \u251C\u2500\u2500 ExprStmt\n\u2502 \u2502 \u2514\u2500\u2500 FunctionCall\n\u2502 \u2514\u2500\u2500 ReturnStmt\n```\n\n### Step 3: Run PrintCFG Query (if needed)\n\nThe PrintCFG query outputs control flow nodes and edges.\n\n- [ ] **Execute PrintCFG**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to analyze (e.g., `"processData"`)\n - `format`: `"graphtext"`\n\n- [ ] **Verify output contains nodes and edges**\n - Look for `nodes` section with CFG nodes\n - Look for `edges` section with `\u2192` arrows showing flow\n - Identify control flow patterns (loops, branches)\n\n**Example CFG output structure:**\n\n```text\nnodes\n| node | semmle.label |\n| ... | entry: processData |\n| ... | if (...) |\n| ... | return |\n\nedges\n| from | to | semmle.label |\n| ... | ... | \u2192 |\n```\n\n### Step 4: Run CallGraph Queries (if needed)\n\nCall graph queries help trace function relationships.\n\n- [ ] **Execute CallGraphFrom** (to find what a function calls)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphFrom"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to trace from (e.g., `"main"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Execute CallGraphTo** (to find what calls a function)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphTo"`\n - `queryLanguage`: Your language\n - `targetFunction`: Function name to find callers of (e.g., `"validate"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Verify call relationships**\n - Confirm results show caller \u2192 callee relationships\n - Note function locations for further analysis\n\n### Step 5: Apply Insights to Query Development\n\nUse the gathered information to inform your query:\n\n- [ ] **From PrintAST**: Identify which AST classes to use in your `from` clause\n- [ ] **From PrintCFG**: Understand execution paths for control-flow-sensitive queries\n- [ ] **From CallGraph**: Map data flow paths through function boundaries\n\n## Common Patterns\n\n### Pattern 1: Finding All Function Calls\n\n```text\n1. Run PrintAST on your source file\n2. Look for FunctionCall, MethodAccess, or similar nodes\n3. Note the parent/child relationships\n4. Use those AST classes in your query\n```\n\n### Pattern 2: Tracing Data Through Functions\n\n```text\n1. Run CallGraphFrom on your entry point function\n2. Identify which functions are called\n3. Run CallGraphTo on sink functions\n4. Map the complete path from source to sink\n```\n\n### Pattern 3: Understanding Loop Structures\n\n```text\n1. Run PrintAST to find loop constructs (ForStmt, WhileStmt, etc.)\n2. Run PrintCFG on the containing function\n3. Identify back edges that represent loop iteration\n4. Use CFG analysis for loop-sensitive queries\n```\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| --------------------- | ------------------------------------- | ------------------------------------------------------ |\n| Empty AST output | `sourceFiles` parameter not matching | Use just filenames, not full paths (e.g., `"test.js"`) |\n| Empty CFG output | `sourceFunction` not found | Check exact function name spelling |\n| Empty CallGraph | No calls exist or wrong function name | Verify function exists and has calls |\n| Query compilation err | Pack dependencies missing | Run #codeql_pack_install on the tools pack |\n\n## MCP Tools Reference\n\n| Tool | Purpose |\n| ------------------------ | ---------------------------------------------------- |\n| #codeql_query_run | Execute tools queries with parameters |\n| #codeql_resolve_database | Validate database before querying |\n| #codeql_database_create | Create database from source code |\n| #codeql_bqrs_interpret | Convert results to different formats |\n| #codeql_pack_install | Install pack dependencies if needed |\n| #codeql_lsp_completion | Explore available types after seeing AST class names |\n| #codeql_lsp_definition | Navigate to class definitions to see predicates |\n| #codeql_lsp_references | Find usage examples of a class or predicate |\n\n### Using LSP Tools After AST Analysis\n\nAfter running PrintAST and identifying relevant AST class names, use the LSP tools\nto explore those classes in your query file:\n\n1. **Write the class name** in your query\'s `from` clause and save the file\n2. **Run #codeql_lsp_completion** after the dot to see member predicates:\n - `file_path`: your query file, `line`/`character`: 0-based position after the dot\n - `workspace_uri`: the pack root directory (containing `codeql-pack.yml`)\n3. **Run #codeql_lsp_definition** on an AST class name to see its full API\n4. **Run #codeql_lsp_references** to find usage examples in the pack\n\n> **Note**: LSP tools use 0-based line/character positions. Run #codeql_pack_install\n> before using them \u2014 they require resolved dependencies. Set `workspace_uri` to\n> a plain directory path (not a `file://` URI).\n\nFor the full iterative LSP development workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n';
|
|
64287
|
+
var tools_query_workflow_prompt_default = '---\nagent: agent\n---\n\n# Using CodeQL Development MCP Server Tools Queries\n\nThis guide helps you use the built-in "tools" queries (`PrintAST`, `PrintCFG`, `CallGraphFrom`, `CallGraphTo`) that ship with the CodeQL Development MCP Server to understand code structure before writing detection queries.\n\n## Why Use Tools Queries?\n\nTools queries provide essential insights into how CodeQL represents your source code:\n\n| Query | Purpose | Use When |\n| --------------- | ------------------------------------------------ | ----------------------------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree | Understanding code structure, finding AST nodes |\n| `PrintCFG` | Visualize Control Flow Graphs | Understanding execution paths, loop/branch flow |\n| `CallGraphFrom` | Find all functions called by a specific function | Tracing data flow through call chains |\n| `CallGraphTo` | Find all functions that call a specific function | Understanding function usage patterns |\n\n## Supported Languages\n\nTools queries are available for: `actions`, `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `swift`\n\n## Prerequisites\n\nBefore using tools queries, you need:\n\n1. **A CodeQL database** - Either create one or use an existing database\n2. **Source files to analyze** - The tools queries filter output to specific files\n\n## Workflow Checklist\n\n### Step 1: Identify or Create Database\n\n- [ ] **Option A: Use existing database**\n - Tool: #codeql_resolve_database\n - Verify database is valid and note the language\n\n- [ ] **Option B: Create new database**\n - Tool: #codeql_database_create\n - Parameters: `database`, `language`, `source-root`\n\n### Step 2: Run PrintAST Query\n\nThe PrintAST query outputs a hierarchical tree of AST nodes with labels.\n\n- [ ] **Execute PrintAST**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"javascript"`, `"python"`, `"cpp"`)\n - `sourceFiles`: Comma-separated file names to analyze (e.g., `"main.js,utils.js"`)\n - `format`: `"graphtext"` (for human-readable output)\n\n- [ ] **Verify output contains AST nodes**\n - Look for hierarchical structure with indentation\n - Confirm nodes have `semmle.label` with class names\n - Identify relevant AST classes for your query\n\n**Example AST output structure:**\n\n```text\nTopLevelFunction\n\u251C\u2500\u2500 FunctionDeclarationEntry\n\u251C\u2500\u2500 Block\n\u2502 \u251C\u2500\u2500 DeclStmt\n\u2502 \u2502 \u2514\u2500\u2500 LocalVariable\n\u2502 \u251C\u2500\u2500 ExprStmt\n\u2502 \u2502 \u2514\u2500\u2500 FunctionCall\n\u2502 \u2514\u2500\u2500 ReturnStmt\n```\n\n### Step 3: Run PrintCFG Query (if needed)\n\nThe PrintCFG query outputs control flow nodes and edges.\n\n- [ ] **Execute PrintCFG**\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to analyze (e.g., `"processData"`)\n - `format`: `"graphtext"`\n\n- [ ] **Verify output contains nodes and edges**\n - Look for `nodes` section with CFG nodes\n - Look for `edges` section with `\u2192` arrows showing flow\n - Identify control flow patterns (loops, branches)\n\n**Example CFG output structure:**\n\n```text\nnodes\n| node | semmle.label |\n| ... | entry: processData |\n| ... | if (...) |\n| ... | return |\n\nedges\n| from | to | semmle.label |\n| ... | ... | \u2192 |\n```\n\n### Step 4: Run CallGraph Queries (if needed)\n\nCall graph queries help trace function relationships.\n\n- [ ] **Execute CallGraphFrom** (to find what a function calls)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphFrom"`\n - `queryLanguage`: Your language\n - `sourceFunction`: Function name to trace from (e.g., `"main"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Execute CallGraphTo** (to find what calls a function)\n - Tool: #codeql_query_run\n - Parameters:\n - `database`: Path to your CodeQL database\n - `queryName`: `"CallGraphTo"`\n - `queryLanguage`: Your language\n - `targetFunction`: Function name to find callers of (e.g., `"validate"`)\n - `format`: `"sarif-latest"` or `"csv"`\n\n- [ ] **Verify call relationships**\n - Confirm results show caller \u2192 callee relationships\n - Note function locations for further analysis\n\n### Step 5: Apply Insights to Query Development\n\nUse the gathered information to inform your query:\n\n- [ ] **From PrintAST**: Identify which AST classes to use in your `from` clause\n- [ ] **From PrintCFG**: Understand execution paths for control-flow-sensitive queries\n- [ ] **From CallGraph**: Map data flow paths through function boundaries\n\n## Common Patterns\n\n### Pattern 1: Finding All Function Calls\n\n```text\n1. Run PrintAST on your source file\n2. Look for FunctionCall, MethodAccess, or similar nodes\n3. Note the parent/child relationships\n4. Use those AST classes in your query\n```\n\n### Pattern 2: Tracing Data Through Functions\n\n```text\n1. Run CallGraphFrom on your entry point function\n2. Identify which functions are called\n3. Run CallGraphTo on sink functions\n4. Map the complete path from source to sink\n```\n\n### Pattern 3: Understanding Loop Structures\n\n```text\n1. Run PrintAST to find loop constructs (ForStmt, WhileStmt, etc.)\n2. Run PrintCFG on the containing function\n3. Identify back edges that represent loop iteration\n4. Use CFG analysis for loop-sensitive queries\n```\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| --------------------- | ------------------------------------- | ------------------------------------------------------ |\n| Empty AST output | `sourceFiles` parameter not matching | Use just filenames, not full paths (e.g., `"test.js"`) |\n| Empty CFG output | `sourceFunction` not found | Check exact function name spelling |\n| Empty CallGraph | No calls exist or wrong function name | Verify function exists and has calls |\n| Query compilation err | Pack dependencies missing | Run #codeql_pack_install on the tools pack |\n\n## MCP Tools Reference\n\n| Tool | Purpose |\n| ------------------------ | ---------------------------------------------------- |\n| #codeql_query_run | Execute tools queries with parameters |\n| #codeql_resolve_database | Validate database before querying |\n| #codeql_database_create | Create database from source code |\n| #codeql_bqrs_interpret | Convert results to different formats |\n| #codeql_pack_install | Install pack dependencies if needed |\n| #codeql_lsp_completion | Explore available types after seeing AST class names |\n| #codeql_lsp_definition | Navigate to class definitions to see predicates |\n| #codeql_lsp_references | Find usage examples of a class or predicate |\n| #search_ql_code | Search QL source files for patterns (text or regex) |\n| #codeql_resolve_files | Find QL files by name, extension, or glob pattern |\n\n### Using LSP Tools After AST Analysis\n\nAfter running PrintAST and identifying relevant AST class names, use the LSP tools\nto explore those classes in your query file:\n\n1. **Write the class name** in your query\'s `from` clause and save the file\n2. **Run #codeql_lsp_completion** after the dot to see member predicates:\n - `file_path`: your query file, `line`/`character`: 0-based position after the dot\n - `workspace_uri`: the pack root directory (containing `codeql-pack.yml`)\n3. **Run #codeql_lsp_definition** on an AST class name to see its full API\n4. **Run #codeql_lsp_references** to find usage examples in the pack\n\n> **Note**: LSP tools use 0-based line/character positions. Run #codeql_pack_install\n> before using them \u2014 they require resolved dependencies. Set `workspace_uri` to\n> a plain directory path (not a `file://` URI).\n\nFor the full iterative LSP development workflow, see: `codeql://prompts/ql_lsp_iterative_development`\n';
|
|
63471
64288
|
|
|
63472
64289
|
// src/prompts/workshop-creation-workflow.prompt.md
|
|
63473
64290
|
var workshop_creation_workflow_prompt_default = '---\nagent: agent\n---\n\n# Creating CodeQL Query Development Workshops\n\nThis guide helps you create educational CodeQL query development workshops from existing production-grade queries. Workshops teach developers how to build queries incrementally through exercises and solutions.\n\n## Workshop Purpose\n\nA CodeQL workshop transforms a complex, production-ready query into a series of incremental learning stages:\n\n- **Exercises**: Incomplete query stubs with scaffolding and hints\n- **Solutions**: Complete working queries for each stage\n- **Tests**: Unit tests validating each stage works correctly\n- **Documentation**: README with learning objectives and instructions\n\n## Prerequisites\n\nBefore creating a workshop, ensure you have:\n\n1. **A production-grade CodeQL query** - The "target" query to decompose\n2. **Working unit tests** - Tests that pass for the target query\n3. **A CodeQL database** - For running tools queries and validating results\n\n## Workshop Creation Checklist\n\n### Phase 1: Analyze the Target Query\n\n- [ ] **Locate query files**\n - Tool: #find_codeql_query_files\n - Parameters: `queryPath` (path to the `.ql` or `.qlref` file)\n - Note: Returns query file, test files, expected results, and metadata\n\n- [ ] **Understand query logic for workshop content**\n - Prompt: `explain_codeql_query`\n - Parameters: `queryPath`, `language`, and optionally `databasePath`\n - Identify: sources, sinks, sanitizers, flow configuration\n - Generates: detailed explanation with mermaid evaluation diagram\n\n- [ ] **Verify existing tests pass**\n - Tool: #codeql_test_run\n - Parameters: `tests` (array of test directories)\n - Confirm: 100% pass rate before proceeding\n\n### Phase 2: Generate AST/CFG Understanding\n\n> **\u26A0\uFE0F CRITICAL**: Run tools queries to understand the test code structure.\n\n- [ ] **Run PrintAST on test code**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintAST"`\n - `queryLanguage`: Your language (e.g., `"cpp"`, `"javascript"`)\n - `database`: Path to test database or extracted `.testproj`\n - `sourceFiles`: Test source file names\n - `format`: `"graphtext"`\n - Verify: Output contains hierarchical AST nodes (not empty)\n\n- [ ] **Run PrintCFG on key functions**\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"PrintCFG"`\n - `queryLanguage`: Your language\n - `database`: Path to database\n - `sourceFunction`: Key function names from test code\n - `format`: `"graphtext"`\n - Verify: Output contains nodes and edges\n\n- [ ] **Run CallGraph queries** (if query involves data flow)\n - Tool: #codeql_query_run\n - Parameters:\n - `queryName`: `"CallGraphFrom"` or `"CallGraphTo"`\n - `database`: Path to database\n - `sourceFunction` / `targetFunction`: Relevant function names\n - Verify: Output shows call relationships\n\n### Phase 3: Plan Workshop Stages\n\nDecompose the query into 4-8 incremental stages using these strategies:\n\n#### Decomposition Strategies\n\n| Strategy | Description | Example Progression |\n| -------------------- | -------------------------------------------------------- | ------------------------------------- |\n| Syntactic \u2192 Semantic | Start with syntax, add type checking, then data flow | AST \u2192 Types \u2192 Local flow \u2192 Global |\n| Local \u2192 Global | Start with local analysis, expand to cross-procedural | Single function \u2192 Multiple functions |\n| Simple \u2192 Filtered | High recall first, then add precision filters | All calls \u2192 Specific calls \u2192 Filtered |\n| Building Blocks | Define helpers, combine into sources/sinks, connect flow | Predicates \u2192 Sources \u2192 Sinks \u2192 Config |\n\n- [ ] **Document stage progression**\n - Stage 1: Basic syntactic pattern (highest recall)\n - Stage 2-N: Add refinements (types, filters, flow)\n - Final Stage: Complete production query\n\n### Phase 4: Create Workshop Structure\n\nStandard workshop directory layout:\n\n```text\nworkshop-name/\n\u251C\u2500\u2500 codeql-workspace.yml # CodeQL workspace configuration\n\u251C\u2500\u2500 README.md # Workshop guide with instructions\n\u251C\u2500\u2500 build-databases.sh # Script to create test databases\n\u251C\u2500\u2500 exercises/ # Student exercise queries\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1.ql\n\u2502 \u251C\u2500\u2500 Exercise2.ql\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 exercises-tests/ # Tests for exercises\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1/\n\u2502 \u2502 \u251C\u2500\u2500 Exercise1.qlref\n\u2502 \u2502 \u251C\u2500\u2500 Exercise1.expected\n\u2502 \u2502 \u2514\u2500\u2500 test.ext\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 solutions/ # Complete solution queries\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u251C\u2500\u2500 Exercise1.ql\n\u2502 \u251C\u2500\u2500 Exercise2.ql\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 solutions-tests/ # Tests for solutions\n\u2502 \u251C\u2500\u2500 codeql-pack.yml\n\u2502 \u2514\u2500\u2500 ...\n\u251C\u2500\u2500 tests-common/ # Shared test code\n\u2502 \u2514\u2500\u2500 test.ext\n\u2514\u2500\u2500 graphs/ # AST/CFG visualizations\n \u2514\u2500\u2500 ast-overview.txt\n```\n\n- [ ] **Create codeql-workspace.yml**\n\n ```yaml\n provide:\n - \'*/codeql-pack.yml\'\n ```\n\n- [ ] **Create pack files for each directory**\n - `exercises/codeql-pack.yml`: Query pack depending on language library\n - `exercises-tests/codeql-pack.yml`: Test pack depending on exercises\n - `solutions/codeql-pack.yml`: Query pack (same deps as exercises)\n - `solutions-tests/codeql-pack.yml`: Test pack depending on solutions\n\n### Phase 5: Create Solution Queries\n\nFor each stage, create a complete solution query. Use the iterative LSP tools\nfor efficient development (see `codeql://prompts/ql_lsp_iterative_development`):\n\n- Use #codeql_lsp_completion to explore types and member predicates while writing queries\n- Use #codeql_lsp_definition to navigate to library class definitions\n- Use #find_predicate_position + #quick_evaluate to test predicates in isolation\n- Set `workspace_uri` to the solutions pack root for dependency resolution\n\n- [ ] **Stage 1 Solution**: Simplest working version\n - Basic import statements\n - Minimal from/where/select clause\n - Should produce results (high recall, lower precision)\n\n- [ ] **Intermediate Stages**: Progressive refinements\n - Add type constraints\n - Add helper predicates\n - Filter out false positives\n - Add data flow (if applicable)\n\n- [ ] **Final Stage Solution**: Production-quality query\n - Complete metadata (@name, @description, @kind, @id)\n - Full data flow configuration (if applicable)\n - Proper sanitizers and barriers\n - Matches the original target query\n\n### Phase 6: Create Exercise Queries\n\nTransform solutions into exercises by removing implementation details:\n\n- [ ] **Add scaffolding structure**\n\n ```ql\n /**\n * @name Exercise N - [Topic]\n * @description TODO: Complete this exercise\n * @kind problem\n * @id workshop/exercise-n\n */\n\n import language\n\n // TODO: Define predicate to find [something]\n predicate findSomething(Type t) {\n // Your implementation here\n none()\n }\n\n from Type t\n where findSomething(t)\n select t, "Found something"\n ```\n\n- [ ] **Include helpful comments**\n - Hints about which AST classes to use\n - References to documentation\n - Expected behavior description\n\n- [ ] **Ensure exercises compile**\n - Tool: #codeql_query_compile\n - Exercises should compile (even if tests fail)\n\n### Phase 7: Create Tests\n\n- [ ] **Copy test code to test directories**\n - Use same test code for exercises and solutions\n - Consider `initialize-qltests.sh` script for shared test code\n\n- [ ] **Create .qlref files**\n - Point to query location: `../exercises/ExerciseN.ql`\n\n- [ ] **Create .expected files**\n - Run solution queries to generate expected output\n - Tool: #codeql_test_run with `--learn` flag\n - Or: #codeql_test_accept after running tests\n\n### Phase 8: Validate Workshop\n\n- [ ] **Run all solution tests**\n - Tool: #codeql_test_run\n - Parameters: `tests` pointing to `solutions-tests/`\n - Verify: 100% pass rate\n\n- [ ] **Verify exercise stubs compile**\n - Tool: #codeql_query_compile\n - Parameters: Each exercise query\n - Verify: No compilation errors\n\n- [ ] **Test pack dependencies**\n - Tool: #codeql_pack_install\n - Run in each pack directory\n - Verify: Dependencies resolve correctly\n\n### Phase 9: Create Documentation\n\n- [ ] **Write README.md**\n - Workshop overview and objectives\n - Setup instructions\n - Stage-by-stage learning guide\n - AST/CFG examples from Phase 2\n\n- [ ] **Include AST/CFG visualizations**\n - Save PrintAST output to `graphs/`\n - Reference in README for learning context\n\n## External Workshop Considerations\n\nWhen creating workshops outside the MCP server repository:\n\n- [ ] **Install pack dependencies first**\n\n ```bash\n codeql pack install solutions\n codeql pack install solutions-tests\n ```\n\n- [ ] **Check for initialization scripts**\n - Some workshops use `initialize-qltests.sh` to copy test files\n - Run before executing tests\n\n- [ ] **Use absolute paths with MCP tools**\n - External paths must be absolute\n\n## MCP Tools and Prompts Reference\n\n| Tool/Prompt | Type | Purpose |\n| ------------------------------- | ------ | ---------------------------------------------------------------------- |\n| #find_codeql_query_files | Tool | Locate query and related files |\n| `explain_codeql_query` | Prompt | Generate detailed explanations for workshop learning content |\n| `document_codeql_query` | Prompt | Create/update query documentation files |\n| `ql_lsp_iterative_development` | Prompt | Iterative query development with LSP tools |\n| #codeql_query_run | Tool | Run tools queries (PrintAST, PrintCFG, etc.) |\n| #codeql_test_run | Tool | Validate tests pass |\n| #codeql_test_accept | Tool | Accept test results as expected baseline |\n| #codeql_query_compile | Tool | Verify queries compile |\n| #codeql_pack_install | Tool | Install pack dependencies |\n| #codeql_resolve_metadata | Tool | Extract query metadata |\n| #codeql_lsp_completion | Tool | Explore types and member predicates during query writing |\n| #codeql_lsp_definition | Tool | Navigate to class/predicate definitions in library code |\n| #find_predicate_position | Tool | Locate predicate positions for quick_evaluate |\n| #quick_evaluate | Tool | Test individual predicates against a database |\n| #profile_codeql_query_from_logs | Tool | Parse evaluator logs from a prior query run into a performance profile |\n| #create_codeql_query | Tool | Scaffold new query structure |\n\n## Troubleshooting\n\n| Issue | Likely Cause | Resolution |\n| ------------------------ | ------------------------------- | --------------------------------------------------- |\n| "Nothing to extract" | Missing test source files | Run `initialize-qltests.sh` or copy from shared dir |\n| Pack not found | Older pack version not cached | Run `codeql pack install` in pack directory |\n| Empty AST/CFG output | Wrong sourceFiles/Function | Use just filenames, verify function name spelling |\n| Tests fail unexpectedly | Expected file outdated | Re-run solution and accept with #codeql_test_accept |\n| Exercise doesn\'t compile | Missing imports or syntax error | Ensure valid QL syntax with `none()` placeholder |\n';
|
|
@@ -63650,7 +64467,7 @@ ${content}`
|
|
|
63650
64467
|
workshopCreationWorkflowSchema.shape,
|
|
63651
64468
|
async ({ queryPath, language, workshopName, numStages }) => {
|
|
63652
64469
|
const template = loadPromptTemplate("workshop-creation-workflow.prompt.md");
|
|
63653
|
-
const derivedName = workshopName ||
|
|
64470
|
+
const derivedName = workshopName || basename7(queryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
|
|
63654
64471
|
const contextSection = buildWorkshopContext(
|
|
63655
64472
|
queryPath,
|
|
63656
64473
|
language,
|
|
@@ -64010,7 +64827,7 @@ var Low = class {
|
|
|
64010
64827
|
};
|
|
64011
64828
|
|
|
64012
64829
|
// ../node_modules/lowdb/lib/adapters/node/TextFile.js
|
|
64013
|
-
import { readFileSync as
|
|
64830
|
+
import { readFileSync as readFileSync10, renameSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
64014
64831
|
import path3 from "node:path";
|
|
64015
64832
|
var TextFileSync = class {
|
|
64016
64833
|
#tempFilename;
|
|
@@ -64023,7 +64840,7 @@ var TextFileSync = class {
|
|
|
64023
64840
|
read() {
|
|
64024
64841
|
let data;
|
|
64025
64842
|
try {
|
|
64026
|
-
data =
|
|
64843
|
+
data = readFileSync10(this.#filename, "utf-8");
|
|
64027
64844
|
} catch (e) {
|
|
64028
64845
|
if (e.code === "ENOENT") {
|
|
64029
64846
|
return null;
|
|
@@ -65369,9 +66186,9 @@ init_cli_executor();
|
|
|
65369
66186
|
init_server_manager();
|
|
65370
66187
|
init_package_paths();
|
|
65371
66188
|
init_logger();
|
|
65372
|
-
import_dotenv.default.config({ path:
|
|
66189
|
+
import_dotenv.default.config({ path: resolve13(packageRootDir, ".env"), quiet: true });
|
|
65373
66190
|
var PACKAGE_NAME = "codeql-development-mcp-server";
|
|
65374
|
-
var VERSION = "2.24.
|
|
66191
|
+
var VERSION = "2.24.3-rc2";
|
|
65375
66192
|
async function startServer(mode = "stdio") {
|
|
65376
66193
|
logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
|
|
65377
66194
|
const codeqlBinary = resolveCodeQLBinary();
|
|
@@ -65425,10 +66242,10 @@ async function startServer(mode = "stdio") {
|
|
|
65425
66242
|
});
|
|
65426
66243
|
const host = process.env.HTTP_HOST || "localhost";
|
|
65427
66244
|
const port = Number(process.env.HTTP_PORT || process.env.PORT) || 3e3;
|
|
65428
|
-
return new Promise((
|
|
66245
|
+
return new Promise((resolve14, reject) => {
|
|
65429
66246
|
const httpServer = app.listen(port, host, () => {
|
|
65430
66247
|
logger.info(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
65431
|
-
|
|
66248
|
+
resolve14();
|
|
65432
66249
|
});
|
|
65433
66250
|
httpServer.on("error", (error2) => {
|
|
65434
66251
|
logger.error("HTTP server error:", error2);
|
|
@@ -65465,7 +66282,7 @@ async function main() {
|
|
|
65465
66282
|
process.exit(1);
|
|
65466
66283
|
}
|
|
65467
66284
|
}
|
|
65468
|
-
var scriptPath = process.argv[1] ?
|
|
66285
|
+
var scriptPath = process.argv[1] ? realpathSync2(resolve13(process.argv[1])) : void 0;
|
|
65469
66286
|
if (scriptPath && import.meta.url === pathToFileURL5(scriptPath).href) {
|
|
65470
66287
|
main();
|
|
65471
66288
|
}
|