codeql-development-mcp-server 2.25.2 → 2.25.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/codeql-development-mcp-server.js +940 -226
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +9 -8
- package/ql/actions/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/actions/tools/src/codeql-pack.yml +2 -2
- package/ql/cpp/tools/src/codeql-pack.lock.yml +12 -12
- package/ql/cpp/tools/src/codeql-pack.yml +2 -2
- package/ql/csharp/tools/src/PrintCFG/PrintCFG.ql +2 -2
- package/ql/csharp/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/csharp/tools/src/codeql-pack.yml +2 -2
- package/ql/go/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/go/tools/src/codeql-pack.yml +2 -2
- package/ql/java/tools/src/codeql-pack.lock.yml +14 -14
- package/ql/java/tools/src/codeql-pack.yml +2 -2
- package/ql/javascript/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/javascript/tools/src/codeql-pack.yml +2 -2
- package/ql/python/tools/src/codeql-pack.lock.yml +13 -13
- package/ql/python/tools/src/codeql-pack.yml +2 -2
- package/ql/ruby/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/ruby/tools/src/codeql-pack.yml +2 -2
- package/ql/rust/tools/src/codeql-pack.lock.yml +12 -12
- package/ql/rust/tools/src/codeql-pack.yml +2 -2
- package/ql/swift/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/swift/tools/src/codeql-pack.yml +2 -2
|
@@ -3117,6 +3117,9 @@ var require_utils = __commonJS({
|
|
|
3117
3117
|
"use strict";
|
|
3118
3118
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3119
3119
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3120
|
+
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3121
|
+
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3122
|
+
var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
|
|
3120
3123
|
function stringArrayToHexStripped(input) {
|
|
3121
3124
|
let acc = "";
|
|
3122
3125
|
let code = 0;
|
|
@@ -3309,27 +3312,77 @@ var require_utils = __commonJS({
|
|
|
3309
3312
|
}
|
|
3310
3313
|
return output.join("");
|
|
3311
3314
|
}
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3315
|
+
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
3316
|
+
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
3317
|
+
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
3318
|
+
function reescapeHostDelimiters(host, isIP) {
|
|
3319
|
+
const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
3320
|
+
re.lastIndex = 0;
|
|
3321
|
+
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
3322
|
+
}
|
|
3323
|
+
function normalizePercentEncoding(input, decodeUnreserved = false) {
|
|
3324
|
+
if (input.indexOf("%") === -1) {
|
|
3325
|
+
return input;
|
|
3322
3326
|
}
|
|
3323
|
-
|
|
3324
|
-
|
|
3327
|
+
let output = "";
|
|
3328
|
+
for (let i = 0; i < input.length; i++) {
|
|
3329
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3330
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3331
|
+
if (isHexPair(hex)) {
|
|
3332
|
+
const normalizedHex = hex.toUpperCase();
|
|
3333
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3334
|
+
if (decodeUnreserved && isUnreserved(decoded)) {
|
|
3335
|
+
output += decoded;
|
|
3336
|
+
} else {
|
|
3337
|
+
output += "%" + normalizedHex;
|
|
3338
|
+
}
|
|
3339
|
+
i += 2;
|
|
3340
|
+
continue;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
output += input[i];
|
|
3325
3344
|
}
|
|
3326
|
-
|
|
3327
|
-
|
|
3345
|
+
return output;
|
|
3346
|
+
}
|
|
3347
|
+
function normalizePathEncoding(input) {
|
|
3348
|
+
let output = "";
|
|
3349
|
+
for (let i = 0; i < input.length; i++) {
|
|
3350
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3351
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3352
|
+
if (isHexPair(hex)) {
|
|
3353
|
+
const normalizedHex = hex.toUpperCase();
|
|
3354
|
+
const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
|
|
3355
|
+
if (decoded !== "." && isUnreserved(decoded)) {
|
|
3356
|
+
output += decoded;
|
|
3357
|
+
} else {
|
|
3358
|
+
output += "%" + normalizedHex;
|
|
3359
|
+
}
|
|
3360
|
+
i += 2;
|
|
3361
|
+
continue;
|
|
3362
|
+
}
|
|
3363
|
+
}
|
|
3364
|
+
if (isPathCharacter(input[i])) {
|
|
3365
|
+
output += input[i];
|
|
3366
|
+
} else {
|
|
3367
|
+
output += escape(input[i]);
|
|
3368
|
+
}
|
|
3328
3369
|
}
|
|
3329
|
-
|
|
3330
|
-
|
|
3370
|
+
return output;
|
|
3371
|
+
}
|
|
3372
|
+
function escapePreservingEscapes(input) {
|
|
3373
|
+
let output = "";
|
|
3374
|
+
for (let i = 0; i < input.length; i++) {
|
|
3375
|
+
if (input[i] === "%" && i + 2 < input.length) {
|
|
3376
|
+
const hex = input.slice(i + 1, i + 3);
|
|
3377
|
+
if (isHexPair(hex)) {
|
|
3378
|
+
output += "%" + hex.toUpperCase();
|
|
3379
|
+
i += 2;
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3382
|
+
}
|
|
3383
|
+
output += escape(input[i]);
|
|
3331
3384
|
}
|
|
3332
|
-
return
|
|
3385
|
+
return output;
|
|
3333
3386
|
}
|
|
3334
3387
|
function recomposeAuthority(component) {
|
|
3335
3388
|
const uriTokens = [];
|
|
@@ -3344,7 +3397,7 @@ var require_utils = __commonJS({
|
|
|
3344
3397
|
if (ipV6res.isIPV6 === true) {
|
|
3345
3398
|
host = `[${ipV6res.escapedHost}]`;
|
|
3346
3399
|
} else {
|
|
3347
|
-
host =
|
|
3400
|
+
host = reescapeHostDelimiters(host, false);
|
|
3348
3401
|
}
|
|
3349
3402
|
}
|
|
3350
3403
|
uriTokens.push(host);
|
|
@@ -3358,7 +3411,10 @@ var require_utils = __commonJS({
|
|
|
3358
3411
|
module.exports = {
|
|
3359
3412
|
nonSimpleDomain,
|
|
3360
3413
|
recomposeAuthority,
|
|
3361
|
-
|
|
3414
|
+
reescapeHostDelimiters,
|
|
3415
|
+
normalizePercentEncoding,
|
|
3416
|
+
normalizePathEncoding,
|
|
3417
|
+
escapePreservingEscapes,
|
|
3362
3418
|
removeDotSegments,
|
|
3363
3419
|
isIPv4,
|
|
3364
3420
|
isUUID,
|
|
@@ -3582,12 +3638,12 @@ var require_schemes = __commonJS({
|
|
|
3582
3638
|
var require_fast_uri = __commonJS({
|
|
3583
3639
|
"../node_modules/fast-uri/index.js"(exports, module) {
|
|
3584
3640
|
"use strict";
|
|
3585
|
-
var { normalizeIPv6, removeDotSegments, recomposeAuthority,
|
|
3641
|
+
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
|
|
3586
3642
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
3587
3643
|
function normalize2(uri, options) {
|
|
3588
3644
|
if (typeof uri === "string") {
|
|
3589
3645
|
uri = /** @type {T} */
|
|
3590
|
-
|
|
3646
|
+
normalizeString(uri, options);
|
|
3591
3647
|
} else if (typeof uri === "object") {
|
|
3592
3648
|
uri = /** @type {T} */
|
|
3593
3649
|
parse4(serialize(uri, options), options);
|
|
@@ -3600,49 +3656,49 @@ var require_fast_uri = __commonJS({
|
|
|
3600
3656
|
schemelessOptions.skipEscape = true;
|
|
3601
3657
|
return serialize(resolved, schemelessOptions);
|
|
3602
3658
|
}
|
|
3603
|
-
function resolveComponent(base,
|
|
3659
|
+
function resolveComponent(base, relative4, options, skipNormalization) {
|
|
3604
3660
|
const target = {};
|
|
3605
3661
|
if (!skipNormalization) {
|
|
3606
3662
|
base = parse4(serialize(base, options), options);
|
|
3607
|
-
|
|
3663
|
+
relative4 = parse4(serialize(relative4, options), options);
|
|
3608
3664
|
}
|
|
3609
3665
|
options = options || {};
|
|
3610
|
-
if (!options.tolerant &&
|
|
3611
|
-
target.scheme =
|
|
3612
|
-
target.userinfo =
|
|
3613
|
-
target.host =
|
|
3614
|
-
target.port =
|
|
3615
|
-
target.path = removeDotSegments(
|
|
3616
|
-
target.query =
|
|
3666
|
+
if (!options.tolerant && relative4.scheme) {
|
|
3667
|
+
target.scheme = relative4.scheme;
|
|
3668
|
+
target.userinfo = relative4.userinfo;
|
|
3669
|
+
target.host = relative4.host;
|
|
3670
|
+
target.port = relative4.port;
|
|
3671
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3672
|
+
target.query = relative4.query;
|
|
3617
3673
|
} else {
|
|
3618
|
-
if (
|
|
3619
|
-
target.userinfo =
|
|
3620
|
-
target.host =
|
|
3621
|
-
target.port =
|
|
3622
|
-
target.path = removeDotSegments(
|
|
3623
|
-
target.query =
|
|
3674
|
+
if (relative4.userinfo !== void 0 || relative4.host !== void 0 || relative4.port !== void 0) {
|
|
3675
|
+
target.userinfo = relative4.userinfo;
|
|
3676
|
+
target.host = relative4.host;
|
|
3677
|
+
target.port = relative4.port;
|
|
3678
|
+
target.path = removeDotSegments(relative4.path || "");
|
|
3679
|
+
target.query = relative4.query;
|
|
3624
3680
|
} else {
|
|
3625
|
-
if (!
|
|
3681
|
+
if (!relative4.path) {
|
|
3626
3682
|
target.path = base.path;
|
|
3627
|
-
if (
|
|
3628
|
-
target.query =
|
|
3683
|
+
if (relative4.query !== void 0) {
|
|
3684
|
+
target.query = relative4.query;
|
|
3629
3685
|
} else {
|
|
3630
3686
|
target.query = base.query;
|
|
3631
3687
|
}
|
|
3632
3688
|
} else {
|
|
3633
|
-
if (
|
|
3634
|
-
target.path = removeDotSegments(
|
|
3689
|
+
if (relative4.path[0] === "/") {
|
|
3690
|
+
target.path = removeDotSegments(relative4.path);
|
|
3635
3691
|
} else {
|
|
3636
3692
|
if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
|
|
3637
|
-
target.path = "/" +
|
|
3693
|
+
target.path = "/" + relative4.path;
|
|
3638
3694
|
} else if (!base.path) {
|
|
3639
|
-
target.path =
|
|
3695
|
+
target.path = relative4.path;
|
|
3640
3696
|
} else {
|
|
3641
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
3697
|
+
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative4.path;
|
|
3642
3698
|
}
|
|
3643
3699
|
target.path = removeDotSegments(target.path);
|
|
3644
3700
|
}
|
|
3645
|
-
target.query =
|
|
3701
|
+
target.query = relative4.query;
|
|
3646
3702
|
}
|
|
3647
3703
|
target.userinfo = base.userinfo;
|
|
3648
3704
|
target.host = base.host;
|
|
@@ -3650,23 +3706,13 @@ var require_fast_uri = __commonJS({
|
|
|
3650
3706
|
}
|
|
3651
3707
|
target.scheme = base.scheme;
|
|
3652
3708
|
}
|
|
3653
|
-
target.fragment =
|
|
3709
|
+
target.fragment = relative4.fragment;
|
|
3654
3710
|
return target;
|
|
3655
3711
|
}
|
|
3656
3712
|
function equal(uriA, uriB, options) {
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
} else if (typeof uriA === "object") {
|
|
3661
|
-
uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
|
|
3662
|
-
}
|
|
3663
|
-
if (typeof uriB === "string") {
|
|
3664
|
-
uriB = unescape(uriB);
|
|
3665
|
-
uriB = serialize(normalizeComponentEncoding(parse4(uriB, options), true), { ...options, skipEscape: true });
|
|
3666
|
-
} else if (typeof uriB === "object") {
|
|
3667
|
-
uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
|
|
3668
|
-
}
|
|
3669
|
-
return uriA.toLowerCase() === uriB.toLowerCase();
|
|
3713
|
+
const normalizedA = normalizeComparableURI(uriA, options);
|
|
3714
|
+
const normalizedB = normalizeComparableURI(uriB, options);
|
|
3715
|
+
return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
|
|
3670
3716
|
}
|
|
3671
3717
|
function serialize(cmpts, opts) {
|
|
3672
3718
|
const component = {
|
|
@@ -3691,12 +3737,12 @@ var require_fast_uri = __commonJS({
|
|
|
3691
3737
|
if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
|
|
3692
3738
|
if (component.path !== void 0) {
|
|
3693
3739
|
if (!options.skipEscape) {
|
|
3694
|
-
component.path =
|
|
3740
|
+
component.path = escapePreservingEscapes(component.path);
|
|
3695
3741
|
if (component.scheme !== void 0) {
|
|
3696
3742
|
component.path = component.path.split("%3A").join(":");
|
|
3697
3743
|
}
|
|
3698
3744
|
} else {
|
|
3699
|
-
component.path =
|
|
3745
|
+
component.path = normalizePercentEncoding(component.path);
|
|
3700
3746
|
}
|
|
3701
3747
|
}
|
|
3702
3748
|
if (options.reference !== "suffix" && component.scheme) {
|
|
@@ -3731,7 +3777,16 @@ var require_fast_uri = __commonJS({
|
|
|
3731
3777
|
return uriTokens.join("");
|
|
3732
3778
|
}
|
|
3733
3779
|
var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
|
|
3734
|
-
function
|
|
3780
|
+
function getParseError(parsed, matches) {
|
|
3781
|
+
if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
|
|
3782
|
+
return 'URI path must start with "/" when authority is present.';
|
|
3783
|
+
}
|
|
3784
|
+
if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
|
|
3785
|
+
return "URI port is malformed.";
|
|
3786
|
+
}
|
|
3787
|
+
return void 0;
|
|
3788
|
+
}
|
|
3789
|
+
function parseWithStatus(uri, opts) {
|
|
3735
3790
|
const options = Object.assign({}, opts);
|
|
3736
3791
|
const parsed = {
|
|
3737
3792
|
scheme: void 0,
|
|
@@ -3742,6 +3797,7 @@ var require_fast_uri = __commonJS({
|
|
|
3742
3797
|
query: void 0,
|
|
3743
3798
|
fragment: void 0
|
|
3744
3799
|
};
|
|
3800
|
+
let malformedAuthorityOrPort = false;
|
|
3745
3801
|
let isIP = false;
|
|
3746
3802
|
if (options.reference === "suffix") {
|
|
3747
3803
|
if (options.scheme) {
|
|
@@ -3762,6 +3818,11 @@ var require_fast_uri = __commonJS({
|
|
|
3762
3818
|
if (isNaN(parsed.port)) {
|
|
3763
3819
|
parsed.port = matches[5];
|
|
3764
3820
|
}
|
|
3821
|
+
const parseError = getParseError(parsed, matches);
|
|
3822
|
+
if (parseError !== void 0) {
|
|
3823
|
+
parsed.error = parsed.error || parseError;
|
|
3824
|
+
malformedAuthorityOrPort = true;
|
|
3825
|
+
}
|
|
3765
3826
|
if (parsed.host) {
|
|
3766
3827
|
const ipv4result = isIPv4(parsed.host);
|
|
3767
3828
|
if (ipv4result === false) {
|
|
@@ -3800,14 +3861,18 @@ var require_fast_uri = __commonJS({
|
|
|
3800
3861
|
parsed.scheme = unescape(parsed.scheme);
|
|
3801
3862
|
}
|
|
3802
3863
|
if (parsed.host !== void 0) {
|
|
3803
|
-
parsed.host = unescape(parsed.host);
|
|
3864
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
|
|
3804
3865
|
}
|
|
3805
3866
|
}
|
|
3806
3867
|
if (parsed.path) {
|
|
3807
|
-
parsed.path =
|
|
3868
|
+
parsed.path = normalizePathEncoding(parsed.path);
|
|
3808
3869
|
}
|
|
3809
3870
|
if (parsed.fragment) {
|
|
3810
|
-
|
|
3871
|
+
try {
|
|
3872
|
+
parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
|
|
3873
|
+
} catch {
|
|
3874
|
+
parsed.error = parsed.error || "URI malformed";
|
|
3875
|
+
}
|
|
3811
3876
|
}
|
|
3812
3877
|
}
|
|
3813
3878
|
if (schemeHandler && schemeHandler.parse) {
|
|
@@ -3816,7 +3881,29 @@ var require_fast_uri = __commonJS({
|
|
|
3816
3881
|
} else {
|
|
3817
3882
|
parsed.error = parsed.error || "URI can not be parsed.";
|
|
3818
3883
|
}
|
|
3819
|
-
return parsed;
|
|
3884
|
+
return { parsed, malformedAuthorityOrPort };
|
|
3885
|
+
}
|
|
3886
|
+
function parse4(uri, opts) {
|
|
3887
|
+
return parseWithStatus(uri, opts).parsed;
|
|
3888
|
+
}
|
|
3889
|
+
function normalizeString(uri, opts) {
|
|
3890
|
+
return normalizeStringWithStatus(uri, opts).normalized;
|
|
3891
|
+
}
|
|
3892
|
+
function normalizeStringWithStatus(uri, opts) {
|
|
3893
|
+
const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
|
|
3894
|
+
return {
|
|
3895
|
+
normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
|
|
3896
|
+
malformedAuthorityOrPort
|
|
3897
|
+
};
|
|
3898
|
+
}
|
|
3899
|
+
function normalizeComparableURI(uri, opts) {
|
|
3900
|
+
if (typeof uri === "string") {
|
|
3901
|
+
const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
|
|
3902
|
+
return malformedAuthorityOrPort ? void 0 : normalized;
|
|
3903
|
+
}
|
|
3904
|
+
if (typeof uri === "object") {
|
|
3905
|
+
return serialize(uri, opts);
|
|
3906
|
+
}
|
|
3820
3907
|
}
|
|
3821
3908
|
var fastUri = {
|
|
3822
3909
|
SCHEMES,
|
|
@@ -13305,7 +13392,7 @@ var require_src = __commonJS({
|
|
|
13305
13392
|
// ../node_modules/depd/index.js
|
|
13306
13393
|
var require_depd = __commonJS({
|
|
13307
13394
|
"../node_modules/depd/index.js"(exports, module) {
|
|
13308
|
-
var
|
|
13395
|
+
var relative4 = __require("path").relative;
|
|
13309
13396
|
module.exports = depd;
|
|
13310
13397
|
var basePath = process.cwd();
|
|
13311
13398
|
function containsNamespace(str2, namespace) {
|
|
@@ -13497,7 +13584,7 @@ var require_depd = __commonJS({
|
|
|
13497
13584
|
return formatted;
|
|
13498
13585
|
}
|
|
13499
13586
|
function formatLocation(callSite) {
|
|
13500
|
-
return
|
|
13587
|
+
return relative4(basePath, callSite[0]) + ":" + callSite[1] + ":" + callSite[2];
|
|
13501
13588
|
}
|
|
13502
13589
|
function getStack() {
|
|
13503
13590
|
var limit = Error.stackTraceLimit;
|
|
@@ -32676,9 +32763,8 @@ var require_side_channel_list = __commonJS({
|
|
|
32676
32763
|
}
|
|
32677
32764
|
},
|
|
32678
32765
|
"delete": function(key) {
|
|
32679
|
-
var root = $o && $o.next;
|
|
32680
32766
|
var deletedNode = listDelete($o, key);
|
|
32681
|
-
if (deletedNode &&
|
|
32767
|
+
if (deletedNode && $o && !$o.next) {
|
|
32682
32768
|
$o = void 0;
|
|
32683
32769
|
}
|
|
32684
32770
|
return !!deletedNode;
|
|
@@ -34321,9 +34407,9 @@ var require_parse = __commonJS({
|
|
|
34321
34407
|
var limit = options.parameterLimit === Infinity ? void 0 : options.parameterLimit;
|
|
34322
34408
|
var parts = cleanStr.split(
|
|
34323
34409
|
options.delimiter,
|
|
34324
|
-
options.throwOnLimitExceeded ? limit + 1 : limit
|
|
34410
|
+
options.throwOnLimitExceeded && typeof limit !== "undefined" ? limit + 1 : limit
|
|
34325
34411
|
);
|
|
34326
|
-
if (options.throwOnLimitExceeded && parts.length > limit) {
|
|
34412
|
+
if (options.throwOnLimitExceeded && typeof limit !== "undefined" && parts.length > limit) {
|
|
34327
34413
|
throw new RangeError("Parameter limit exceeded. Only " + limit + " parameter" + (limit === 1 ? "" : "s") + " allowed.");
|
|
34328
34414
|
}
|
|
34329
34415
|
var skipIndex = -1;
|
|
@@ -35004,7 +35090,7 @@ var require_view = __commonJS({
|
|
|
35004
35090
|
var path3 = __require("node:path");
|
|
35005
35091
|
var fs3 = __require("node:fs");
|
|
35006
35092
|
var dirname10 = path3.dirname;
|
|
35007
|
-
var
|
|
35093
|
+
var basename11 = path3.basename;
|
|
35008
35094
|
var extname3 = path3.extname;
|
|
35009
35095
|
var join23 = path3.join;
|
|
35010
35096
|
var resolve15 = path3.resolve;
|
|
@@ -35043,7 +35129,7 @@ var require_view = __commonJS({
|
|
|
35043
35129
|
var root = roots[i];
|
|
35044
35130
|
var loc = resolve15(root, name);
|
|
35045
35131
|
var dir = dirname10(loc);
|
|
35046
|
-
var file =
|
|
35132
|
+
var file = basename11(loc);
|
|
35047
35133
|
path4 = this.resolve(dir, file);
|
|
35048
35134
|
}
|
|
35049
35135
|
return path4;
|
|
@@ -35073,7 +35159,7 @@ var require_view = __commonJS({
|
|
|
35073
35159
|
if (stat && stat.isFile()) {
|
|
35074
35160
|
return path4;
|
|
35075
35161
|
}
|
|
35076
|
-
path4 = join23(dir,
|
|
35162
|
+
path4 = join23(dir, basename11(file, ext), "index" + ext);
|
|
35077
35163
|
stat = tryStat(path4);
|
|
35078
35164
|
if (stat && stat.isFile()) {
|
|
35079
35165
|
return path4;
|
|
@@ -38371,10 +38457,8 @@ var require_content_disposition = __commonJS({
|
|
|
38371
38457
|
"use strict";
|
|
38372
38458
|
module.exports = contentDisposition;
|
|
38373
38459
|
module.exports.parse = parse4;
|
|
38374
|
-
var
|
|
38460
|
+
var utf8Decoder = new TextDecoder("utf-8");
|
|
38375
38461
|
var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
|
|
38376
|
-
var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
|
|
38377
|
-
var HEX_ESCAPE_REPLACE_REGEXP = /%([0-9A-Fa-f]{2})/g;
|
|
38378
38462
|
var NON_LATIN1_REGEXP = /[^\x20-\x7e\xa0-\xff]/g;
|
|
38379
38463
|
var QESC_REGEXP = /\\([\u0000-\u007f])/g;
|
|
38380
38464
|
var QUOTE_REGEXP = /([\\"])/g;
|
|
@@ -38406,11 +38490,11 @@ var require_content_disposition = __commonJS({
|
|
|
38406
38490
|
if (typeof fallback === "string" && NON_LATIN1_REGEXP.test(fallback)) {
|
|
38407
38491
|
throw new TypeError("fallback must be ISO-8859-1 string");
|
|
38408
38492
|
}
|
|
38409
|
-
var name =
|
|
38493
|
+
var name = basename11(filename);
|
|
38410
38494
|
var isQuotedString = TEXT_REGEXP.test(name);
|
|
38411
|
-
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) :
|
|
38495
|
+
var fallbackName = typeof fallback !== "string" ? fallback && getlatin1(name) : basename11(fallback);
|
|
38412
38496
|
var hasFallback = typeof fallbackName === "string" && fallbackName !== name;
|
|
38413
|
-
if (hasFallback || !isQuotedString ||
|
|
38497
|
+
if (hasFallback || !isQuotedString || hasHexEscape(name)) {
|
|
38414
38498
|
params["filename*"] = name;
|
|
38415
38499
|
}
|
|
38416
38500
|
if (isQuotedString || hasFallback) {
|
|
@@ -38437,26 +38521,32 @@ var require_content_disposition = __commonJS({
|
|
|
38437
38521
|
return string3;
|
|
38438
38522
|
}
|
|
38439
38523
|
function decodefield(str2) {
|
|
38440
|
-
|
|
38524
|
+
const match = EXT_VALUE_REGEXP.exec(str2);
|
|
38441
38525
|
if (!match) {
|
|
38442
38526
|
throw new TypeError("invalid extended field value");
|
|
38443
38527
|
}
|
|
38444
|
-
|
|
38445
|
-
|
|
38446
|
-
var value;
|
|
38447
|
-
var binary2 = encoded.replace(HEX_ESCAPE_REPLACE_REGEXP, pdecode);
|
|
38528
|
+
const charset = match[1].toLowerCase();
|
|
38529
|
+
const encoded = match[2];
|
|
38448
38530
|
switch (charset) {
|
|
38449
|
-
case "iso-8859-1":
|
|
38450
|
-
|
|
38451
|
-
|
|
38531
|
+
case "iso-8859-1": {
|
|
38532
|
+
const binary2 = decodeHexEscapes(encoded);
|
|
38533
|
+
return getlatin1(binary2);
|
|
38534
|
+
}
|
|
38452
38535
|
case "utf-8":
|
|
38453
|
-
case "utf8":
|
|
38454
|
-
|
|
38455
|
-
|
|
38456
|
-
|
|
38457
|
-
|
|
38536
|
+
case "utf8": {
|
|
38537
|
+
try {
|
|
38538
|
+
return decodeURIComponent(encoded);
|
|
38539
|
+
} catch {
|
|
38540
|
+
const binary2 = decodeHexEscapes(encoded);
|
|
38541
|
+
const bytes = new Uint8Array(binary2.length);
|
|
38542
|
+
for (let idx = 0; idx < binary2.length; idx++) {
|
|
38543
|
+
bytes[idx] = binary2.charCodeAt(idx);
|
|
38544
|
+
}
|
|
38545
|
+
return utf8Decoder.decode(bytes);
|
|
38546
|
+
}
|
|
38547
|
+
}
|
|
38458
38548
|
}
|
|
38459
|
-
|
|
38549
|
+
throw new TypeError("unsupported charset in extended field");
|
|
38460
38550
|
}
|
|
38461
38551
|
function getlatin1(val) {
|
|
38462
38552
|
return String(val).replace(NON_LATIN1_REGEXP, "?");
|
|
@@ -38506,9 +38596,6 @@ var require_content_disposition = __commonJS({
|
|
|
38506
38596
|
}
|
|
38507
38597
|
return new ContentDisposition(type2, params);
|
|
38508
38598
|
}
|
|
38509
|
-
function pdecode(str2, hex) {
|
|
38510
|
-
return String.fromCharCode(parseInt(hex, 16));
|
|
38511
|
-
}
|
|
38512
38599
|
function pencode(char) {
|
|
38513
38600
|
return "%" + String(char).charCodeAt(0).toString(16).toUpperCase();
|
|
38514
38601
|
}
|
|
@@ -38525,6 +38612,51 @@ var require_content_disposition = __commonJS({
|
|
|
38525
38612
|
this.type = type2;
|
|
38526
38613
|
this.parameters = parameters;
|
|
38527
38614
|
}
|
|
38615
|
+
function basename11(path3) {
|
|
38616
|
+
const normalized = path3.replaceAll("\\", "/");
|
|
38617
|
+
let end = normalized.length;
|
|
38618
|
+
while (end > 0 && normalized[end - 1] === "/") {
|
|
38619
|
+
end--;
|
|
38620
|
+
}
|
|
38621
|
+
if (end === 0) {
|
|
38622
|
+
return "";
|
|
38623
|
+
}
|
|
38624
|
+
let start = end - 1;
|
|
38625
|
+
while (start >= 0 && normalized[start] !== "/") {
|
|
38626
|
+
start--;
|
|
38627
|
+
}
|
|
38628
|
+
return normalized.slice(start + 1, end);
|
|
38629
|
+
}
|
|
38630
|
+
function isHexDigit(char) {
|
|
38631
|
+
const code = char.charCodeAt(0);
|
|
38632
|
+
return code >= 48 && code <= 57 || // 0-9
|
|
38633
|
+
code >= 65 && code <= 70 || // A-F
|
|
38634
|
+
code >= 97 && code <= 102;
|
|
38635
|
+
}
|
|
38636
|
+
function hasHexEscape(str2) {
|
|
38637
|
+
const maxIndex = str2.length - 3;
|
|
38638
|
+
let lastIndex = -1;
|
|
38639
|
+
while ((lastIndex = str2.indexOf("%", lastIndex + 1)) !== -1 && lastIndex <= maxIndex) {
|
|
38640
|
+
if (isHexDigit(str2[lastIndex + 1]) && isHexDigit(str2[lastIndex + 2])) {
|
|
38641
|
+
return true;
|
|
38642
|
+
}
|
|
38643
|
+
}
|
|
38644
|
+
return false;
|
|
38645
|
+
}
|
|
38646
|
+
function decodeHexEscapes(str2) {
|
|
38647
|
+
const firstEscape = str2.indexOf("%");
|
|
38648
|
+
if (firstEscape === -1) return str2;
|
|
38649
|
+
let result = str2.slice(0, firstEscape);
|
|
38650
|
+
for (let idx = firstEscape; idx < str2.length; idx++) {
|
|
38651
|
+
if (str2[idx] === "%" && idx + 2 < str2.length && isHexDigit(str2[idx + 1]) && isHexDigit(str2[idx + 2])) {
|
|
38652
|
+
result += String.fromCharCode(Number.parseInt(str2[idx + 1] + str2[idx + 2], 16));
|
|
38653
|
+
idx += 2;
|
|
38654
|
+
} else {
|
|
38655
|
+
result += str2[idx];
|
|
38656
|
+
}
|
|
38657
|
+
}
|
|
38658
|
+
return result;
|
|
38659
|
+
}
|
|
38528
38660
|
}
|
|
38529
38661
|
});
|
|
38530
38662
|
|
|
@@ -38735,7 +38867,7 @@ var require_send = __commonJS({
|
|
|
38735
38867
|
var join23 = path3.join;
|
|
38736
38868
|
var normalize2 = path3.normalize;
|
|
38737
38869
|
var resolve15 = path3.resolve;
|
|
38738
|
-
var
|
|
38870
|
+
var sep5 = path3.sep;
|
|
38739
38871
|
var BYTES_RANGE_REGEXP = /^ *bytes=/;
|
|
38740
38872
|
var MAX_MAXAGE = 60 * 60 * 24 * 365 * 1e3;
|
|
38741
38873
|
var UP_PATH_REGEXP = /(?:^|[\\/])\.\.(?:[\\/]|$)/;
|
|
@@ -38896,14 +39028,14 @@ var require_send = __commonJS({
|
|
|
38896
39028
|
var parts;
|
|
38897
39029
|
if (root !== null) {
|
|
38898
39030
|
if (path4) {
|
|
38899
|
-
path4 = normalize2("." +
|
|
39031
|
+
path4 = normalize2("." + sep5 + path4);
|
|
38900
39032
|
}
|
|
38901
39033
|
if (UP_PATH_REGEXP.test(path4)) {
|
|
38902
39034
|
debug('malicious path "%s"', path4);
|
|
38903
39035
|
this.error(403);
|
|
38904
39036
|
return res;
|
|
38905
39037
|
}
|
|
38906
|
-
parts = path4.split(
|
|
39038
|
+
parts = path4.split(sep5);
|
|
38907
39039
|
path4 = normalize2(join23(root, path4));
|
|
38908
39040
|
} else {
|
|
38909
39041
|
if (UP_PATH_REGEXP.test(path4)) {
|
|
@@ -38911,7 +39043,7 @@ var require_send = __commonJS({
|
|
|
38911
39043
|
this.error(403);
|
|
38912
39044
|
return res;
|
|
38913
39045
|
}
|
|
38914
|
-
parts = normalize2(path4).split(
|
|
39046
|
+
parts = normalize2(path4).split(sep5);
|
|
38915
39047
|
path4 = resolve15(path4);
|
|
38916
39048
|
}
|
|
38917
39049
|
if (containsDotFile(parts)) {
|
|
@@ -39005,7 +39137,7 @@ var require_send = __commonJS({
|
|
|
39005
39137
|
var self2 = this;
|
|
39006
39138
|
debug('stat "%s"', path4);
|
|
39007
39139
|
fs3.stat(path4, function onstat(err, stat) {
|
|
39008
|
-
var pathEndsWithSep = path4[path4.length - 1] ===
|
|
39140
|
+
var pathEndsWithSep = path4[path4.length - 1] === sep5;
|
|
39009
39141
|
if (err && err.code === "ENOENT" && !extname3(path4) && !pathEndsWithSep) {
|
|
39010
39142
|
return next(err);
|
|
39011
39143
|
}
|
|
@@ -40383,8 +40515,8 @@ var require_main = __commonJS({
|
|
|
40383
40515
|
const shortPaths = [];
|
|
40384
40516
|
for (const filePath of optionPaths) {
|
|
40385
40517
|
try {
|
|
40386
|
-
const
|
|
40387
|
-
shortPaths.push(
|
|
40518
|
+
const relative4 = path3.relative(process.cwd(), filePath);
|
|
40519
|
+
shortPaths.push(relative4);
|
|
40388
40520
|
} catch (e) {
|
|
40389
40521
|
if (debug) {
|
|
40390
40522
|
_debug(`failed to load ${filePath} ${e.message}`);
|
|
@@ -40392,7 +40524,7 @@ var require_main = __commonJS({
|
|
|
40392
40524
|
lastError = e;
|
|
40393
40525
|
}
|
|
40394
40526
|
}
|
|
40395
|
-
_log(`
|
|
40527
|
+
_log(`injected env (${keysCount}) from ${shortPaths.join(",")} ${dim(`// tip: ${_getRandomTip()}`)}`);
|
|
40396
40528
|
}
|
|
40397
40529
|
if (lastError) {
|
|
40398
40530
|
return { parsed: parsedAll, error: lastError };
|
|
@@ -172214,8 +172346,8 @@ var require_adm_zip = __commonJS({
|
|
|
172214
172346
|
return null;
|
|
172215
172347
|
}
|
|
172216
172348
|
function fixPath(zipPath) {
|
|
172217
|
-
const { join: join23, normalize: normalize2, sep:
|
|
172218
|
-
return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(
|
|
172349
|
+
const { join: join23, normalize: normalize2, sep: sep5 } = pth.posix;
|
|
172350
|
+
return join23(pth.isAbsolute(zipPath) ? "/" : ".", normalize2(sep5 + zipPath.split("\\").join(sep5) + sep5));
|
|
172219
172351
|
}
|
|
172220
172352
|
function filenameFilter(filterfn) {
|
|
172221
172353
|
if (filterfn instanceof RegExp) {
|
|
@@ -188585,12 +188717,13 @@ init_logger();
|
|
|
188585
188717
|
// src/lib/log-directory-manager.ts
|
|
188586
188718
|
init_temp_dir();
|
|
188587
188719
|
import { mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
|
|
188588
|
-
import { join as join7, resolve as resolve3 } from "path";
|
|
188720
|
+
import { join as join7, resolve as resolve3, sep, relative, isAbsolute as isAbsolute3 } from "path";
|
|
188589
188721
|
import { randomBytes } from "crypto";
|
|
188590
188722
|
function ensurePathWithinBase(baseDir, targetPath) {
|
|
188591
188723
|
const absBase = resolve3(baseDir);
|
|
188592
188724
|
const absTarget = resolve3(targetPath);
|
|
188593
|
-
|
|
188725
|
+
const rel = relative(absBase, absTarget);
|
|
188726
|
+
if (rel === ".." || rel.startsWith(".." + sep) || isAbsolute3(rel)) {
|
|
188594
188727
|
throw new Error(`Provided log directory is outside the allowed base directory: ${absBase}`);
|
|
188595
188728
|
}
|
|
188596
188729
|
return absTarget;
|
|
@@ -188726,7 +188859,7 @@ import { createHash as createHash2 } from "crypto";
|
|
|
188726
188859
|
init_cli_executor();
|
|
188727
188860
|
init_logger();
|
|
188728
188861
|
import { closeSync, fstatSync, mkdirSync as mkdirSync4, openSync, readFileSync as readFileSync5, writeFileSync } from "fs";
|
|
188729
|
-
import { dirname as dirname3, isAbsolute as
|
|
188862
|
+
import { dirname as dirname3, isAbsolute as isAbsolute4 } from "path";
|
|
188730
188863
|
var BUILT_IN_EVALUATORS = {
|
|
188731
188864
|
"json-decode": "JSON format decoder for query results",
|
|
188732
188865
|
"csv-decode": "CSV format decoder for query results",
|
|
@@ -188889,7 +189022,8 @@ ${queryDesc}
|
|
|
188889
189022
|
mermaidContent += "```mermaid\ngraph TD\n A[No Results]\n```\n";
|
|
188890
189023
|
return mermaidContent;
|
|
188891
189024
|
}
|
|
188892
|
-
const
|
|
189025
|
+
const resultsObj = queryResults;
|
|
189026
|
+
const tuples = resultsObj.tuples || queryResults;
|
|
188893
189027
|
if (!Array.isArray(tuples) || tuples.length === 0) {
|
|
188894
189028
|
mermaidContent += "```mermaid\ngraph TD\n A[No Graph Data]\n```\n";
|
|
188895
189029
|
return mermaidContent;
|
|
@@ -188916,9 +189050,10 @@ ${queryDesc}
|
|
|
188916
189050
|
edges.add(edgeId);
|
|
188917
189051
|
}
|
|
188918
189052
|
} else if (typeof tuple === "object" && tuple !== null) {
|
|
188919
|
-
const
|
|
188920
|
-
const
|
|
188921
|
-
const
|
|
189053
|
+
const obj = tuple;
|
|
189054
|
+
const source = sanitizeNodeId(obj.source?.toString() || obj.from?.toString() || `node_${index}_src`);
|
|
189055
|
+
const target = sanitizeNodeId(obj.target?.toString() || obj.to?.toString() || `node_${index}_tgt`);
|
|
189056
|
+
const label = obj.label?.toString() || obj.relation?.toString() || "";
|
|
188922
189057
|
nodes.add(source);
|
|
188923
189058
|
nodes.add(target);
|
|
188924
189059
|
const edgeId = `${source}_${target}`;
|
|
@@ -188979,7 +189114,7 @@ async function evaluateQueryResults(bqrsPath, queryPath, evaluationFunction, out
|
|
|
188979
189114
|
case "mermaid-graph":
|
|
188980
189115
|
return await evaluateWithMermaidGraph(bqrsPath, queryPath, outputPath);
|
|
188981
189116
|
default:
|
|
188982
|
-
if (
|
|
189117
|
+
if (isAbsolute4(evalFunc)) {
|
|
188983
189118
|
return await evaluateWithCustomScript(bqrsPath, queryPath, evalFunc, outputPath);
|
|
188984
189119
|
} else {
|
|
188985
189120
|
return {
|
|
@@ -189396,10 +189531,43 @@ function diffSarifRules(sarifA, sarifB) {
|
|
|
189396
189531
|
unchangedRules
|
|
189397
189532
|
};
|
|
189398
189533
|
}
|
|
189534
|
+
function computeFingerprintOverlap(resultA, resultB) {
|
|
189535
|
+
const fpA = resultA.partialFingerprints;
|
|
189536
|
+
const fpB = resultB.partialFingerprints;
|
|
189537
|
+
if (!fpA || !fpB || Object.keys(fpA).length === 0 || Object.keys(fpB).length === 0) {
|
|
189538
|
+
return {
|
|
189539
|
+
fingerprintMatch: false,
|
|
189540
|
+
overlaps: false,
|
|
189541
|
+
overlapMode: "fingerprint",
|
|
189542
|
+
sharedLocations: []
|
|
189543
|
+
};
|
|
189544
|
+
}
|
|
189545
|
+
const matchedFingerprints = {};
|
|
189546
|
+
for (const key of Object.keys(fpA)) {
|
|
189547
|
+
if (key in fpB && fpA[key] === fpB[key]) {
|
|
189548
|
+
matchedFingerprints[key] = fpA[key];
|
|
189549
|
+
}
|
|
189550
|
+
}
|
|
189551
|
+
const hasMatch = Object.keys(matchedFingerprints).length > 0;
|
|
189552
|
+
return {
|
|
189553
|
+
fingerprintMatch: hasMatch,
|
|
189554
|
+
matchedFingerprints: hasMatch ? matchedFingerprints : void 0,
|
|
189555
|
+
overlaps: hasMatch,
|
|
189556
|
+
overlapMode: "fingerprint",
|
|
189557
|
+
sharedLocations: []
|
|
189558
|
+
};
|
|
189559
|
+
}
|
|
189399
189560
|
function computeLocationOverlap(resultA, resultB, mode = "sink") {
|
|
189400
189561
|
let locsA;
|
|
189401
189562
|
let locsB;
|
|
189402
189563
|
switch (mode) {
|
|
189564
|
+
case "fingerprint": {
|
|
189565
|
+
const fpResult = computeFingerprintOverlap(resultA, resultB);
|
|
189566
|
+
if (fpResult.fingerprintMatch) {
|
|
189567
|
+
return fpResult;
|
|
189568
|
+
}
|
|
189569
|
+
return computeLocationOverlap(resultA, resultB, "full-path");
|
|
189570
|
+
}
|
|
189403
189571
|
case "sink":
|
|
189404
189572
|
locsA = extractPrimaryLocations(resultA);
|
|
189405
189573
|
locsB = extractPrimaryLocations(resultB);
|
|
@@ -189439,6 +189607,99 @@ function computeLocationOverlap(resultA, resultB, mode = "sink") {
|
|
|
189439
189607
|
sharedLocations: shared
|
|
189440
189608
|
};
|
|
189441
189609
|
}
|
|
189610
|
+
function findOverlappingAlerts(resultsA, ruleA, resultsB, ruleB, mode = "sink") {
|
|
189611
|
+
const overlaps = [];
|
|
189612
|
+
for (let i = 0; i < resultsA.length; i++) {
|
|
189613
|
+
for (let j = 0; j < resultsB.length; j++) {
|
|
189614
|
+
const overlapDetails = computeLocationOverlap(resultsA[i], resultsB[j], mode);
|
|
189615
|
+
if (overlapDetails.overlaps) {
|
|
189616
|
+
overlaps.push({
|
|
189617
|
+
overlapDetails,
|
|
189618
|
+
resultA: resultsA[i],
|
|
189619
|
+
resultAIndex: i,
|
|
189620
|
+
resultB: resultsB[j],
|
|
189621
|
+
resultBIndex: j,
|
|
189622
|
+
ruleIdA: ruleA.id,
|
|
189623
|
+
ruleIdB: ruleB.id
|
|
189624
|
+
});
|
|
189625
|
+
}
|
|
189626
|
+
}
|
|
189627
|
+
}
|
|
189628
|
+
return overlaps;
|
|
189629
|
+
}
|
|
189630
|
+
function lineInHunks(line, hunks) {
|
|
189631
|
+
for (const hunk of hunks) {
|
|
189632
|
+
const hunkEnd = hunk.startLine + Math.max(hunk.lineCount - 1, 0);
|
|
189633
|
+
if (line >= hunk.startLine && line <= hunkEnd) {
|
|
189634
|
+
return true;
|
|
189635
|
+
}
|
|
189636
|
+
}
|
|
189637
|
+
return false;
|
|
189638
|
+
}
|
|
189639
|
+
function diffSarifByCommits(sarif, diffFiles, refRange, granularity = "file") {
|
|
189640
|
+
const results = sarif.runs[0]?.results ?? [];
|
|
189641
|
+
const newResults = [];
|
|
189642
|
+
const preExistingResults = [];
|
|
189643
|
+
const normalizedDiffEntries = diffFiles.map((df) => ({
|
|
189644
|
+
entry: df,
|
|
189645
|
+
normalized: normalizeUri(df.path)
|
|
189646
|
+
}));
|
|
189647
|
+
for (let i = 0; i < results.length; i++) {
|
|
189648
|
+
const result = results[i];
|
|
189649
|
+
const primaryLoc = result.locations?.[0]?.physicalLocation;
|
|
189650
|
+
const uri = primaryLoc?.artifactLocation?.uri;
|
|
189651
|
+
if (!uri) {
|
|
189652
|
+
preExistingResults.push({
|
|
189653
|
+
file: "<unknown>",
|
|
189654
|
+
resultIndex: i,
|
|
189655
|
+
ruleId: result.ruleId
|
|
189656
|
+
});
|
|
189657
|
+
continue;
|
|
189658
|
+
}
|
|
189659
|
+
const startLine = primaryLoc?.region?.startLine;
|
|
189660
|
+
const normalizedUri = normalizeUri(uri);
|
|
189661
|
+
let matchingDiff;
|
|
189662
|
+
for (const { entry, normalized } of normalizedDiffEntries) {
|
|
189663
|
+
if (normalized === normalizedUri || normalized.endsWith(normalizedUri) || normalizedUri.endsWith(normalized)) {
|
|
189664
|
+
matchingDiff = entry;
|
|
189665
|
+
break;
|
|
189666
|
+
}
|
|
189667
|
+
}
|
|
189668
|
+
let isNew = false;
|
|
189669
|
+
if (matchingDiff) {
|
|
189670
|
+
if (granularity === "file") {
|
|
189671
|
+
isNew = true;
|
|
189672
|
+
} else if (startLine !== void 0 && matchingDiff.hunks.length > 0) {
|
|
189673
|
+
isNew = lineInHunks(startLine, matchingDiff.hunks);
|
|
189674
|
+
} else if (matchingDiff.hunks.length === 0 && !matchingDiff.hunksParsed) {
|
|
189675
|
+
isNew = true;
|
|
189676
|
+
}
|
|
189677
|
+
}
|
|
189678
|
+
const classified = {
|
|
189679
|
+
file: matchingDiff ? matchingDiff.path : normalizedUri,
|
|
189680
|
+
line: startLine,
|
|
189681
|
+
resultIndex: i,
|
|
189682
|
+
ruleId: result.ruleId
|
|
189683
|
+
};
|
|
189684
|
+
if (isNew) {
|
|
189685
|
+
newResults.push(classified);
|
|
189686
|
+
} else {
|
|
189687
|
+
preExistingResults.push(classified);
|
|
189688
|
+
}
|
|
189689
|
+
}
|
|
189690
|
+
return {
|
|
189691
|
+
granularity,
|
|
189692
|
+
newResults,
|
|
189693
|
+
preExistingResults,
|
|
189694
|
+
summary: {
|
|
189695
|
+
diffFileCount: diffFiles.length,
|
|
189696
|
+
refRange,
|
|
189697
|
+
totalNew: newResults.length,
|
|
189698
|
+
totalPreExisting: preExistingResults.length,
|
|
189699
|
+
totalResults: results.length
|
|
189700
|
+
}
|
|
189701
|
+
};
|
|
189702
|
+
}
|
|
189442
189703
|
|
|
189443
189704
|
// src/lib/session-data-manager.ts
|
|
189444
189705
|
init_temp_dir();
|
|
@@ -190314,8 +190575,8 @@ var MonitoringConfigSchema = external_exports.object({
|
|
|
190314
190575
|
enableRecommendations: external_exports.boolean().default(true),
|
|
190315
190576
|
enableMonitoringTools: external_exports.boolean().default(false),
|
|
190316
190577
|
// Opt-in: session_* tools disabled by default for end-users
|
|
190317
|
-
enableAnnotationTools: external_exports.boolean().default(
|
|
190318
|
-
//
|
|
190578
|
+
enableAnnotationTools: external_exports.boolean().default(true)
|
|
190579
|
+
// Controls auto-caching behaviour in result-processor; tools are always registered
|
|
190319
190580
|
});
|
|
190320
190581
|
|
|
190321
190582
|
// src/lib/session-data-manager.ts
|
|
@@ -190602,7 +190863,7 @@ function parseBoolEnv(envVar, defaultValue) {
|
|
|
190602
190863
|
var sessionDataManager = new SessionDataManager({
|
|
190603
190864
|
storageLocation: process.env.MONITORING_STORAGE_LOCATION || join9(getProjectTmpBase(), ".ql-mcp-tracking"),
|
|
190604
190865
|
enableMonitoringTools: parseBoolEnv(process.env.ENABLE_MONITORING_TOOLS, false),
|
|
190605
|
-
enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS,
|
|
190866
|
+
enableAnnotationTools: parseBoolEnv(process.env.ENABLE_ANNOTATION_TOOLS, true)
|
|
190606
190867
|
});
|
|
190607
190868
|
|
|
190608
190869
|
// src/lib/result-processor.ts
|
|
@@ -190633,12 +190894,12 @@ function getDefaultExtension(format) {
|
|
|
190633
190894
|
return ".txt";
|
|
190634
190895
|
}
|
|
190635
190896
|
}
|
|
190636
|
-
async function interpretBQRSFile(bqrsPath, queryPath, format, outputPath, logger2) {
|
|
190897
|
+
async function interpretBQRSFile(bqrsPath, queryPath, format, outputPath, logger2, metadata) {
|
|
190637
190898
|
try {
|
|
190638
|
-
const
|
|
190899
|
+
const queryMetadata = metadata ?? await extractQueryMetadata(queryPath);
|
|
190639
190900
|
const missingFields = [];
|
|
190640
|
-
if (!
|
|
190641
|
-
if (!
|
|
190901
|
+
if (!queryMetadata.id) missingFields.push("id");
|
|
190902
|
+
if (!queryMetadata.kind) missingFields.push("kind");
|
|
190642
190903
|
if (missingFields.length > 0) {
|
|
190643
190904
|
return {
|
|
190644
190905
|
error: `Query metadata is incomplete. Missing required field(s): ${missingFields.join(", ")}. Ensure the query file contains @id and @kind metadata.`,
|
|
@@ -190648,12 +190909,12 @@ async function interpretBQRSFile(bqrsPath, queryPath, format, outputPath, logger
|
|
|
190648
190909
|
success: false
|
|
190649
190910
|
};
|
|
190650
190911
|
}
|
|
190651
|
-
const sanitizedId = (
|
|
190652
|
-
const sanitizedKind = (
|
|
190912
|
+
const sanitizedId = (queryMetadata.id || "").replace(/[^a-zA-Z0-9_/:-]/g, "");
|
|
190913
|
+
const sanitizedKind = (queryMetadata.kind || "").replace(/[^a-zA-Z0-9_-]/g, "");
|
|
190653
190914
|
const graphFormats = ["graphtext", "dgml", "dot"];
|
|
190654
|
-
if (graphFormats.includes(format) &&
|
|
190915
|
+
if (graphFormats.includes(format) && queryMetadata.kind !== "graph") {
|
|
190655
190916
|
return {
|
|
190656
|
-
error: `Format '${format}' is only compatible with @kind graph queries, but this query has @kind ${
|
|
190917
|
+
error: `Format '${format}' is only compatible with @kind graph queries, but this query has @kind ${queryMetadata.kind}`,
|
|
190657
190918
|
exitCode: 1,
|
|
190658
190919
|
stderr: "",
|
|
190659
190920
|
stdout: "",
|
|
@@ -190691,9 +190952,6 @@ async function processQueryRunResults(result, params, logger2) {
|
|
|
190691
190952
|
queryLanguage,
|
|
190692
190953
|
queryName
|
|
190693
190954
|
} = params;
|
|
190694
|
-
if (!format && !evaluationFunction) {
|
|
190695
|
-
return result;
|
|
190696
|
-
}
|
|
190697
190955
|
if (!output) {
|
|
190698
190956
|
return result;
|
|
190699
190957
|
}
|
|
@@ -190704,6 +190962,28 @@ async function processQueryRunResults(result, params, logger2) {
|
|
|
190704
190962
|
} else if (!queryPath && queryName && queryLanguage) {
|
|
190705
190963
|
queryPath = await resolveQueryPath(params, logger2);
|
|
190706
190964
|
}
|
|
190965
|
+
let effectiveFormat = format;
|
|
190966
|
+
let queryMetadata;
|
|
190967
|
+
if (queryPath) {
|
|
190968
|
+
try {
|
|
190969
|
+
queryMetadata = await extractQueryMetadata(queryPath);
|
|
190970
|
+
} catch (metaErr) {
|
|
190971
|
+
logger2.error("Failed to extract query metadata:", metaErr);
|
|
190972
|
+
}
|
|
190973
|
+
}
|
|
190974
|
+
if (!effectiveFormat && !evaluationFunction && queryMetadata) {
|
|
190975
|
+
if (queryMetadata.kind === "problem" || queryMetadata.kind === "path-problem") {
|
|
190976
|
+
effectiveFormat = "sarif-latest";
|
|
190977
|
+
} else if (queryMetadata.kind === "graph") {
|
|
190978
|
+
effectiveFormat = "graphtext";
|
|
190979
|
+
}
|
|
190980
|
+
if (effectiveFormat) {
|
|
190981
|
+
logger2.info(`No format specified; defaulting to '${effectiveFormat}' for @kind ${queryMetadata.kind} query`);
|
|
190982
|
+
}
|
|
190983
|
+
}
|
|
190984
|
+
if (!effectiveFormat && !evaluationFunction) {
|
|
190985
|
+
return result;
|
|
190986
|
+
}
|
|
190707
190987
|
if (!queryPath) {
|
|
190708
190988
|
logger2.error("Cannot determine query path for interpretation/evaluation");
|
|
190709
190989
|
return {
|
|
@@ -190711,15 +190991,15 @@ async function processQueryRunResults(result, params, logger2) {
|
|
|
190711
190991
|
stdout: result.stdout + "\n\nWarning: Query interpretation skipped - could not determine query path"
|
|
190712
190992
|
};
|
|
190713
190993
|
}
|
|
190714
|
-
if (
|
|
190715
|
-
const outputFormat =
|
|
190994
|
+
if (effectiveFormat) {
|
|
190995
|
+
const outputFormat = effectiveFormat;
|
|
190716
190996
|
let outputFilePath = interpretedOutput;
|
|
190717
190997
|
if (!outputFilePath) {
|
|
190718
190998
|
const ext = getDefaultExtension(outputFormat);
|
|
190719
190999
|
outputFilePath = bqrsPath.replace(".bqrs", ext);
|
|
190720
191000
|
}
|
|
190721
191001
|
logger2.info(`Interpreting query results from ${bqrsPath} with format: ${outputFormat}`);
|
|
190722
|
-
const interpretResult = await interpretBQRSFile(bqrsPath, queryPath, outputFormat, outputFilePath, logger2);
|
|
191002
|
+
const interpretResult = await interpretBQRSFile(bqrsPath, queryPath, outputFormat, outputFilePath, logger2, queryMetadata);
|
|
190723
191003
|
if (interpretResult.success) {
|
|
190724
191004
|
let enhancedOutput = result.stdout;
|
|
190725
191005
|
enhancedOutput += `
|
|
@@ -190932,7 +191212,7 @@ function cacheDatabaseAnalyzeResults(params, logger2) {
|
|
|
190932
191212
|
// src/lib/cli-tool-registry.ts
|
|
190933
191213
|
init_package_paths();
|
|
190934
191214
|
import { existsSync as existsSync6, mkdirSync as mkdirSync8, realpathSync, rmSync, writeFileSync as writeFileSync4 } from "fs";
|
|
190935
|
-
import { delimiter as delimiter5, dirname as dirname5, isAbsolute as
|
|
191215
|
+
import { basename as basename5, delimiter as delimiter5, dirname as dirname5, isAbsolute as isAbsolute5, join as join10, resolve as resolve4 } from "path";
|
|
190936
191216
|
|
|
190937
191217
|
// ../node_modules/js-yaml/dist/js-yaml.mjs
|
|
190938
191218
|
function isNothing(subject) {
|
|
@@ -193711,12 +193991,12 @@ function registerCLITool(server, definition) {
|
|
|
193711
193991
|
if (tests && Array.isArray(tests)) {
|
|
193712
193992
|
const userDir = getUserWorkspaceDir();
|
|
193713
193993
|
positionalArgs = [...positionalArgs, ...tests.map(
|
|
193714
|
-
(t) =>
|
|
193994
|
+
(t) => isAbsolute5(t) ? t : resolve4(userDir, t)
|
|
193715
193995
|
)];
|
|
193716
193996
|
}
|
|
193717
193997
|
break;
|
|
193718
193998
|
case "codeql_query_run": {
|
|
193719
|
-
if (options.database && typeof options.database === "string" && !
|
|
193999
|
+
if (options.database && typeof options.database === "string" && !isAbsolute5(options.database)) {
|
|
193720
194000
|
options.database = resolve4(getUserWorkspaceDir(), options.database);
|
|
193721
194001
|
logger.info(`Resolved database path to: ${options.database}`);
|
|
193722
194002
|
}
|
|
@@ -193836,6 +194116,19 @@ function registerCLITool(server, definition) {
|
|
|
193836
194116
|
break;
|
|
193837
194117
|
}
|
|
193838
194118
|
case "codeql_query_compile":
|
|
194119
|
+
if (query) {
|
|
194120
|
+
positionalArgs = [...positionalArgs, query];
|
|
194121
|
+
}
|
|
194122
|
+
if (options["dump-dil"] === void 0) {
|
|
194123
|
+
const pending = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
|
|
194124
|
+
const hasDilOverride = pending.some(
|
|
194125
|
+
(arg) => arg === "--no-dump-dil" || arg === "--dump-dil"
|
|
194126
|
+
);
|
|
194127
|
+
if (!hasDilOverride) {
|
|
194128
|
+
options["dump-dil"] = true;
|
|
194129
|
+
}
|
|
194130
|
+
}
|
|
194131
|
+
break;
|
|
193839
194132
|
case "codeql_resolve_metadata":
|
|
193840
194133
|
if (query) {
|
|
193841
194134
|
positionalArgs = [...positionalArgs, query];
|
|
@@ -193885,8 +194178,25 @@ function registerCLITool(server, definition) {
|
|
|
193885
194178
|
mkdirSync8(outputDir, { recursive: true });
|
|
193886
194179
|
}
|
|
193887
194180
|
}
|
|
193888
|
-
|
|
194181
|
+
let effectiveDumpDilEnabled = false;
|
|
194182
|
+
let rawAdditionalArgs = Array.isArray(options.additionalArgs) ? options.additionalArgs : [];
|
|
193889
194183
|
delete options.additionalArgs;
|
|
194184
|
+
if (name === "codeql_query_compile") {
|
|
194185
|
+
const lastDumpDilFlag = [...rawAdditionalArgs].reverse().find(
|
|
194186
|
+
(arg) => arg === "--dump-dil" || arg === "--no-dump-dil"
|
|
194187
|
+
);
|
|
194188
|
+
if (lastDumpDilFlag === "--dump-dil") {
|
|
194189
|
+
options["dump-dil"] = true;
|
|
194190
|
+
} else if (lastDumpDilFlag === "--no-dump-dil") {
|
|
194191
|
+
options["dump-dil"] = false;
|
|
194192
|
+
}
|
|
194193
|
+
if (lastDumpDilFlag !== void 0) {
|
|
194194
|
+
rawAdditionalArgs = rawAdditionalArgs.filter(
|
|
194195
|
+
(arg) => arg !== "--dump-dil" && arg !== "--no-dump-dil"
|
|
194196
|
+
);
|
|
194197
|
+
}
|
|
194198
|
+
effectiveDumpDilEnabled = options["dump-dil"] !== false;
|
|
194199
|
+
}
|
|
193890
194200
|
const managedFlagNames = /* @__PURE__ */ new Set([
|
|
193891
194201
|
"evaluator-log",
|
|
193892
194202
|
"logdir",
|
|
@@ -193918,7 +194228,7 @@ function registerCLITool(server, definition) {
|
|
|
193918
194228
|
let cwd;
|
|
193919
194229
|
if ((name === "codeql_pack_install" || name === "codeql_pack_ls") && (dir || packDir)) {
|
|
193920
194230
|
const rawCwd = dir || packDir;
|
|
193921
|
-
cwd =
|
|
194231
|
+
cwd = isAbsolute5(rawCwd) ? rawCwd : resolve4(getUserWorkspaceDir(), rawCwd);
|
|
193922
194232
|
}
|
|
193923
194233
|
const defaultExamplesPath = resolve4(packageRootDir, "ql", "javascript", "examples");
|
|
193924
194234
|
const additionalPacksPath = process.env.CODEQL_ADDITIONAL_PACKS || (existsSync6(defaultExamplesPath) ? defaultExamplesPath : void 0);
|
|
@@ -193980,7 +194290,36 @@ function registerCLITool(server, definition) {
|
|
|
193980
194290
|
const resolvedDb = typeof params.database === "string" ? resolveDatabasePath(params.database) : params.database;
|
|
193981
194291
|
cacheDatabaseAnalyzeResults({ ...params, database: resolvedDb, output: options.output, format: options.format }, logger);
|
|
193982
194292
|
}
|
|
193983
|
-
|
|
194293
|
+
let dilFilePath;
|
|
194294
|
+
if (name === "codeql_query_compile" && result.success && effectiveDumpDilEnabled && result.stdout) {
|
|
194295
|
+
try {
|
|
194296
|
+
const compileLogDir = getOrCreateLogDirectory(customLogDir);
|
|
194297
|
+
logger.info(`Using log directory for ${name}: ${compileLogDir}`);
|
|
194298
|
+
const queryBaseName = query ? basename5(query, ".ql") : "query";
|
|
194299
|
+
dilFilePath = join10(compileLogDir, `${queryBaseName}.dil`);
|
|
194300
|
+
writeFileSync4(dilFilePath, result.stdout, "utf8");
|
|
194301
|
+
logger.info(`Saved DIL output to ${dilFilePath}`);
|
|
194302
|
+
} catch (dilError) {
|
|
194303
|
+
logger.warn(`Failed to save DIL output: ${dilError}`);
|
|
194304
|
+
dilFilePath = void 0;
|
|
194305
|
+
}
|
|
194306
|
+
}
|
|
194307
|
+
let processedResult;
|
|
194308
|
+
if (dilFilePath) {
|
|
194309
|
+
const stdoutBytes = Buffer.byteLength(result.stdout ?? "", "utf8");
|
|
194310
|
+
processedResult = `Compiled successfully. DIL output written to file (${stdoutBytes} bytes).`;
|
|
194311
|
+
if (result.stderr) {
|
|
194312
|
+
processedResult += `
|
|
194313
|
+
|
|
194314
|
+
Warnings/Info:
|
|
194315
|
+
${result.stderr}`;
|
|
194316
|
+
}
|
|
194317
|
+
processedResult += `
|
|
194318
|
+
|
|
194319
|
+
DIL file: ${dilFilePath}`;
|
|
194320
|
+
} else {
|
|
194321
|
+
processedResult = resultProcessor(result, params);
|
|
194322
|
+
}
|
|
193984
194323
|
return {
|
|
193985
194324
|
content: [{
|
|
193986
194325
|
type: "text",
|
|
@@ -195252,7 +195591,7 @@ var codeqlPackLsTool = {
|
|
|
195252
195591
|
|
|
195253
195592
|
// src/tools/codeql/profile-codeql-query-from-logs.ts
|
|
195254
195593
|
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
|
|
195255
|
-
import { basename as
|
|
195594
|
+
import { basename as basename7, dirname as dirname7, join as join15 } from "path";
|
|
195256
195595
|
|
|
195257
195596
|
// src/lib/evaluator-log-parser.ts
|
|
195258
195597
|
init_logger();
|
|
@@ -195584,7 +195923,7 @@ function buildDetailFile(profile, topN) {
|
|
|
195584
195923
|
lines.push("");
|
|
195585
195924
|
for (let qIdx = 0; qIdx < profile.queries.length; qIdx++) {
|
|
195586
195925
|
const query = profile.queries[qIdx];
|
|
195587
|
-
const qName =
|
|
195926
|
+
const qName = basename7(query.queryName);
|
|
195588
195927
|
lines.push(`== Query: ${qName} ==`);
|
|
195589
195928
|
lines.push(` Total: ${query.totalDurationMs.toFixed(2)}ms | Predicates evaluated: ${query.predicateCount} | Cache hits: ${query.cacheHits}`);
|
|
195590
195929
|
lines.push("");
|
|
@@ -195743,7 +196082,7 @@ init_cli_executor();
|
|
|
195743
196082
|
init_logger();
|
|
195744
196083
|
import { writeFileSync as writeFileSync6, existsSync as existsSync12 } from "fs";
|
|
195745
196084
|
import { createReadStream as createReadStream2 } from "fs";
|
|
195746
|
-
import { join as join16, dirname as dirname8, basename as
|
|
196085
|
+
import { join as join16, dirname as dirname8, basename as basename8 } from "path";
|
|
195747
196086
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
195748
196087
|
import { createInterface as createInterface2 } from "readline";
|
|
195749
196088
|
async function parseEvaluatorLog2(logPath) {
|
|
@@ -195869,7 +196208,7 @@ function formatAsMermaid(profile) {
|
|
|
195869
196208
|
lines.push("```mermaid");
|
|
195870
196209
|
lines.push("graph TD");
|
|
195871
196210
|
lines.push("");
|
|
195872
|
-
lines.push(` QUERY["${
|
|
196211
|
+
lines.push(` QUERY["${basename8(profile.queryName)}<br/>Total: ${profile.totalDuration.toFixed(2)}ms"]`);
|
|
195873
196212
|
lines.push("");
|
|
195874
196213
|
profile.pipelines.forEach((pipeline) => {
|
|
195875
196214
|
const nodeId = `P${pipeline.eventId}`;
|
|
@@ -196000,7 +196339,7 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
196000
196339
|
...outputFiles.map((f) => ` - ${f}`),
|
|
196001
196340
|
"",
|
|
196002
196341
|
"Profile Summary:",
|
|
196003
|
-
` - Query: ${
|
|
196342
|
+
` - Query: ${basename8(profile.queryName)}`,
|
|
196004
196343
|
` - Total Duration: ${profile.totalDuration.toFixed(2)} ms`,
|
|
196005
196344
|
` - Total Pipelines: ${profile.pipelines.length}`,
|
|
196006
196345
|
` - Total Events: ${profile.totalEvents}`,
|
|
@@ -196037,13 +196376,15 @@ function registerProfileCodeQLQueryTool(server) {
|
|
|
196037
196376
|
// src/tools/codeql/query-compile.ts
|
|
196038
196377
|
var codeqlQueryCompileTool = {
|
|
196039
196378
|
name: "codeql_query_compile",
|
|
196040
|
-
description: "Compile and validate CodeQL queries",
|
|
196379
|
+
description: "Compile and validate CodeQL queries. By default, produces a .dil file containing the optimized DIL intermediate representation alongside the compilation output.",
|
|
196041
196380
|
command: "codeql",
|
|
196042
196381
|
subcommand: "query compile",
|
|
196043
196382
|
inputSchema: {
|
|
196044
196383
|
query: external_exports.string().describe("Path to the CodeQL query file (.ql)"),
|
|
196045
196384
|
database: external_exports.string().optional().describe("Path to the CodeQL database"),
|
|
196385
|
+
"dump-dil": external_exports.boolean().optional().describe("Print the optimized DIL intermediate representation to standard output while compiling. Enabled by default; pass false or --no-dump-dil to disable."),
|
|
196046
196386
|
library: external_exports.string().optional().describe("Path to query library"),
|
|
196387
|
+
logDir: external_exports.string().optional().describe("Custom directory for compilation DIL output (overrides CODEQL_QUERY_LOG_DIR environment variable). If not provided, uses CODEQL_QUERY_LOG_DIR or defaults to .tmp/query-logs/<unique-id>"),
|
|
196047
196388
|
output: external_exports.string().optional().describe("Output file path"),
|
|
196048
196389
|
warnings: external_exports.enum(["hide", "show", "error"]).optional().describe("How to handle compilation warnings"),
|
|
196049
196390
|
verbose: external_exports.boolean().optional().describe("Enable verbose output"),
|
|
@@ -196051,6 +196392,7 @@ var codeqlQueryCompileTool = {
|
|
|
196051
196392
|
},
|
|
196052
196393
|
examples: [
|
|
196053
196394
|
"codeql query compile --database=/path/to/db MyQuery.ql",
|
|
196395
|
+
"codeql query compile --dump-dil --database=/path/to/db MyQuery.ql",
|
|
196054
196396
|
"codeql query compile --library=/path/to/lib --output=compiled.qlo MyQuery.ql"
|
|
196055
196397
|
]
|
|
196056
196398
|
};
|
|
@@ -196699,7 +197041,7 @@ var codeqlResolveTestsTool = {
|
|
|
196699
197041
|
|
|
196700
197042
|
// src/tools/codeql/search-ql-code.ts
|
|
196701
197043
|
import { closeSync as closeSync2, createReadStream as createReadStream3, fstatSync as fstatSync2, lstatSync, openSync as openSync2, readdirSync as readdirSync8, readFileSync as readFileSync12, realpathSync as realpathSync2 } from "fs";
|
|
196702
|
-
import { basename as
|
|
197044
|
+
import { basename as basename9, extname as extname2, join as join19, resolve as resolve9 } from "path";
|
|
196703
197045
|
import { createInterface as createInterface3 } from "readline";
|
|
196704
197046
|
|
|
196705
197047
|
// src/lib/scan-exclude.ts
|
|
@@ -196747,10 +197089,13 @@ var MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;
|
|
|
196747
197089
|
var MAX_FILES_TRAVERSED = 1e4;
|
|
196748
197090
|
var MAX_CONTEXT_LINES = 50;
|
|
196749
197091
|
var MAX_MAX_RESULTS = 1e4;
|
|
196750
|
-
|
|
197092
|
+
function getSkipDirs() {
|
|
197093
|
+
return getScanExcludeDirs();
|
|
197094
|
+
}
|
|
196751
197095
|
function collectFiles(paths, extensions, fileCount) {
|
|
196752
197096
|
const files = [];
|
|
196753
197097
|
const visitedDirs = /* @__PURE__ */ new Set();
|
|
197098
|
+
const skipDirs = getSkipDirs();
|
|
196754
197099
|
function walk(p) {
|
|
196755
197100
|
if (fileCount.value >= MAX_FILES_TRAVERSED) return;
|
|
196756
197101
|
let stat;
|
|
@@ -196766,7 +197111,7 @@ function collectFiles(paths, extensions, fileCount) {
|
|
|
196766
197111
|
}
|
|
196767
197112
|
fileCount.value++;
|
|
196768
197113
|
} else if (stat.isDirectory()) {
|
|
196769
|
-
if (
|
|
197114
|
+
if (skipDirs.has(basename9(p))) return;
|
|
196770
197115
|
let realPath;
|
|
196771
197116
|
try {
|
|
196772
197117
|
realPath = realpathSync2(p);
|
|
@@ -197282,6 +197627,9 @@ function registerCodeQLTools(server) {
|
|
|
197282
197627
|
registerSearchQlCodeTool(server);
|
|
197283
197628
|
}
|
|
197284
197629
|
|
|
197630
|
+
// src/resources/learning-data-extensions.md
|
|
197631
|
+
var learning_data_extensions_default = "# CodeQL Data Extensions Overview\n\n## Purpose\n\nData extensions (Models-as-Data / MaD) let you customize CodeQL's taint tracking and data-flow analysis for third-party libraries and frameworks \u2014 without writing QL code. You author YAML files that declare which functions are sources, sinks, summaries, barriers, barrier guards, or neutral.\n\nFor language-specific guidance, see the per-language library-modeling resources at `codeql://languages/{language}/library-modeling`.\n\n## When to Use Data Extensions\n\nUse data extensions when:\n\n- A library is **not modeled** by the default CodeQL packs and you need taint to flow through its APIs\n- You want to **add new sinks** for a framework that CodeQL does not cover out of the box\n- You want to **reduce false positives** by marking sanitizers (barriers) or validation checks (barrier guards)\n- You want to **reduce false negatives** by adding flow summaries for data-passing functions\n\nUse a custom QL query instead when:\n\n- You need complex control-flow reasoning beyond what access paths can express\n- You need to correlate multiple call sites or match structural patterns that MaD cannot describe\n\n## Two Model Formats\n\nCodeQL uses two distinct formats depending on the language. The choice is fixed per language \u2014 you cannot mix formats. For authoritative language-specific details, see `codeql://languages/{language}/library-modeling`.\n\n### MaD Tuple Format (9\u201310 Column Tuples)\n\n**Languages**: C/C++, C#, Go, Java/Kotlin, Swift\n\nIdentifies callables by **package/namespace, type, method name, and signature**. Each row is a tuple of 9\u201310 string columns.\n\n> **Rust** uses a distinct crate-path-based format that does not match either the tuple or API-graph layout described here. Consult `codeql://languages/rust/library-modeling` for the Rust-specific column layout.\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/<language>-all\n extensible: sinkModel\n data:\n - [\n 'package',\n 'Type',\n True,\n 'methodName',\n '(Signature)',\n '',\n 'Argument[0]',\n 'sql-injection',\n 'manual'\n ]\n```\n\n| Column | Description |\n| ----------------------- | ------------------------------------------------------------------------- |\n| `package` / `namespace` | Fully qualified package or namespace path |\n| `type` | Class or type name (`\"\"` for free functions) |\n| `subtypes` | `True` to include subclass overrides; `False` for exact match only |\n| `name` | Method or function name |\n| `signature` | Parameter type signature (`\"\"` to match all overloads) |\n| `ext` | Reserved \u2014 always `\"\"` |\n| `input` / `output` | Access path (see below) |\n| `kind` | Source/sink/summary kind (e.g., `\"sql-injection\"`, `\"taint\"`, `\"remote\"`) |\n| `provenance` | Origin marker \u2014 use `\"manual\"` for hand-written models |\n\n### API Graph Format (3\u20135 Column Tuples)\n\n**Languages**: JavaScript/TypeScript, Python, Ruby\n\nIdentifies callables by **package name and access path** through the API graph. Tuples are shorter (3\u20135 columns).\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/<language>-all\n extensible: sinkModel\n data:\n - ['package-name', 'Member[method].Argument[0]', 'sql-injection']\n```\n\n| Column | Description |\n| ------ | ------------------------------------------------- |\n| `type` | Package or module name, class name, or `\"global\"` |\n| `path` | Dot-separated API graph access path |\n| `kind` | Source/sink kind |\n\nFor `summaryModel`, two additional columns specify `input` and `output` access paths.\n\n## YAML Structure\n\nAll data extension files use the same top-level structure:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/<language>-all # Target pack\n extensible: <predicate-name> # e.g., sourceModel, sinkModel\n data:\n - <tuple1>\n - <tuple2>\n```\n\nMultiple `addsTo` blocks can appear in a single file. Multiple YAML files are combined using union semantics \u2014 rows merge across files and duplicates are automatically removed.\n\n## Extensible Predicates\n\n| Predicate | Purpose | Available In |\n| ------------------- | ---------------------------------------------------------------- | ------------------------------ |\n| `sourceModel` | Define sources of untrusted data (e.g., HTTP request parameters) | All languages |\n| `sinkModel` | Define dangerous operations (e.g., SQL query execution) | All languages |\n| `summaryModel` | Define how data flows through a function (input \u2192 output) | All languages |\n| `barrierModel` | Define sanitizers that stop taint flow (e.g., HTML-escaping) | All languages (CodeQL 2.25.2+) |\n| `barrierGuardModel` | Define validators that stop taint via conditional checks | All languages (CodeQL 2.25.2+) |\n| `neutralModel` | Mark functions as having no dataflow impact (reduces noise) | MaD tuple languages + Python |\n| `typeModel` | Define type relationships for untyped code | API Graph languages only |\n\n## Common Access Path Components\n\n### MaD Tuple Languages\n\n| Component | Description |\n| --------------------- | ----------------------------------------------------- |\n| `Argument[n]` | Argument at index n (0-based) |\n| `Argument[this]` | The receiver/qualifier of a method call |\n| `Argument[receiver]` | The receiver (Go-specific, replaces `Argument[this]`) |\n| `Argument[n1..n2]` | Range of arguments |\n| `ReturnValue` | Return value of the function |\n| `ReturnValue[n]` | The nth return value (Go only, 0-indexed) |\n| `Field[name]` | Named field of a struct/class |\n| `Element` | Elements of a collection |\n| `ArrayElement` | Elements of an array/slice |\n| `MapKey` / `MapValue` | Key or value of a map |\n| `Parameter[n]` | Parameter of a callback/lambda |\n\n### API Graph Languages\n\n| Component | Description |\n| -------------- | ------------------------------------------------------- |\n| `Member[name]` | Property or attribute access |\n| `Argument[n]` | Argument at index n |\n| `Parameter[n]` | Parameter at index n |\n| `ReturnValue` | Return value |\n| `ArrayElement` | Array element |\n| `MapValue` | Map value |\n| `Instance` | Instances of a class |\n| `Fuzzy` | All values derived from the current value (approximate) |\n\n## Threat Model Kinds (Sources)\n\n| Kind | Description |\n| ---------- | ---------------------------------------------------------------- |\n| `remote` | Remote/network input (HTTP requests, WebSocket messages) |\n| `local` | Local input (files, CLI arguments, environment variables, stdin) |\n| `database` | Data from database reads |\n\n## Sink Kinds\n\nCommon sink kinds across all languages:\n\n`sql-injection`, `command-injection`, `code-injection`, `path-injection`, `url-redirection`, `log-injection`, `request-forgery`, `xpath-injection`, `html-injection`\n\nSee per-language resources for language-specific sink kinds.\n\n## Model Packs\n\n### Structure\n\nGroup data extension files into a distributable CodeQL model pack:\n\n```yaml\n# codeql-pack.yml\nname: my-org/security-models\nversion: 1.0.0\ndependencies:\n codeql/<language>-all: '*'\ndataExtensions:\n - 'ext/*.model.yml'\n```\n\n### Testing Extensions\n\nApply extensions during query execution or testing:\n\n```bash\n# Run a query with extensions\ncodeql query run --additional-packs=<model-pack-dir> <query.ql> --database=<db>\n\n# Run tests with extensions\ncodeql test run --additional-packs=<model-pack-dir> <test-dir>\n```\n\n### Publishing to GitHub Container Registry\n\n```bash\ncodeql pack publish\n```\n\nConsumers can use published model packs via:\n\n```yaml\n# In consumer's codeql-pack.yml\ndependencies:\n my-org/security-models: '^1.0.0'\n```\n\nOr configure them org-wide for GitHub Code Scanning Default Setup.\n\n## Development Workflow\n\n1. **Identify the gap** \u2014 run a CodeQL query against a codebase and observe missing coverage (false negatives) or incorrect results (false positives)\n2. **Analyze the library** \u2014 understand the API surface: which functions are sources, sinks, or data-passing\n3. **Create model YAML** \u2014 write a `.model.yml` file with the appropriate extensible predicates\n4. **Test with `--additional-packs`** \u2014 verify the extension produces expected results using `codeql query run` or `codeql test run`\n5. **Iterate** \u2014 refine access paths and add barrier/barrierGuard models to reduce false positives\n6. **Package and publish** \u2014 bundle into a model pack for distribution\n\n## Related Resources\n\n- `codeql://languages/{language}/library-modeling` \u2014 Language-specific library modeling guide\n- `codeql://templates/security` \u2014 Security query templates\n- `codeql://learning/query-basics` \u2014 QL query writing reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL\n";
|
|
197632
|
+
|
|
197285
197633
|
// src/resources/dataflow-migration-v1-to-v2.md
|
|
197286
197634
|
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';
|
|
197287
197635
|
|
|
@@ -197301,16 +197649,16 @@ var codeql_query_unit_testing_default = '# CodeQL Query Unit Testing\n\nGuide fo
|
|
|
197301
197649
|
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';
|
|
197302
197650
|
|
|
197303
197651
|
// src/resources/server-overview.md
|
|
197304
|
-
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
|
|
197652
|
+
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://learning/data-extensions` | Data extensions (Models-as-Data) overview and formats |\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| `codeql://languages/{language}/library-modeling` | Language-specific library modeling \u2014 registered for every CodeQL language that supports Models-as-Data (`cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `rust`, `swift`) |\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 **15 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- **Alert analysis** \u2014 `compare_overlapping_alerts`, `check_for_duplicated_code`, `find_overlapping_queries`\n- **Data extension development** \u2014 `data_extension_development`\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`, `rust`, `swift`.\n';
|
|
197305
197653
|
|
|
197306
197654
|
// src/resources/server-prompts.md
|
|
197307
|
-
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| `compare_overlapping_alerts` | Compare CodeQL SARIF alerts across rules, files, runs, databases, or CodeQL versions |\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. Uses `query_results_cache_lookup`, `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, and `read_database_source` for structured analysis.\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. Uses `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `read_database_source`, `sarif_compare_alerts`, and `sarif_diff_runs` for context gathering.\n\n### Alert Analysis and Comparison\n\n- **`compare_overlapping_alerts`** \u2014 Compares CodeQL SARIF alerts across any combination of SARIF files, analysis runs, CodeQL databases, or query packs. Classifies findings as redundant, complementary, false overlap, behavioral regression, or new coverage. Uses `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs`, and `read_database_source` tools. Requires `sarifPathA`; optionally accepts `sarifPathB` for cross-file comparison, `ruleIdA`/`ruleIdB` to narrow to specific rules, and `databasePath` for source code context.\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";
|
|
197655
|
+
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| `compare_overlapping_alerts` | Compare CodeQL SARIF alerts across rules, files, runs, databases, or CodeQL versions |\n| `data_extension_development` | End-to-end workflow for creating CodeQL data extensions (Models-as-Data) for third-party libraries |\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. Uses `query_results_cache_lookup`, `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, and `read_database_source` for structured analysis.\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. Uses `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `read_database_source`, `sarif_compare_alerts`, and `sarif_diff_runs` for context gathering.\n\n### Alert Analysis and Comparison\n\n- **`compare_overlapping_alerts`** \u2014 Compares CodeQL SARIF alerts across any combination of SARIF files, analysis runs, CodeQL databases, or query packs. Classifies findings as redundant, complementary, false overlap, behavioral regression, or new coverage. Uses `sarif_list_rules`, `sarif_extract_rule`, `sarif_rule_to_markdown`, `sarif_compare_alerts`, `sarif_diff_runs`, and `read_database_source` tools. Requires `sarifPathA`; optionally accepts `sarifPathB` for cross-file comparison, `ruleIdA`/`ruleIdB` to narrow to specific rules, and `databasePath` for source code context.\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### Data Extension Development\n\n- **`data_extension_development`** \u2014 End-to-end procedural workflow for creating CodeQL data extensions (Models-as-Data) for third-party libraries. Covers: identify target library \u2192 classify API surface \u2192 choose deployment scope \u2192 author `.model.yml` \u2192 configure pack \u2192 test with `codeql_query_run` and `codeql_test_run` \u2192 decide next steps. Requires `language`; optionally accepts `libraryName` and `database`. References `codeql://learning/data-extensions` and `codeql://languages/{language}/library-modeling` for format-specific guidance.\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";
|
|
197308
197656
|
|
|
197309
197657
|
// src/resources/server-queries.md
|
|
197310
|
-
var server_queries_default = '# MCP Server Bundled Queries\n\nThis resource describes the tools queries bundled with the CodeQL Development MCP Server. These queries run via `codeql_query_run` and provide structural insight into how source code is represented in a CodeQL database. Use them to understand code structure before writing detection queries.\n\nFor general QL query writing guidance (syntax, metadata, `from`/`where`/`select`, testing conventions), see `codeql://learning/query-basics`.\n\n## Bundled Tools Queries\n\nThe server bundles five tools queries that operate on CodeQL databases:\n\n| Query | Purpose
|
|
197658
|
+
var server_queries_default = '# MCP Server Bundled Queries\n\nThis resource describes the tools queries bundled with the CodeQL Development MCP Server. These queries run via `codeql_query_run` and provide structural insight into how source code is represented in a CodeQL database. Use them to understand code structure before writing detection queries.\n\nFor general QL query writing guidance (syntax, metadata, `from`/`where`/`select`, testing conventions), see `codeql://learning/query-basics`.\n\n## Bundled Tools Queries\n\nThe server bundles five tools queries that operate on CodeQL databases:\n\n| Query | Purpose | Output Format |\n| ----------------- | ------------------------------------------------- | ------------------------- |\n| `PrintAST` | Visualize the Abstract Syntax Tree of source code | `@kind graph` (graphtext) |\n| `PrintCFG` | Visualize the Control Flow Graph of a function | `@kind graph` (graphtext) |\n| `CallGraphFrom` | Show all functions called FROM a given function | `@kind graph` (graphtext) |\n| `CallGraphTo` | Show all call sites that call TO a given function | `@kind graph` (graphtext) |\n| `CallGraphFromTo` | Show calls FROM one function TO another | `@kind graph` (graphtext) |\n\nAll five queries use `@kind graph` metadata and produce output in graphtext format.\n\n## PrintAST\n\n**Purpose**: Outputs a hierarchical representation of the Abstract Syntax Tree showing parent-child relationships between declarations, statements, and expressions.\n\n**When to use**: Before writing any CodeQL query, run `PrintAST` on your test source code to understand which QL classes represent which source constructs and which predicates are available for matching.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintAST"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFiles: "<comma-separated-filenames>" (optional \u2014 filter to specific files)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A tree showing each AST node with its QL class name, properties, and position in the hierarchy. This reveals exactly which QL classes and predicates to use in `from`/`where`/`select` clauses.\n\n## PrintCFG\n\n**Purpose**: Produces a Control Flow Graph representation showing the order in which statements and expressions execute, including branching paths.\n\n**When to use**: When writing queries that reason about execution order, reachability, or branching logic (e.g., "is this check always performed before this call?").\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "PrintCFG"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>" (optional \u2014 target a specific function)\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: Nodes representing CFG basic blocks and edges representing possible execution transitions (successor relationships).\n\n## CallGraphFrom\n\n**Purpose**: Shows all functions called FROM a specified source function \u2014 the outbound call dependencies.\n\n**When to use**: When analyzing what a function does by tracing the functions it invokes. Useful for understanding call chains and identifying potential data flow paths.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFrom"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each call site within the source function and the target function being called.\n\n## CallGraphTo\n\n**Purpose**: Shows all call sites that invoke a specified target function \u2014 the inbound callers.\n\n**When to use**: When performing impact analysis to understand where a function is used, or when identifying all locations that pass data to a particular sink function.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n targetFunction: "<function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing each caller function and the specific call site where the target function is invoked.\n\n## CallGraphFromTo\n\n**Purpose**: Shows the call relationship between two specific functions \u2014 whether function A calls function B (directly or transitively) and what the call path looks like.\n\n**When to use**: When investigating whether a specific source function can reach a specific sink function through the call graph. Useful for validating dataflow hypotheses before writing taint-tracking queries.\n\n**How to run**:\n\n```text\nTool: codeql_query_run\nParameters:\n queryName: "CallGraphFromTo"\n queryLanguage: "<language>"\n database: "<path-to-database>"\n sourceFunction: "<calling-function-name>"\n targetFunction: "<called-function-name>"\n format: "graphtext"\n interpretedOutput: "<output-directory>"\n```\n\n**Output**: A graph showing the call path from the source function to the target function, including intermediate call sites.\n\n## Language Support\n\n| Language | PrintAST | PrintCFG | CallGraphFrom | CallGraphTo | CallGraphFromTo |\n| ---------- | :------: | :------: | :-----------: | :---------: | :-------------: |\n| actions | \u2713 | \u2713 | | | |\n| cpp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| csharp | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| go | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| java | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| javascript | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| python | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| ruby | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| rust | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n| swift | \u2713 | \u2713 | \u2713 | \u2713 | \u2713 |\n\nNote: The `actions` language supports PrintAST and PrintCFG only (no call graph queries).\n\n## Recommended Workflow\n\nUse the `tools_query_workflow` prompt for a guided step-by-step workflow:\n\n1. **Identify or create a database**: Use `list_codeql_databases` or `codeql_database_create`\n2. **Run PrintAST**: Understand how the source code maps to QL classes\n3. **Run PrintCFG**: Understand control flow for the functions of interest\n4. **Run CallGraphFrom / CallGraphTo**: Trace call relationships to identify sources and sinks\n5. **Run CallGraphFromTo**: Verify specific source-to-sink call paths\n6. **Write detection queries**: Use the insights from steps 2\u20135 to select the right QL classes and predicates\n\n## Related Resources\n\n- `codeql://learning/query-basics` \u2014 QL query writing reference (syntax, metadata, patterns, testing)\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/tools` \u2014 Complete tool reference\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n- `codeql://languages/{language}/ast` \u2014 Language-specific AST class reference\n';
|
|
197311
197659
|
|
|
197312
197660
|
// src/resources/server-tools.md
|
|
197313
|
-
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------- |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
197661
|
+
var server_tools_default = '# MCP Server Tools\n\nThis resource provides a complete reference of the default tools exposed by the CodeQL Development MCP Server. These tools wrap the CodeQL CLI and supporting utilities, enabling an LLM to develop, test, and analyze CodeQL queries programmatically.\n\n## CodeQL CLI Tools\n\n| Tool | Description |\n| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_bqrs_decode` | Decode BQRS result files to human-readable formats (text, csv, json). Supports `--result-set` and `--rows` for pagination |\n| `codeql_bqrs_info` | Get metadata about BQRS result files: result sets, column types, row counts |\n| `codeql_bqrs_interpret` | Interpret BQRS result files according to query metadata and generate output in specified formats (CSV, SARIF, graph formats) |\n| `codeql_database_analyze` | Run queries or query suites against CodeQL databases. Produces evaluator logs, BQRS, and SARIF output |\n| `codeql_database_create` | Create a CodeQL database from source code |\n| `codeql_generate_log-summary` | Create a summary of a structured JSON evaluator event log file |\n| `codeql_generate_query-help` | Generate query help documentation from QLDoc comments |\n| `codeql_pack_install` | Install CodeQL pack dependencies |\n| `codeql_pack_ls` | List CodeQL packs under a local directory path |\n| `codeql_query_compile` | Compile and validate CodeQL queries |\n| `codeql_query_format` | Automatically format CodeQL source code files |\n| `codeql_query_run` | Execute a CodeQL query against a database |\n| `codeql_resolve_database` | Resolve database path and validate database structure |\n| `codeql_resolve_files` | Find files in a directory tree, filtered by extension and glob patterns. Useful for discovering QL library files |\n| `codeql_resolve_languages` | List installed CodeQL extractor packs |\n| `codeql_resolve_library-path` | Resolve library path for CodeQL queries and libraries |\n| `codeql_resolve_metadata` | Resolve and return key-value metadata pairs from a CodeQL query source file |\n| `codeql_resolve_qlref` | Resolve `.qlref` files to their corresponding query files |\n| `codeql_resolve_queries` | List available CodeQL queries found on the local filesystem |\n| `codeql_resolve_tests` | Resolve the local filesystem paths of unit tests and/or queries under a base directory |\n| `codeql_test_accept` | Accept new test results as the expected baseline |\n| `codeql_test_extract` | Extract test databases for CodeQL query tests |\n| `codeql_test_run` | Run CodeQL query tests |\n\n## Language Server Protocol (LSP) Tools\n\n| Tool | Description |\n| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `codeql_lsp_completion` | Get code completions at a cursor position in a CodeQL file |\n| `codeql_lsp_definition` | Go to the definition of a CodeQL symbol at a given position |\n| `codeql_lsp_diagnostics` | Syntax and semantic validation of CodeQL code via the Language Server. Note: inline `ql_code` cannot resolve pack imports; use `codeql_query_compile` for files with imports |\n| `codeql_lsp_references` | Find all references to a CodeQL symbol at a given position |\n\n## Query Development Tools\n\n| Tool | Description |\n| -------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| `create_codeql_query` | Create directory structure and files for a new CodeQL query with tests |\n| `find_class_position` | Find the start/end line and column of a class for quick evaluation |\n| `find_codeql_query_files` | Find and track all files and directories related to a CodeQL query, including resolved metadata |\n| `find_predicate_position` | Find the start/end line and column of a predicate for quick evaluation |\n| `list_codeql_databases` | List CodeQL databases discovered in configured base directories |\n| `list_mrva_run_results` | List MRVA (Multi-Repository Variant Analysis) run results with per-repo details |\n| `list_query_run_results` | List query run result directories with artifact inventory. Filter by `queryName`, `language`, or `queryPath` |\n| `profile_codeql_query` | Profile the performance of a CodeQL query run against a specific database by analyzing the evaluator log |\n| `profile_codeql_query_from_logs` | Parse evaluator logs into a compact profile with line-indexed detail file for targeted read_file access |\n| `quick_evaluate` | Quick evaluate either a class or a predicate in a CodeQL query for debugging |\n| `read_database_source` | Read source file contents from a CodeQL database source archive. Omit `filePath` to list all files |\n| `register_database` | Register a CodeQL database given a local path to the database directory |\n| `search_ql_code` | Search QL source files for text or regex patterns with structured results (replaces grep for QL code) |\n| `validate_codeql_query` | Quick heuristic validation for CodeQL query structure (does not compile the query) |\n\n## SARIF Analysis Tools\n\n| Tool | Description |\n| ------------------------- | ---------------------------------------------------------------------------------------------------- |\n| `sarif_compare_alerts` | Compare code locations of two SARIF alerts for overlap (sink, source, any-location, full-path modes) |\n| `sarif_deduplicate_rules` | Find duplicate rules across two SARIF files using fingerprint-first, full-path-fallback overlap |\n| `sarif_diff_by_commits` | Correlate SARIF results with a git diff to classify findings as "new" or "pre-existing" |\n| `sarif_diff_runs` | Diff two SARIF files to find added, removed, and changed rules/results across analysis runs |\n| `sarif_extract_rule` | Extract all data for a specific rule from multi-rule SARIF. Returns a valid SARIF JSON subset |\n| `sarif_list_rules` | List all rules in a SARIF file with result counts, severity, precision, and tags |\n| `sarif_rule_to_markdown` | Convert per-rule SARIF data to markdown with Mermaid dataflow diagrams |\n| `sarif_store` | Cache SARIF content in the session store and return a cache key for use by downstream SARIF tools |\n\n### `sarif_list_rules` Response Format\n\nReturns a JSON object with per-rule result counts and metadata:\n\n```json\n{\n "totalRules": 3,\n "totalResults": 15,\n "rules": [\n {\n "ruleId": "js/sql-injection",\n "resultCount": 8,\n "name": "Database query built from user-controlled sources",\n "kind": "path-problem",\n "precision": "high",\n "severity": "8.8",\n "tags": ["security", "external/cwe/cwe-089"],\n "tool": "CodeQL",\n "toolVersion": "2.20.4"\n }\n ]\n}\n```\n\n| Field | Type | Description |\n| -------------- | ------ | ------------------------------------------------ |\n| `totalRules` | number | Total number of distinct rules in the SARIF file |\n| `totalResults` | number | Sum of `resultCount` across all rules |\n| `rules[]` | array | Per-rule summaries (see below) |\n\nEach rule object:\n\n| Field | Type | Required | Description |\n| ------------- | -------- | -------- | ---------------------------------------------------------------------------- |\n| `ruleId` | string | yes | Rule identifier (matches the CodeQL query `@id`) |\n| `resultCount` | number | yes | Number of results (findings) for this rule; `0` if defined but not triggered |\n| `name` | string | no | Display name (from `shortDescription.text`, `name`, or `id`) |\n| `kind` | string | no | Query kind (`path-problem`, `problem`, etc.) |\n| `precision` | string | no | Precision level (`high`, `medium`, `low`, `very-high`) |\n| `severity` | string | no | Security severity score (from `security-severity` property) |\n| `tags` | string[] | no | Rule tags (e.g., `security`, `external/cwe/cwe-089`) |\n| `tool` | string | no | Tool driver name (e.g., `CodeQL`) |\n| `toolVersion` | string | no | Tool driver version |\n\n## Common Tool Workflows\n\n### Create and Test a Query\n\n1. `create_codeql_query` \u2014 scaffold files\n2. `codeql_pack_install` \u2014 install dependencies\n3. `codeql_query_compile` \u2014 validate syntax\n4. `codeql_test_run` \u2014 run tests\n5. `codeql_test_accept` \u2014 accept correct results\n\n### Understand Code Structure\n\n1. `codeql_query_run` with `queryName="PrintAST"` \u2014 visualize the AST\n2. `codeql_query_run` with `queryName="PrintCFG"` \u2014 visualize control flow\n3. `codeql_query_run` with `queryName="CallGraphFrom"` / `"CallGraphTo"` \u2014 trace call relationships\n4. `codeql_query_run` with `queryName="CallGraphFromTo"` \u2014 verify source-to-sink call paths\n\n### Profile Query Performance\n\n1. `codeql_query_run` with `evaluationOutput` \u2014 run query and capture evaluator logs\n2. `profile_codeql_query_from_logs` \u2014 analyze evaluator logs: slowest predicates, RA operations, tuple count progressions, dependencies\n\n### Discover and Search QL Code\n\n1. `codeql_resolve_files` \u2014 find QL files by extension and glob patterns in library packs\n2. `search_ql_code` \u2014 search QL source files for classes, predicates, or patterns by text/regex\n3. `codeql_lsp_definition` \u2014 navigate to the definition of a discovered symbol\n4. `codeql_lsp_references` \u2014 find all usages of a symbol across a pack\n\n### Interactive Development\n\n1. `codeql_lsp_completion` \u2014 get QL code completions\n2. `codeql_lsp_definition` \u2014 navigate to definitions\n3. `codeql_lsp_references` \u2014 find all references\n4. `codeql_lsp_diagnostics` \u2014 real-time validation\n\n### Analyze and Compare Results\n\n1. `codeql_database_analyze` \u2014 run query packs and produce SARIF\n2. `sarif_list_rules` \u2014 discover rules and result counts in the SARIF\n3. `query_results_cache_lookup` with `ruleId` \u2014 find cached results by CodeQL query `@id`\n4. `sarif_extract_rule` \u2014 extract results for a specific rule from multi-rule SARIF\n5. `sarif_rule_to_markdown` \u2014 generate markdown report with Mermaid dataflow diagrams\n6. `sarif_compare_alerts` \u2014 compare two alerts for location overlap\n7. `sarif_diff_runs` \u2014 diff two SARIF files to detect behavioral changes across runs\n8. `sarif_diff_by_commits` \u2014 correlate SARIF results with git diff to triage new vs pre-existing\n9. `query_results_cache_compare` with `ruleId` \u2014 compare results across databases\n\n## Tool Input Conventions\n\n- **LSP tools** use **0-based** line and column positions for input. Output uses 1-based `startLine`/`endLine`.\n- **`find_predicate_position`** and **`find_class_position`** return **1-based** positions.\n- **`workspace_uri`** for LSP tools must be a **plain directory path** to the pack root containing `codeql-pack.yml`, not a `file://` URI.\n\n## Related Resources\n\n- `codeql://server/overview` \u2014 MCP server orientation guide\n- `codeql://server/prompts` \u2014 Complete prompt reference\n- `codeql://learning/query-basics` \u2014 Query writing reference\n- `codeql://patterns/performance` \u2014 Performance profiling guide\n';
|
|
197314
197662
|
|
|
197315
197663
|
// src/lib/resources.ts
|
|
197316
197664
|
function getLearningQueryBasics() {
|
|
@@ -197340,6 +197688,9 @@ function getTestDrivenDevelopment() {
|
|
|
197340
197688
|
function getQueryUnitTesting() {
|
|
197341
197689
|
return codeql_query_unit_testing_default;
|
|
197342
197690
|
}
|
|
197691
|
+
function getLearningDataExtensions() {
|
|
197692
|
+
return learning_data_extensions_default;
|
|
197693
|
+
}
|
|
197343
197694
|
function getDataflowMigration() {
|
|
197344
197695
|
return dataflow_migration_v1_to_v2_default;
|
|
197345
197696
|
}
|
|
@@ -197517,6 +197868,25 @@ function registerCodeQLResources(server) {
|
|
|
197517
197868
|
};
|
|
197518
197869
|
}
|
|
197519
197870
|
);
|
|
197871
|
+
server.resource(
|
|
197872
|
+
"CodeQL Data Extensions Overview",
|
|
197873
|
+
"codeql://learning/data-extensions",
|
|
197874
|
+
{
|
|
197875
|
+
description: "Data extensions (Models-as-Data) overview: YAML model formats, extensible predicates, model packs",
|
|
197876
|
+
mimeType: "text/markdown"
|
|
197877
|
+
},
|
|
197878
|
+
async () => {
|
|
197879
|
+
return {
|
|
197880
|
+
contents: [
|
|
197881
|
+
{
|
|
197882
|
+
uri: "codeql://learning/data-extensions",
|
|
197883
|
+
mimeType: "text/markdown",
|
|
197884
|
+
text: getLearningDataExtensions()
|
|
197885
|
+
}
|
|
197886
|
+
]
|
|
197887
|
+
};
|
|
197888
|
+
}
|
|
197889
|
+
);
|
|
197520
197890
|
server.resource(
|
|
197521
197891
|
"CodeQL Dataflow Migration v1 to v2",
|
|
197522
197892
|
"codeql://guides/dataflow-migration-v1-to-v2",
|
|
@@ -197547,7 +197917,7 @@ import { pathToFileURL as pathToFileURL3 } from "url";
|
|
|
197547
197917
|
// src/tools/lsp/lsp-server-helper.ts
|
|
197548
197918
|
init_server_manager();
|
|
197549
197919
|
init_logger();
|
|
197550
|
-
import { isAbsolute as
|
|
197920
|
+
import { isAbsolute as isAbsolute6, resolve as resolve11 } from "path";
|
|
197551
197921
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
197552
197922
|
async function getInitializedLanguageServer(opts = {}) {
|
|
197553
197923
|
const { packageRootDir: pkgRoot, getUserWorkspaceDir: getUserWorkspaceDir2 } = await Promise.resolve().then(() => (init_package_paths(), package_paths_exports));
|
|
@@ -197563,7 +197933,7 @@ async function getInitializedLanguageServer(opts = {}) {
|
|
|
197563
197933
|
const server = await manager.getLanguageServer(config2);
|
|
197564
197934
|
let effectiveUri = opts.workspaceUri;
|
|
197565
197935
|
if (effectiveUri && !effectiveUri.startsWith("file://")) {
|
|
197566
|
-
const absWorkspace =
|
|
197936
|
+
const absWorkspace = isAbsolute6(effectiveUri) ? effectiveUri : resolve11(getUserWorkspaceDir2(), effectiveUri);
|
|
197567
197937
|
effectiveUri = pathToFileURL2(absWorkspace).href;
|
|
197568
197938
|
}
|
|
197569
197939
|
effectiveUri = effectiveUri ?? pathToFileURL2(resolve11(pkgRoot, "ql")).href;
|
|
@@ -197728,7 +198098,7 @@ function registerLspDiagnosticsTool(server) {
|
|
|
197728
198098
|
init_logger();
|
|
197729
198099
|
init_package_paths();
|
|
197730
198100
|
import { readFile as readFile3 } from "fs/promises";
|
|
197731
|
-
import { isAbsolute as
|
|
198101
|
+
import { isAbsolute as isAbsolute7, resolve as resolve12 } from "path";
|
|
197732
198102
|
import { pathToFileURL as pathToFileURL4 } from "url";
|
|
197733
198103
|
async function getInitializedServer(params) {
|
|
197734
198104
|
return getInitializedLanguageServer({
|
|
@@ -197737,7 +198107,7 @@ async function getInitializedServer(params) {
|
|
|
197737
198107
|
});
|
|
197738
198108
|
}
|
|
197739
198109
|
function prepareDocumentPosition(params) {
|
|
197740
|
-
const absPath =
|
|
198110
|
+
const absPath = isAbsolute7(params.filePath) ? params.filePath : resolve12(getUserWorkspaceDir(), params.filePath);
|
|
197741
198111
|
const docUri = pathToFileURL4(absPath).href;
|
|
197742
198112
|
return { absPath, docUri };
|
|
197743
198113
|
}
|
|
@@ -197993,12 +198363,18 @@ var actions_ast_default = '# CodeQL AST nodes for `actions` language\n\n## CodeQ
|
|
|
197993
198363
|
// src/resources/languages/cpp_ast.md
|
|
197994
198364
|
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';
|
|
197995
198365
|
|
|
198366
|
+
// src/resources/languages/cpp_library_modeling.md
|
|
198367
|
+
var cpp_library_modeling_default = "# Customizing Library Models for C/C++\n\n## Purpose\n\nCustomize data-flow and taint analysis for C/C++ by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/cpp-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## Model Format\n\nC/C++ uses a **MaD (Models as Data)** format with **9\u201310 column tuples**. Same structural pattern as Java/Kotlin, C#, and Go, but with namespace-based identification and pointer indirection support.\n\n## Extensible Predicates for C/C++\n\n| Predicate | Columns | Purpose |\n| ------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| `sourceModel` | `(namespace, type, subtypes, name, signature, ext, output, kind, provenance)` | Model sources of tainted data |\n| `sinkModel` | `(namespace, type, subtypes, name, signature, ext, input, kind, provenance)` | Model sinks |\n| `summaryModel` | `(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance)` | Model flow through functions |\n| `barrierModel` | `(namespace, type, subtypes, name, signature, ext, output, kind, provenance)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(namespace, type, subtypes, name, signature, ext, input, acceptingValue, kind, provenance)` | Model barrier guards (validators) that stop taint via conditional checks |\n\n**Note:** C/C++ does **not** currently support `neutralModel`.\n\n## Tuple Column Reference\n\n| Column | Description | Example |\n| ---------------- | ------------------------------------------------------------------------------------ | --------------------------------- |\n| `namespace` | C++ namespace (use `\"\"` for global namespace) | `\"boost::asio\"`, `\"\"` |\n| `type` | Class name (use `\"\"` for free functions) | `\"\"`, `\"Socket\"` |\n| `subtypes` | Whether model applies to overrides (`True`/`False`). Use `False` for free functions. | `False` |\n| `name` | Function or method name | `\"read_until\"`, `\"write\"` |\n| `signature` | Can narrow between overloaded functions. Use `\"\"` to match all overloads. | `\"\"` |\n| `ext` | Leave empty (`\"\"`) | `\"\"` |\n| `input`/`output` | Access path (supports pointer indirection via `*`) | `\"Argument[*1]\"`, `\"ReturnValue\"` |\n| `kind` | Source/sink/summary kind | `\"remote\"`, `\"remote-sink\"` |\n| `provenance` | Origin of the model | `\"manual\"` |\n\n### Important: C/C++-Specific Rules\n\n- **Pointer indirection**: Use the `*` prefix on argument indices to dereference pointers. `Argument[*1]` means \"the pointed-to value of the second argument.\"\n- **Free functions** have `type` = `\"\"` and `subtypes` = `False`\n- **Namespace nesting**: Use `::` separator (e.g., `\"boost::asio\"`)\n- **Global namespace** functions use `\"\"` for the namespace column\n- **Signature column** can be used to disambiguate overloaded functions, but `\"\"` matches all overloads\n\n## Access Paths\n\n| Component | Description |\n| ---------------- | -------------------------------------------------- |\n| `Argument[n]` | Argument at index n (0-based, the value itself) |\n| `Argument[*n]` | First indirection (pointed-to value) of argument n |\n| `ReturnValue` | Return value of the function |\n| `ReturnValue[*]` | Pointed-to value of the return value |\n\n## Sink Kinds\n\n`sql-injection`, `command-injection`, `path-injection`, `remote-sink` (data transmitted across network), `format-string` (uncontrolled format strings)\n\n## Sample Model\n\nGiven a snippet using `boost::asio`:\n\n```cpp\nboost::asio::write(socket, send_buffer, error); // sink: data sent over network\n```\n\n`boost_asio.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/cpp-all\n extensible: sourceModel\n data: []\n\n - addsTo:\n pack: codeql/cpp-all\n extensible: sinkModel\n data:\n - ['boost::asio', '', False, 'write', '', '', 'Argument[*1]', 'remote-sink', 'manual']\n\n - addsTo:\n pack: codeql/cpp-all\n extensible: summaryModel\n data: []\n\n - addsTo:\n pack: codeql/cpp-all\n extensible: barrierModel\n data: []\n\n - addsTo:\n pack: codeql/cpp-all\n extensible: barrierGuardModel\n data: []\n```\n\n## Examples\n\n### Source from Network Read\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/cpp-all\n extensible: sourceModel\n data:\n - ['boost::asio', '', False, 'read_until', '', '', 'Argument[*1]', 'remote', 'manual']\n```\n\nNote: `Argument[*1]` means the **pointed-to value** of the second argument (the buffer being filled with network data).\n\n### Flow Through `boost::asio::buffer`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/cpp-all\n extensible: summaryModel\n data:\n - [\n 'boost::asio',\n '',\n False,\n 'buffer',\n '',\n '',\n 'Argument[*0]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n```\n\n### Barrier: `mysql_real_escape_string`\n\nThe `mysql_real_escape_string` function escapes special characters in a string for use in SQL statements, preventing SQL injection. The escaped output (written to the second argument's pointed-to value) is safe.\n\n```cpp\nchar *escaped_name = new char[2 * strlen(name) + 1];\nmysql_real_escape_string(mysql, escaped_name, name, strlen(name)); // escaped_name is safe for SQL\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/cpp-all\n extensible: barrierModel\n data:\n - [\n '',\n '',\n False,\n 'mysql_real_escape_string',\n '',\n '',\n 'Argument[*1]',\n 'sql-injection',\n 'manual'\n ]\n```\n\nNote: `Argument[*1]` means the **pointed-to value** of the second argument \u2014 the output buffer that receives the escaped string. The `kind` `\"sql-injection\"` must match the sink kind used by SQL injection queries.\n\n### Barrier Guard: Validation Function\n\nA barrier guard models a function that returns a boolean indicating whether data is safe. When the function returns the expected value, taint flow is stopped through the guarded branch.\n\n```cpp\nif (is_safe(user_input)) { // The check guards the use\n mysql_query(user_input); // This is safe\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/cpp-all\n extensible: barrierGuardModel\n data:\n - ['', '', False, 'is_safe', '', '', 'Argument[*0]', 'true', 'sql-injection', 'manual']\n```\n\nNote: The `acceptingValue` `\"true\"` means the barrier applies when `is_safe` returns true. The `input` `\"Argument[*0]\"` identifies the value being validated (the pointed-to value of the first argument).\n\n## Key Differences from Other Languages\n\n| Aspect | C/C++ | Java/C#/Go |\n| ------------------- | ----------------------------------------------------- | --------------------------------------- |\n| Pack name | `codeql/cpp-all` | `codeql/java-all`, etc. |\n| Identifier column 1 | `namespace` (C++ namespace) | `package`/`namespace` |\n| Pointer indirection | `Argument[*n]` for dereferenced pointers | Not applicable |\n| `neutralModel` | Not supported | Supported |\n| Receiver access | Not applicable (C++ uses `Argument[this]` if modeled) | `Argument[this]` / `Argument[receiver]` |\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/cpp/ast` \u2014 C/C++ AST class reference\n- `codeql://languages/cpp/security` \u2014 C/C++ security query patterns\n- [Customizing Library Models for C and C++](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-cpp/)\n";
|
|
198368
|
+
|
|
197996
198369
|
// src/resources/languages/cpp_security_query_guide.md
|
|
197997
198370
|
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";
|
|
197998
198371
|
|
|
197999
198372
|
// src/resources/languages/csharp_ast.md
|
|
198000
198373
|
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';
|
|
198001
198374
|
|
|
198375
|
+
// src/resources/languages/csharp_library_modeling.md
|
|
198376
|
+
var csharp_library_modeling_default = "# Customizing Library Models for C\\#\n\n## Purpose\n\nCustomize data-flow and taint analysis for C# by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/csharp-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## Model Format\n\nC# uses a **MaD (Models as Data)** format with **9\u201310 column tuples** that identify callables by fully qualified namespace, type, method name, and signature. Same structural pattern as Java/Kotlin and Go.\n\n## Extensible Predicates for C\\#\n\n| Predicate | Columns | Purpose |\n| ------------------- | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| `sourceModel` | `(namespace, type, subtypes, name, signature, ext, output, kind, provenance)` | Model sources of tainted data |\n| `sinkModel` | `(namespace, type, subtypes, name, signature, ext, input, kind, provenance)` | Model sinks |\n| `summaryModel` | `(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance)` | Model flow through methods |\n| `barrierModel` | `(namespace, type, subtypes, name, signature, ext, output, kind, provenance)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(namespace, type, subtypes, name, signature, ext, input, acceptingValue, kind, provenance)` | Model barrier guards (validators) that stop taint via conditional checks |\n| `neutralModel` | `(namespace, type, name, signature, kind, provenance)` | Mark methods as having no dataflow impact |\n\n## Tuple Column Reference\n\n| Column | Description | Example |\n| ---------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------- |\n| `namespace` | Fully qualified namespace | `\"System.Data.SqlClient\"` |\n| `type` | Class or interface name | `\"SqlCommand\"` |\n| `subtypes` | Whether model applies to overrides (`True`/`False`) | `False` |\n| `name` | Method/property name. Constructors use the class name. Getters: `get_Name`, Setters: `set_Name` | `\"SqlCommand\"`, `\"get_Now\"` |\n| `signature` | Fully qualified parameter types in parentheses | `\"(System.String,System.Data.SqlClient.SqlConnection)\"` |\n| `ext` | Leave empty (`\"\"`) | `\"\"` |\n| `input`/`output` | Access path | `\"Argument[0]\"`, `\"ReturnValue\"` |\n| `kind` | Source/sink/summary kind | `\"sql-injection\"`, `\"taint\"` |\n| `provenance` | Origin of the model | `\"manual\"` |\n\n### Important: C#-Specific Signature Rules\n\n- Type names must be **fully qualified**: `System.String`, not `string`\n- Generic type parameters must match source code names: `Select<TSource,TResult>`\n- Generics in signatures must match: `(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,TResult>)`\n- Property getters/setters are modeled as `get_PropertyName`/`set_PropertyName`\n- Constructors use the class name (e.g., `\"SqlCommand\"`)\n\n## Access Paths\n\n| Component | Description |\n| ----------------- | -------------------------------------------- |\n| `Argument[n]` | Argument at index n (0-based) |\n| `Argument[this]` | The qualifier/receiver of a method call |\n| `Argument[n1,n2]` | Shorthand for multiple arguments |\n| `ReturnValue` | Return value of the method |\n| `Element` | Elements of a collection (e.g., IEnumerable) |\n| `Parameter[n]` | Parameter at index n of a delegate/lambda |\n| `Field[name]` | Named field |\n| `Property[name]` | Named property |\n\n## Sink Kinds\n\n`sql-injection`, `command-injection`, `code-injection`, `path-injection`, `url-redirection`, `log-injection`, `request-forgery`, `xpath-injection`, `ldap-injection`\n\n## Threat Models (C#-Specific)\n\nIn addition to `remote` and `local`, C# supports:\n\n- `file-write` \u2014 opening a file in write mode\n- `windows-registry` \u2014 Windows registry values (C# only)\n\n## Sample Model\n\nGiven a snippet where the `SqlCommand` constructor takes a SQL string:\n\n```csharp\npublic static void TaintSink(SqlConnection conn, string query) {\n SqlCommand command = new SqlCommand(query, conn); // sink: SQL injection\n}\n```\n\n`sqlclient.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: sourceModel\n data: []\n\n - addsTo:\n pack: codeql/csharp-all\n extensible: sinkModel\n data:\n - [\n 'System.Data.SqlClient',\n 'SqlCommand',\n False,\n 'SqlCommand',\n '(System.String,System.Data.SqlClient.SqlConnection)',\n '',\n 'Argument[0]',\n 'sql-injection',\n 'manual'\n ]\n\n - addsTo:\n pack: codeql/csharp-all\n extensible: summaryModel\n data: []\n\n - addsTo:\n pack: codeql/csharp-all\n extensible: barrierModel\n data: []\n\n - addsTo:\n pack: codeql/csharp-all\n extensible: barrierGuardModel\n data: []\n\n - addsTo:\n pack: codeql/csharp-all\n extensible: neutralModel\n data: []\n```\n\n## Examples\n\n### Remote Source from Network Stream\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: sourceModel\n data:\n - [\n 'System.Net.Sockets',\n 'TcpClient',\n False,\n 'GetStream',\n '()',\n '',\n 'ReturnValue',\n 'remote',\n 'manual'\n ]\n```\n\n### Flow Through `String.Concat`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: summaryModel\n data:\n - [\n 'System',\n 'String',\n False,\n 'Concat',\n '(System.Object,System.Object)',\n '',\n 'Argument[0,1]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n```\n\nNote: `Argument[0,1]` is shorthand for both `Argument[0]` and `Argument[1]`.\n\n### Flow Through `String.Trim` (Instance Method)\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: summaryModel\n data:\n - [\n 'System',\n 'String',\n False,\n 'Trim',\n '()',\n '',\n 'Argument[this]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n```\n\n### Flow Through LINQ `Select` (Higher-Order + Generics)\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: summaryModel\n data:\n - [\n 'System.Linq',\n 'Enumerable',\n False,\n 'Select<TSource,TResult>',\n '(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,TResult>)',\n '',\n 'Argument[0].Element',\n 'Argument[1].Parameter[0]',\n 'value',\n 'manual'\n ]\n - [\n 'System.Linq',\n 'Enumerable',\n False,\n 'Select<TSource,TResult>',\n '(System.Collections.Generic.IEnumerable<TSource>,System.Func<TSource,TResult>)',\n '',\n 'Argument[1].ReturnValue',\n 'ReturnValue.Element',\n 'value',\n 'manual'\n ]\n```\n\nNote: Two rows model the two-step flow: collection elements into the lambda parameter, then from the lambda return value into the output collection elements. Generic type parameter names must match the source code.\n\n### Neutral Model (Property Getter)\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: neutralModel\n data:\n - ['System', 'DateTime', 'get_Now', '()', 'summary', 'manual']\n```\n\n### Barrier: URL Safety\n\nThe `RawUrl` property of `HttpRequest` returns the raw URL of the current request, which is safe for URL redirects because it cannot be manipulated by an attacker.\n\n```csharp\npublic static void TaintBarrier(HttpRequest request) {\n string url = request.RawUrl; // Safe for URL redirects\n Response.Redirect(url); // Not a URL redirection vulnerability\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: barrierModel\n data:\n - [\n 'System.Web',\n 'HttpRequest',\n False,\n 'get_RawUrl',\n '()',\n '',\n 'ReturnValue',\n 'url-redirection',\n 'manual'\n ]\n```\n\nNote: Property getters are modeled as `get_PropertyName`. The `kind` `\"url-redirection\"` must match the sink kind used by URL redirection queries.\n\n### Barrier Guard: URL Validation\n\nThe `IsAbsoluteUri` property of `Uri` returns `false` when the URL is relative and therefore safe for URL redirects.\n\n```csharp\npublic static void TaintBarrierGuard(Uri uri) {\n if (!uri.IsAbsoluteUri) { // The check guards the redirect\n Response.Redirect(uri.ToString()); // Safe\n }\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/csharp-all\n extensible: barrierGuardModel\n data:\n - [\n 'System',\n 'Uri',\n False,\n 'get_IsAbsoluteUri',\n '()',\n '',\n 'Argument[this]',\n 'false',\n 'url-redirection',\n 'manual'\n ]\n```\n\nNote: The `acceptingValue` `\"false\"` means the barrier applies when `IsAbsoluteUri` is false (the URL is relative). The `input` `\"Argument[this]\"` identifies the qualifier (`uri`) whose taint flow is blocked.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/csharp/ast` \u2014 C# AST class reference\n- `codeql://languages/csharp/security` \u2014 C# security query patterns\n- [Customizing Library Models for C#](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-csharp/)\n";
|
|
198377
|
+
|
|
198002
198378
|
// src/resources/languages/csharp_security_query_guide.md
|
|
198003
198379
|
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";
|
|
198004
198380
|
|
|
@@ -198012,7 +198388,7 @@ var go_basic_queries_default = '# Basic CodeQL Query Examples for Go\n\n## Purpo
|
|
|
198012
198388
|
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';
|
|
198013
198389
|
|
|
198014
198390
|
// src/resources/languages/go_library_modeling.md
|
|
198015
|
-
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";
|
|
198391
|
+
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### Barrier Models (CodeQL 2.25.2+)\n\n**`barrierModel(package, type, subtypes, name, signature, ext, output, kind, provenance)`**\n\nDefine sanitizers that stop taint flow. The `output` access path identifies the value that is safe after the function returns. The `kind` must match the sink kind used by the corresponding security query.\n\n**Example**: HTML-escaping prevents XSS\n\n```go\nfunc Render(w http.ResponseWriter, r *http.Request) {\n name := r.FormValue(\"name\")\n safe := beego.Htmlquote(name) // safe is HTML-escaped\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: barrierModel\n data:\n - ['group:beego', '', true, 'Htmlquote', '', '', 'ReturnValue', 'html-injection', 'manual']\n```\n\nNote: The `group:` prefix matches multiple package paths that refer to the same package (configured via `packageGrouping`). The `kind` `\"html-injection\"` must match the sink kind used by XSS queries.\n\n### Barrier Guard Models (CodeQL 2.25.2+)\n\n**`barrierGuardModel(package, type, subtypes, name, signature, ext, input, acceptingValue, kind, provenance)`**\n\nDefine validators that stop taint flow via conditional checks. When the function returns the `acceptingValue`, taint flow is stopped through the guarded branch. The `input` access path identifies the value being validated.\n\n**Example**: Validation function prevents SQL injection\n\n```go\nfunc Query(db *sql.DB, input string) {\n if example.IsSafe(input) { // The check guards the query\n db.Query(input) // Safe\n }\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/go-all\n extensible: barrierGuardModel\n data:\n - [\n 'example.com/example',\n '',\n false,\n 'IsSafe',\n '',\n '',\n 'Argument[0]',\n 'true',\n 'sql-injection',\n 'manual'\n ]\n```\n\nNote: The `acceptingValue` `\"true\"` means the barrier applies when `IsSafe` returns true. The `input` `\"Argument[0]\"` identifies the first argument whose taint flow is blocked.\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";
|
|
198016
198392
|
|
|
198017
198393
|
// src/resources/languages/go_security_query_guide.md
|
|
198018
198394
|
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";
|
|
@@ -198020,24 +198396,42 @@ var go_security_query_guide_default = "# Go Security Query Guide\n\nLanguage-spe
|
|
|
198020
198396
|
// src/resources/languages/java_ast.md
|
|
198021
198397
|
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## Control Flow Graph\n\nThe Java `ControlFlowGraph` module provides CFG analysis via the `ControlFlowNode` class\n(imported from `semmle.code.java.ControlFlowGraph`). Key types and predicates:\n\n- **`ControlFlowNode`** - A node in the control flow graph (replaces the removed `ControlFlow::Node` type)\n - `getASuccessor()` - Gets a successor node in the CFG\n - `getASuccessor(SuccessorType t)` - Gets a successor of a specific type\n - `asExpr()` - Gets the expression this node represents\n - `asStmt()` - Gets the statement this node represents\n - `toString()` - String representation of the CFG node\n- **`ConditionNode`** - A CFG node that branches on a boolean condition\n - `getATrueSuccessor()` - Gets a true-branch successor\n - `getAFalseSuccessor()` - Gets a false-branch successor\n\n**Note**: The `ControlFlow` module (with `ControlFlow::Node`) was removed in `codeql/java-all@9.0.0`.\nUse `ControlFlowNode` directly instead. The CFG now includes richer node types such as\n`Entry`, `Before ...`, `After ...`, and `[LoopHeader]` nodes for more precise flow analysis.\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';
|
|
198022
198398
|
|
|
198399
|
+
// src/resources/languages/java_library_modeling.md
|
|
198400
|
+
var java_library_modeling_default = "# Customizing Library Models for Java/Kotlin\n\n## Purpose\n\nCustomize data-flow and taint analysis for Java and Kotlin by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/java-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## Model Format\n\nJava/Kotlin uses a **MaD (Models as Data)** format with **9\u201310 column tuples** that identify callables by fully qualified package, type, method name, and signature. Same structural pattern as C#, C/C++, and Go.\n\n## Extensible Predicates for Java/Kotlin\n\n| Predicate | Columns | Purpose |\n| ------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------ |\n| `sourceModel` | `(package, type, subtypes, name, signature, ext, output, kind, provenance)` | Model sources of tainted data |\n| `sinkModel` | `(package, type, subtypes, name, signature, ext, input, kind, provenance)` | Model sinks |\n| `summaryModel` | `(package, type, subtypes, name, signature, ext, input, output, kind, provenance)` | Model flow through methods |\n| `barrierModel` | `(package, type, subtypes, name, signature, ext, output, kind, provenance)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(package, type, subtypes, name, signature, ext, input, acceptingValue, kind, provenance)` | Model barrier guards (validators) that stop taint via conditional checks |\n| `neutralModel` | `(package, type, name, signature, kind, provenance)` | Mark methods as having no dataflow impact |\n\n## Tuple Column Reference\n\n| Column | Description | Example |\n| ---------------- | --------------------------------------------------- | -------------------------------- |\n| `package` | Fully qualified package name | `\"java.sql\"` |\n| `type` | Class or interface name | `\"Statement\"` |\n| `subtypes` | Whether model applies to overrides (`True`/`False`) | `True` |\n| `name` | Method name (constructors use the class name) | `\"execute\"` |\n| `signature` | Method parameter type signature | `\"(String)\"` |\n| `ext` | Leave empty (`\"\"`) | `\"\"` |\n| `input`/`output` | Access path to the input/output of the flow | `\"Argument[0]\"`, `\"ReturnValue\"` |\n| `kind` | Source/sink/summary kind | `\"sql-injection\"`, `\"taint\"` |\n| `provenance` | Origin of the model | `\"manual\"` |\n\n### Important: `subtypes` Flag\n\n- `True` \u2014 the model applies to the method **and all overrides** in subclasses/implementing classes\n- `False` \u2014 only applies to the exact class specified\n\n### Important: `signature` Column\n\n- Type names must be **fully qualified**: `\"(String)\"` means `java.lang.String`\n- Multiple parameters: `\"(String,int)\"`\n- Generic type parameters must match source: `\"Select<TSource,TResult>\"`\n- Empty `\"\"` matches any signature (use sparingly)\n\n## Access Paths\n\n| Component | Description |\n| ------------------ | --------------------------------------- |\n| `Argument[n]` | Argument at index n (0-based) |\n| `Argument[this]` | The qualifier/receiver of a method call |\n| `Argument[n1..n2]` | Range of arguments |\n| `ReturnValue` | Return value of the method |\n| `Element` | Elements of a collection |\n| `Field[name]` | Named field of a class |\n| `Parameter[n]` | Parameter at index n of a callback |\n| `MapKey` | Key of a map |\n| `MapValue` | Value of a map |\n\n## Sink Kinds\n\n`sql-injection`, `command-injection`, `code-injection`, `path-injection`, `url-redirection`, `log-injection`, `request-forgery`, `xpath-injection`, `ldap-injection`, `jndi-injection`, `template-injection`, `hostname-verification`\n\n## Threat Models (Java-Specific)\n\nIn addition to `remote` and `local`, Java supports:\n\n- `android` (`android-external-storage-dir`, `contentprovider`) \u2014 Android-specific sources\n- `reverse-dns` \u2014 reverse DNS lookups\n\n## Sample Model\n\nGiven a snippet where `stmt.execute(query)` is a SQL injection sink:\n\n```java\npublic static void taintsink(Connection conn, String query) throws SQLException {\n Statement stmt = conn.createStatement();\n stmt.execute(query); // sink: SQL injection\n}\n```\n\n`jdbc.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: sourceModel\n data: []\n\n - addsTo:\n pack: codeql/java-all\n extensible: sinkModel\n data:\n - [\n 'java.sql',\n 'Statement',\n True,\n 'execute',\n '(String)',\n '',\n 'Argument[0]',\n 'sql-injection',\n 'manual'\n ]\n\n - addsTo:\n pack: codeql/java-all\n extensible: summaryModel\n data: []\n\n - addsTo:\n pack: codeql/java-all\n extensible: barrierModel\n data: []\n\n - addsTo:\n pack: codeql/java-all\n extensible: barrierGuardModel\n data: []\n\n - addsTo:\n pack: codeql/java-all\n extensible: neutralModel\n data: []\n```\n\n## Examples\n\n### Source from Network Socket\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: sourceModel\n data:\n - ['java.net', 'Socket', False, 'getInputStream', '()', '', 'ReturnValue', 'remote', 'manual']\n```\n\n### Flow Through `String.concat`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: summaryModel\n data:\n - [\n 'java.lang',\n 'String',\n False,\n 'concat',\n '(String)',\n '',\n 'Argument[this]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n - [\n 'java.lang',\n 'String',\n False,\n 'concat',\n '(String)',\n '',\n 'Argument[0]',\n 'ReturnValue',\n 'taint',\n 'manual'\n ]\n```\n\n### Flow Through Higher-Order Method `Stream.map`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: summaryModel\n data:\n - [\n 'java.util.stream',\n 'Stream',\n True,\n 'map',\n '(Function)',\n '',\n 'Argument[this].Element',\n 'Argument[0].Parameter[0]',\n 'value',\n 'manual'\n ]\n - [\n 'java.util.stream',\n 'Stream',\n True,\n 'map',\n '(Function)',\n '',\n 'Argument[0].ReturnValue',\n 'ReturnValue.Element',\n 'value',\n 'manual'\n ]\n```\n\nNote: Two rows are needed \u2014 one for flow into the lambda parameter, one for flow from the lambda return to the output stream elements.\n\n### Neutral Model\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: neutralModel\n data:\n - ['java.time', 'Instant', 'now', '()', 'summary', 'manual']\n```\n\n### Barrier: Path Injection Prevention\n\nThe `File.getName()` method returns only the final component of a path, which protects against path injection vulnerabilities.\n\n```java\npublic static void barrier(File file) {\n String name = file.getName(); // Only the filename, no directory traversal\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: barrierModel\n data:\n - ['java.io', 'File', True, 'getName', '()', '', 'ReturnValue', 'path-injection', 'manual']\n```\n\nNote: The `kind` `\"path-injection\"` must match the sink kind used by path injection queries. `subtypes: True` ensures the model applies to subclasses of `File`.\n\n### Barrier Guard: Request Forgery Prevention\n\nThe `URI.isAbsolute()` method returns `false` when the URI is relative and therefore safe for request forgery because it cannot redirect to an external server.\n\n```java\npublic static void barrierguard(URI uri) throws IOException {\n if (!uri.isAbsolute()) { // The check guards the request\n URL url = uri.toURL();\n url.openConnection(); // Safe\n }\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/java-all\n extensible: barrierGuardModel\n data:\n - [\n 'java.net',\n 'URI',\n True,\n 'isAbsolute',\n '()',\n '',\n 'Argument[this]',\n 'false',\n 'request-forgery',\n 'manual'\n ]\n```\n\nNote: The `acceptingValue` `\"false\"` means the barrier applies when `isAbsolute` returns false (the URI is relative). The `input` `\"Argument[this]\"` identifies the qualifier (`uri`) whose taint flow is blocked.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/java/ast` \u2014 Java AST class reference\n- [Customizing Library Models for Java and Kotlin](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-java-and-kotlin/)\n";
|
|
198401
|
+
|
|
198023
198402
|
// src/resources/languages/javascript_ast.md
|
|
198024
198403
|
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';
|
|
198025
198404
|
|
|
198405
|
+
// src/resources/languages/javascript_library_modeling.md
|
|
198406
|
+
var javascript_library_modeling_default = "# Customizing Library Models for JavaScript/TypeScript\n\n## Purpose\n\nCustomize data-flow and taint analysis for JavaScript and TypeScript by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/javascript-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## Model Format\n\nJavaScript/TypeScript uses an **API Graph-based** model format with short tuples (3\u20135 columns) \u2014 similar to Python and Ruby. This is fundamentally different from the MaD tuple format used by Java, C#, C++, and Go.\n\n## Extensible Predicates for JavaScript/TypeScript\n\n| Predicate | Columns | Purpose |\n| ------------------- | ------------------------------------ | ------------------------------------------------------------------------ |\n| `sourceModel` | `(type, path, kind)` | Model sources of tainted data |\n| `sinkModel` | `(type, path, kind)` | Model sinks where tainted data is used vulnerably |\n| `summaryModel` | `(type, path, input, output, kind)` | Model flow through function calls |\n| `barrierModel` | `(type, path, kind)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(type, path, acceptingValue, kind)` | Model barrier guards (validators) that stop taint via conditional checks |\n| `typeModel` | `(type1, type2, path)` | Define type relationships |\n\n## Type Column\n\nThe `type` column identifies a starting point for access path evaluation:\n\n- **NPM package name** (e.g., `\"execa\"`, `\"mysql\"`) \u2014 matches imports of that package. If the package name has dots, surround with single quotes: `'lodash.escape'`.\n- **`\"global\"`** \u2014 matches the global object (window). Use this to access global variables/functions like `eval`, `decodeURIComponent`.\n- **Qualified type** `\"<package>.<type>\"` (e.g., `\"mysql.Connection\"`) \u2014 matches expressions known to be instances of that type (via type annotations or `typeModel` definitions).\n\n## Access Paths\n\nAccess paths are `.`-separated, evaluated left to right:\n\n| Component | Description |\n| ----------------- | ------------------------------------------------------------------------------------- |\n| `Member[name]` | Property access with the given name |\n| `AnyMember` | Any property regardless of name |\n| `Argument[n]` | Argument at index n |\n| `Argument[this]` | The receiver of a method call |\n| `Parameter[n]` | Parameter at index n |\n| `Parameter[this]` | The `this` parameter of a function |\n| `ReturnValue` | Return value of a function or call |\n| `ArrayElement` | An element of an array |\n| `MapValue` | A value of a map object |\n| `Awaited` | The value of a resolved promise |\n| `Instance` | Instances of a class (including subclasses) |\n| `Fuzzy` | All values derived from the current value (approximate, useful for complex libraries) |\n\n### Call Site Filters\n\n| Component | Description |\n| ----------------------------- | ------------------------------------------------ |\n| `WithArity[n]` | Calls with exactly n arguments |\n| `WithStringArgument[n=value]` | Calls where argument n is string literal `value` |\n\n### Decorator Components\n\n| Component | Description |\n| -------------------- | ------------------------------------------------------ |\n| `DecoratedClass` | A class decorated by the current value |\n| `DecoratedParameter` | A parameter decorated by the current value |\n| `DecoratedMember` | A method/field/accessor decorated by the current value |\n\n### Middleware Component\n\n| Component | Description |\n| --------------------- | ------------------------------------------------ |\n| `GuardedRouteHandler` | Route handlers guarded by the current middleware |\n\n### Syntax Notes\n\n- Multiple operands: `Member[foo,bar]` matches either `foo` or `bar`\n- Numeric intervals: `Argument[0..2]` matches arguments 0, 1, or 2\n- Last argument: `Argument[N-1]`, second-to-last: `Argument[N-2]`\n\n## Sink Kinds\n\n`code-injection`, `command-injection`, `path-injection`, `sql-injection`, `nosql-injection`, `html-injection`, `request-forgery`, `url-redirection`, `unsafe-deserialization`, `log-injection`\n\n## Threat Models (JS-Specific)\n\nIn addition to `remote` and `local`, JavaScript supports:\n\n- `database-access-result` \u2014 data from database reads\n- `view-component-input` \u2014 inputs to React/Vue/Angular components (props)\n\n## Sample Model\n\nGiven a snippet using the `execa` package:\n\n```javascript\nimport { shell } from 'execa';\nshell(cmd); // sink: command injection\n```\n\n`execa.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: sinkModel\n data:\n - ['execa', 'Member[shell].Argument[0]', 'command-injection']\n```\n\n## Examples\n\n### Source from Window Message Events\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: sourceModel\n data:\n - [\n 'global',\n 'Member[addEventListener].WithStringArgument[0=message].Argument[1].Parameter[0].Member[data]',\n 'remote'\n ]\n```\n\nNote: `WithStringArgument[0=message]` restricts to only `\"message\"` event listeners.\n\n### Using Fuzzy Models\n\nWhen a library is complex and precise modeling is difficult, `Fuzzy` approximates all values derived from a package:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: sinkModel\n data:\n - ['mysql', 'Fuzzy.Member[query].Argument[0]', 'sql-injection']\n```\n\n### typeModel for Untyped Code\n\nWhen code lacks type annotations, use `typeModel` to define that a function returns an instance of a known type:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: typeModel\n data:\n - ['mysql.Connection', '@example/db', 'Member[getConnection].ReturnValue']\n```\n\n### Summary with GuardedRouteHandler\n\nModel a middleware that injects tainted data on `req.data`:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: sourceModel\n data:\n - [\n '@example/middleware',\n 'Member[injectData].ReturnValue.GuardedRouteHandler.Parameter[0].Member[data]',\n 'remote'\n ]\n```\n\n### Barrier: `encodeURIComponent`\n\nThe `encodeURIComponent` function encodes a string for safe use in URLs, preventing HTML injection when the result is used in HTML contexts.\n\n```javascript\nlet escaped = encodeURIComponent(input); // Safe for XSS\ndocument.body.innerHTML = escaped;\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: barrierModel\n data:\n - ['global', 'Member[encodeURIComponent].ReturnValue', 'html-injection']\n```\n\nNote: The `type` `\"global\"` starts at the global object. The `path` navigates to the return value of `encodeURIComponent`. The `kind` `\"html-injection\"` must match the sink kind used by XSS queries.\n\n### Barrier Guard: Validation Function\n\nA barrier guard models a function that returns a boolean indicating whether data is safe. When the function returns the expected value, taint flow is stopped through the guarded branch.\n\n```javascript\nif (isValid(userInput)) {\n // The check guards the use\n db.query(userInput); // Safe\n}\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/javascript-all\n extensible: barrierGuardModel\n data:\n - ['my-package', 'Member[isValid].Argument[0]', 'true', 'sql-injection']\n```\n\nNote: The `acceptingValue` `\"true\"` means the barrier applies when `isValid` returns true. The `path` `\"Member[isValid].Argument[0]\"` identifies the value being validated (the first argument).\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/javascript/ast` \u2014 JavaScript AST class reference\n- `codeql://languages/javascript/security` \u2014 JavaScript security query patterns\n- [Customizing Library Models for JavaScript](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-javascript/)\n";
|
|
198407
|
+
|
|
198026
198408
|
// src/resources/languages/javascript_security_query_guide.md
|
|
198027
198409
|
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";
|
|
198028
198410
|
|
|
198029
198411
|
// src/resources/languages/python_ast.md
|
|
198030
198412
|
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';
|
|
198031
198413
|
|
|
198414
|
+
// src/resources/languages/python_library_modeling.md
|
|
198415
|
+
var python_library_modeling_default = '# Customizing Library Models for Python\n\n## Purpose\n\nCustomize data-flow and taint analysis for Python by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/python-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## Model Format\n\nPython uses an **API Graph-based** model format with short tuples (3\u20135 columns) \u2014 similar to JavaScript/TypeScript and Ruby. Access paths in extensions are powered by API graphs.\n\n## Extensible Predicates for Python\n\n| Predicate | Columns | Purpose |\n| ------------------- | ------------------------------------ | ------------------------------------------------------------------------ |\n| `sourceModel` | `(type, path, kind)` | Model sources of tainted data |\n| `sinkModel` | `(type, path, kind)` | Model sinks where tainted data is used vulnerably |\n| `summaryModel` | `(type, path, input, output, kind)` | Model flow through function calls |\n| `barrierModel` | `(type, path, kind)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(type, path, acceptingValue, kind)` | Model barrier guards (validators) that stop taint via conditional checks |\n| `neutralModel` | `(type, path, kind)` | Mark functions as having no dataflow impact |\n| `typeModel` | `(type1, type2, path)` | Define type relationships |\n\n## Type Column\n\nThe `type` column identifies the top-level Python module import. For example:\n\n- `"flask"` matches `import flask` or `from flask import ...`\n- `"databricks"` matches `import databricks` or `from databricks import ...`\n\n## Access Paths\n\nAccess paths are `.`-separated, evaluated left to right. They mirror Python\'s API graph navigation:\n\n| Component | Description |\n| ------------------- | ------------------------------------------- |\n| `Member[name]` | Attribute access (e.g., `.sql`, `.connect`) |\n| `Argument[n]` | Positional argument at index n |\n| `Argument[name:]` | Keyword argument with the given name |\n| `Argument[n,name:]` | Positional or keyword argument |\n| `ReturnValue` | Return value of a call |\n| `Parameter[n]` | Parameter at index n |\n| `Subclass` | Subclasses of a class |\n\n### API Graph Verification\n\nYou can verify API graph paths by running a QL query against your database:\n\n```ql\nimport python\nimport semmle.python.ApiGraphs\n\nfrom API::CallNode call\nwhere\n call = API::moduleImport("re").getMember("compile").getACall() and\n call.getParameter(0, "pattern") =\n API::moduleImport("argparse")\n .getMember("ArgumentParser")\n .getReturn()\n .getMember("parse_args")\n .getMember(_)\nselect call\n```\n\n### How Access Path Parsing Works\n\nThe path `"Member[sql].Member[connect].ReturnValue.Member[cursor].ReturnValue.Member[execute].Argument[0]"` is tokenized into:\n\n1. `Member[sql]` \u2014 attribute access `.sql`\n2. `Member[connect]` \u2014 attribute access `.connect`\n3. `ReturnValue` \u2014 the return value of calling `.connect()`\n4. `Member[cursor]` \u2014 attribute access `.cursor`\n5. `ReturnValue` \u2014 the return value of calling `.cursor()`\n6. `Member[execute]` \u2014 attribute access `.execute`\n7. `Argument[0]` \u2014 the first argument to `.execute()`\n\n## Sink Kinds\n\n`sql-injection`, `command-injection`, `code-injection`, `path-injection`, `url-redirection`, `log-injection`, `request-forgery`\n\n## Sample Model\n\nGiven this snippet using the Databricks SQL connector:\n\n```python\nfrom flask import Flask, request\nimport databricks.sql as dbsql\n\napp = Flask(__name__)\n\n@app.get("/q")\ndef q():\n s = request.args["s"] # remote user input\n query = "SELECT * FROM users WHERE name=\'" + s + "\'"\n\n with dbsql.connect(server_hostname="HOST", http_path="HTTP_PATH", access_token="TOKEN") as conn:\n with conn.cursor() as cursor:\n cursor.execute(query) # sink we want to model\n return str(cursor.fetchall())\n```\n\n`databricks.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/python-all\n extensible: sourceModel\n data: []\n\n - addsTo:\n pack: codeql/python-all\n extensible: sinkModel\n data:\n - [\n \'databricks\',\n \'Member[sql].Member[connect].ReturnValue.Member[cursor].ReturnValue.Member[execute].Argument[0]\',\n \'sql-injection\'\n ]\n\n - addsTo:\n pack: codeql/python-all\n extensible: summaryModel\n data: []\n\n - addsTo:\n pack: codeql/python-all\n extensible: barrierModel\n data: []\n\n - addsTo:\n pack: codeql/python-all\n extensible: barrierGuardModel\n data: []\n\n - addsTo:\n pack: codeql/python-all\n extensible: neutralModel\n data: []\n\n - addsTo:\n pack: codeql/python-all\n extensible: typeModel\n data: []\n```\n\n## Examples\n\n### Barrier: `html.escape`\n\nThe `html.escape` function HTML-escapes a string, preventing HTML injection (XSS) attacks.\n\n```python\nimport html\nescaped = html.escape(unknown) # Safe for XSS\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/python-all\n extensible: barrierModel\n data:\n - [\'html\', \'Member[escape].ReturnValue\', \'html-injection\']\n```\n\nNote: The `type` `"html"` starts at the `html` module import. The `path` navigates to the return value of `escape`. The `kind` `"html-injection"` must match the sink kind used by XSS queries.\n\n### Barrier Guard: Django URL Validation\n\nThe `url_has_allowed_host_and_scheme` function from Django validates that a URL is safe for redirects.\n\n```python\nif url_has_allowed_host_and_scheme(url, allowed_hosts=...):\n redirect(url) # Safe\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/python-all\n extensible: barrierGuardModel\n data:\n - [\n \'django\',\n \'Member[utils].Member[http].Member[url_has_allowed_host_and_scheme].Argument[0,url:]\',\n \'true\',\n \'url-redirection\'\n ]\n```\n\nNote: The `acceptingValue` `"true"` means the barrier applies when the function returns true. `Argument[0,url:]` matches either the first positional argument or the keyword argument `url`.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/python/ast` \u2014 Python AST class reference\n- `codeql://languages/python/security` \u2014 Python security query patterns\n- [Customizing Library Models for Python](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-python/)\n- [Using API graphs in Python](https://codeql.github.com/docs/codeql-language-guides/using-api-graphs-in-python/)\n';
|
|
198416
|
+
|
|
198032
198417
|
// src/resources/languages/python_security_query_guide.md
|
|
198033
198418
|
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';
|
|
198034
198419
|
|
|
198035
198420
|
// src/resources/languages/ruby_ast.md
|
|
198036
198421
|
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';
|
|
198037
198422
|
|
|
198423
|
+
// src/resources/languages/ruby_library_modeling.md
|
|
198424
|
+
var ruby_library_modeling_default = "# Customizing Library Models for Ruby\n\n## Purpose\n\nCustomize data-flow and taint analysis for Ruby by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/ruby-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## Model Format\n\nRuby uses an **API Graph-based** model format with short tuples (3\u20135 columns) \u2014 similar to JavaScript/TypeScript and Python.\n\n## Extensible Predicates for Ruby\n\n| Predicate | Columns | Purpose |\n| ------------------- | ------------------------------------ | ------------------------------------------------------------------------ |\n| `sourceModel` | `(type, path, kind)` | Model sources of tainted data |\n| `sinkModel` | `(type, path, kind)` | Model sinks where tainted data is used vulnerably |\n| `summaryModel` | `(type, path, input, output, kind)` | Model flow through method calls |\n| `barrierModel` | `(type, path, kind)` | Model barriers (sanitizers) that stop taint flow |\n| `barrierGuardModel` | `(type, path, acceptingValue, kind)` | Model barrier guards (validators) that stop taint via conditional checks |\n| `typeModel` | `(type1, type2, path)` | Define type relationships |\n\n## Type Column\n\nThe `type` column identifies a starting point for access path evaluation:\n\n- A class name like `\"TTY::Command\"` matches instances of that class\n- Appending `!` (e.g., `\"Sinatra::Base!\"`) matches references to the **class itself** rather than instances\n- `typeModel` rows can define aliases so that subtypes inherit all models from a parent type\n\n## Access Paths\n\nAccess paths are `.`-separated, evaluated left to right:\n\n| Component | Description |\n| ----------------------- | ------------------------------------------------------- |\n| `Method[name]` | Calls to the named method |\n| `Argument[n]` | Argument at index n |\n| `Argument[name:]` | Keyword argument with the given name |\n| `Argument[self]` | The receiver of a method call |\n| `Argument[block]` | The block argument |\n| `Argument[any]` | Any argument (except self/block) |\n| `Argument[any-named]` | Any keyword argument |\n| `Argument[hash-splat]` | All keyword arguments (`**kwargs`) |\n| `Parameter[n]` | Parameter at index n |\n| `Parameter[name:]` | Keyword parameter with the given name |\n| `Parameter[self]` | The self parameter |\n| `Parameter[block]` | The block parameter |\n| `Parameter[any]` | Any parameter (except self/block) |\n| `Parameter[any-named]` | Any keyword parameter |\n| `Parameter[hash-splat]` | Hash splat parameter |\n| `ReturnValue` | Return value of a call |\n| `Element[any]` | Any element of an array or hash |\n| `Element[n]` | Array element at the given index |\n| `Element[key]` | Hash element at the given key |\n| `Field[@name]` | Instance variable with the given name |\n| `Fuzzy` | All values derived from the current value (approximate) |\n\n### Syntax Notes\n\n- Multiple operands: `Method[foo,bar]` matches calls to either `foo` or `bar`\n- Numeric ranges: `Argument[1..]` matches all arguments from index 1 onward\n\n## Sink Kinds\n\n`code-injection`, `command-injection`, `path-injection`, `sql-injection`, `url-redirection`, `log-injection`\n\n## Sample Model\n\nGiven a snippet using the `tty-command` gem:\n\n```ruby\ntty = TTY::Command.new\ntty.run(cmd) # sink: command injection\n```\n\n`tty_command.model.yml`\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: sourceModel\n data: []\n\n - addsTo:\n pack: codeql/ruby-all\n extensible: sinkModel\n data:\n - ['TTY::Command', 'Method[run].Argument[0]', 'command-injection']\n\n - addsTo:\n pack: codeql/ruby-all\n extensible: summaryModel\n data: []\n\n - addsTo:\n pack: codeql/ruby-all\n extensible: barrierModel\n data: []\n\n - addsTo:\n pack: codeql/ruby-all\n extensible: barrierGuardModel\n data: []\n\n - addsTo:\n pack: codeql/ruby-all\n extensible: typeModel\n data: []\n```\n\n## Examples\n\n### Flow Through a Method\n\nModel flow through `URI.decode_uri_component`:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: summaryModel\n data:\n - ['URI!', 'Method[decode_uri_component]', 'Argument[0]', 'ReturnValue', 'taint']\n```\n\nNote: `URI!` with the `!` suffix matches the class itself (not instances), since `decode_uri_component` is a class method.\n\n### Source from Block Parameters\n\nModel `x` in a Sinatra route block as a remote source:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: sourceModel\n data:\n - ['Sinatra::Base!', 'Method[get].Argument[block].Parameter[0]', 'remote']\n```\n\n### typeModel for Subclass Inheritance\n\nWhen `Mysql2::EM::Client` is a subclass of `Mysql2::Client`, add a type model so all parent models apply:\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: typeModel\n data:\n - ['Mysql2::Client', 'Mysql2::EM::Client', '']\n```\n\n### Barrier: `Mysql2::Client#escape`\n\nThe `escape` method on `Mysql2::Client` escapes special characters in a string for use in SQL statements, preventing SQL injection.\n\n```ruby\nclient = Mysql2::Client.new\nescaped = client.escape(input) # Safe for SQL injection\nclient.query(\"SELECT * FROM users WHERE name = '#{escaped}'\")\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: barrierModel\n data:\n - ['Mysql2::Client', 'Method[escape].ReturnValue', 'sql-injection']\n```\n\nNote: The `type` `\"Mysql2::Client\"` matches instances of the class. The `kind` `\"sql-injection\"` must match the sink kind used by SQL injection queries.\n\n### Barrier Guard: Validation Method\n\nA barrier guard models a method that returns a boolean indicating whether data is safe. When the method returns the expected value, taint flow is stopped through the guarded branch.\n\n```ruby\nif Validator.is_safe(user_input)\n # The check guards the use, so the input is safe.\n client.query(\"SELECT * FROM users WHERE name = '#{user_input}'\")\nend\n```\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/ruby-all\n extensible: barrierGuardModel\n data:\n - ['Validator!', 'Method[is_safe].Argument[0]', 'true', 'sql-injection']\n```\n\nNote: The `!` suffix on `\"Validator!\"` matches the class itself (not instances), since `is_safe` is a class method. The `acceptingValue` `\"true\"` means the barrier applies when `is_safe` returns true.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview\n- `codeql://languages/ruby/ast` \u2014 Ruby AST class reference\n- [Customizing Library Models for Ruby](https://codeql.github.com/docs/codeql-language-guides/customizing-library-models-for-ruby/)\n- [Using API graphs in Ruby](https://codeql.github.com/docs/codeql-language-guides/using-api-graphs-in-ruby/)\n";
|
|
198425
|
+
|
|
198038
198426
|
// src/resources/languages/rust_ast.md
|
|
198039
198427
|
var rust_ast_default = '# CodeQL AST Classes for Rust Programs\n\n## Purpose\n\nWrite CodeQL queries over Rust by navigating the Rust AST classes. Model: Syntax \u2192 CodeQL class hierarchy; use predicates to access parts (fields, expressions, patterns). Pattern: `get<Part>()`, `getA<Part>()`, `getName().getText()`, `getBody()`.\n\n## Core Namespaces\n\n- **Items**: `Function`, `Struct`, `Enum`, `Impl`, `Trait`, `Module`, `Const`, `Static`, `TypeAlias`, `Use`, `ExternBlock`\n- **Expressions**: subclasses of `Expr` (literals, calls, operators, blocks, control flow)\n- **Statements**: `LetStmt`, `ExprStmt`\n- **Patterns**: `IdentPat`, `TuplePat`, `StructPat`, `TupleStructPat`, `WildcardPat`, `RefPat`, `LiteralPat`, `RangePat`\n- **Types**: `PathTypeRepr`, `RefTypeRepr`, `TupleTypeRepr`, `ArrayTypeRepr`, `SliceTypeRepr`, `FnPtrTypeRepr`\n- **Paths**: `Path`, `PathSegment`, `NameRef`\n- **Names**: `Name` (use `.getText()` to get the string value)\n\n## Items\n\n### Functions\n\n- **`Function`** \u2014 Function declaration: `fn foo(x: u32) -> u64 { ... }`\n - `getName()` \u2192 `Name` (use `.getText()` for string)\n - `getParamList()` \u2192 `ParamList`\n - `getRetType()` \u2192 `RetTypeRepr`\n - `getFunctionBody()` \u2192 `BlockExpr`\n - `getAbi()` \u2192 `Abi` (for `extern "C" fn`)\n\n### Structs and Enums\n\n- **`Struct`** \u2014 Struct declaration\n - `getName()` \u2192 `Name`\n - `getFieldList()` \u2192 `StructFieldList` or `TupleFieldList`\n- **`Enum`** \u2014 Enum declaration\n - `getName()` \u2192 `Name`\n - `getVariantList()` \u2192 `VariantList`\n- **`Variant`** \u2014 Enum variant\n - `getName()` \u2192 `Name`\n - `getFieldList()` \u2192 field list\n\n### Implementations and Traits\n\n- **`Impl`** \u2014 Implementation block: `impl Foo { ... }` or `impl Trait for Foo { ... }`\n - `getAssocItemList()` \u2192 `AssocItemList`\n - `getTrait()` \u2192 trait path (for trait implementations)\n- **`Trait`** \u2014 Trait declaration\n - `getName()` \u2192 `Name`\n - `getAssocItemList()` \u2192 `AssocItemList`\n\n### Other Items\n\n- **`Module`** \u2014 Module declaration: `mod foo { ... }`\n- **`Use`** \u2014 Use import: `use std::io;`\n- **`Const`** \u2014 Constant: `const X: i32 = 42;`\n- **`Static`** \u2014 Static variable: `static Y: &str = "hello";`\n- **`TypeAlias`** \u2014 Type alias: `type Result<T> = std::result::Result<T, Error>;`\n\n## Expressions (Expr)\n\n### Literals\n\n- **`IntegerLiteralExpr`** \u2014 Integer: `42`, `0xFF`\n- **`FloatLiteralExpr`** \u2014 Float: `3.14`\n- **`BooleanLiteralExpr`** \u2014 Boolean: `true`, `false`\n- **`StringLiteralExpr`** \u2014 String: `"hello"`\n- **`CharLiteralExpr`** \u2014 Character: `\'a\'`\n- **`ByteLiteralExpr`** \u2014 Byte: `b\'x\'`\n- **`ByteStringLiteralExpr`** \u2014 Byte string: `b"hello"`\n\n### Calls and Method Calls\n\n- **`CallExpr`** \u2014 Function call: `foo(42)`\n - `getFunction()` \u2192 callee expression\n - `getArgList()` \u2192 `ArgList`\n - `getResolvedTarget()` \u2192 resolved `Addressable`\n - `getEnclosingCallable()` \u2192 enclosing `Callable`\n- **`MethodCallExpr`** \u2014 Method call: `x.foo(42)`\n - `getReceiver()` \u2192 receiver expression\n - `getIdentifier()` \u2192 `NameRef` (method name)\n - `getArgList()` \u2192 `ArgList`\n\n### Operators\n\n- **`BinaryExpr`** \u2014 Binary: `x + y`, `x && y`, `x <= y`, `x = y`\n - `getLhs()`, `getRhs()` \u2192 operands\n - `getOperatorName()` \u2192 operator string\n- **`UnaryExpr`** / **`PrefixExpr`** \u2014 Unary: `-x`, `!x`, `*x`, `&x`\n- **`RangeExpr`** \u2014 Range: `0..10`, `0..=10`\n\n### Control Flow\n\n- **`IfExpr`** \u2014 if/else: `if cond { ... } else { ... }`\n - `getCondition()`, `getThen()`, `getElse()`\n- **`MatchExpr`** \u2014 Pattern matching: `match x { ... }`\n - `getScrutinee()` \u2192 scrutinee expression\n - `getMatchArmList()` \u2192 `MatchArmList`\n- **`MatchArm`** \u2014 Match arm: `pat => expr`\n - `getPat()` \u2192 pattern\n - `getExpr()` \u2192 body\n - `getGuard()` \u2192 optional guard\n- **`LoopExpr`** \u2014 Infinite loop: `loop { ... }`\n- **`WhileExpr`** \u2014 While loop: `while cond { ... }`\n - `getCondition()`, `getBody()`\n- **`ForExpr`** \u2014 For loop: `for x in iter { ... }`\n - `getPat()` \u2192 loop variable pattern\n - `getIterable()` \u2192 iterator expression\n - `getLoopBody()` \u2192 loop body\n- **`BreakExpr`** \u2014 Break: `break` or `break \'label value`\n- **`ContinueExpr`** \u2014 Continue: `continue` or `continue \'label`\n- **`ReturnExpr`** \u2014 Return: `return value`\n\n### Blocks and Closures\n\n- **`BlockExpr`** \u2014 Block: `{ stmts; tail_expr }`\n - `getStmtList()` \u2192 `StmtList`\n- **`ClosureExpr`** \u2014 Closure: `|x| x + 1`, `move |x| { ... }`\n - `getParamList()` \u2192 parameters\n - `getBody()` \u2192 body expression\n- **`AsyncBlockExpr`** \u2014 Async block: `async { ... }`\n- **`UnsafeBlockExpr`** \u2014 Unsafe block: `unsafe { ... }`\n\n### Field and Index Access\n\n- **`FieldExpr`** \u2014 Field access: `x.field`\n - `getContainer()` \u2192 receiver\n - `getIdentifier()` \u2192 `NameRef` (field name)\n- **`IndexExpr`** \u2014 Index: `arr[i]`\n- **`TupleExpr`** \u2014 Tuple: `(a, b, c)`\n- **`ArrayExpr`** / **`ArrayListExpr`** \u2014 Array: `[1, 2, 3]`\n\n### Other Expressions\n\n- **`PathExpr`** \u2014 Path reference: `std::io::stdin`\n- **`StructExpr`** \u2014 Struct literal: `Point { x: 1, y: 2 }`\n- **`CastExpr`** \u2014 Type cast: `x as u64`\n- **`RefExpr`** \u2014 Reference: `&x`, `&mut x`\n- **`AwaitExpr`** \u2014 Await: `future.await`\n- **`TryExpr`** \u2014 Try operator: `expr?`\n- **`MacroExpr`** \u2014 Macro invocation expression\n - `getMacroCall()` \u2192 `MacroCall`\n\n## Statements\n\n- **`LetStmt`** \u2014 Let binding: `let x: i32 = 42;`\n - `getPat()` \u2192 pattern\n - `getTypeRepr()` \u2192 optional type annotation\n - `getInitializer()` \u2192 optional initializer\n- **`ExprStmt`** \u2014 Expression statement: `foo();`\n - `getExpr()` \u2192 expression\n\n## Patterns (Pat)\n\n- **`IdentPat`** \u2014 Variable pattern: `x`, `mut x`, `ref x`\n - `getName()` \u2192 `Name`\n- **`WildcardPat`** \u2014 Wildcard: `_`\n- **`TuplePat`** \u2014 Tuple: `(a, b)`\n- **`StructPat`** \u2014 Struct: `Point { x, y }`\n- **`TupleStructPat`** \u2014 Tuple struct: `Some(x)`\n- **`LiteralPat`** \u2014 Literal: `42`, `"hello"`\n- **`RangePat`** \u2014 Range: `0..=10`\n- **`RefPat`** \u2014 Reference: `&x`, `&mut x`\n- **`OrPat`** \u2014 Or pattern: `A | B`\n\n## Navigation Idioms\n\n```ql\n// Find all function definitions\nfrom Function f\nwhere f.fromSource()\nselect f, f.getName().getText()\n\n// Find all calls to a specific function\nfrom CallExpr call, Function target\nwhere\n call.getResolvedTarget() = target and\n target.getName().getText() = "dangerous_fn"\nselect call, "Call to dangerous_fn"\n\n// Find all struct field accesses\nfrom FieldExpr fe\nwhere fe.getIdentifier().getText() = "password"\nselect fe, "Access to password field"\n\n// Find match expressions with wildcard patterns\nfrom MatchExpr m, MatchArm arm\nwhere\n arm = m.getMatchArmList().getAnArm() and\n arm.getPat() instanceof WildcardPat\nselect m, "Match with wildcard arm"\n\n// Navigate from method call to receiver type\nfrom MethodCallExpr call\nwhere call.getIdentifier().getText() = "unwrap"\nselect call, call.getReceiver()\n```\n\n## File and Module Navigation\n\n- **`SourceFile`** \u2014 Top-level file node\n - `getItem(i)` \u2192 i-th item\n- **`Module`** \u2014 Module declaration\n - `getName()` \u2192 `Name`\n - `getItemList()` \u2192 items in module\n\n## Key API Differences from Other Languages\n\n- `Function.getName()` returns a `Name` object, not a string \u2014 use `.getText()` to get the string value\n- `CallExpr.getResolvedTarget()` returns an `Addressable` \u2014 cast to `Function` when needed\n- `CallExpr.getEnclosingCallable()` returns a `Callable` \u2014 encompasses both `Function` and `ClosureExpr`\n- Rust has no `class` concept \u2014 use `Struct`, `Enum`, `Impl`, and `Trait` instead\n- Macro expansions are represented as `MacroExpr` \u2192 `MacroCall` \u2192 expansion\n\n## Tips\n\n- Use `fromSource()` to filter out elements from macro expansions and library code\n- Use `.getName().getText()` instead of `.getName()` when comparing with strings\n- `MethodCallExpr` and `CallExpr` are separate types \u2014 a unified `Call` type also exists\n- Pattern matching is pervasive in Rust; many constructs use `Pat` subclasses\n- Block expressions (`BlockExpr`) can appear anywhere an expression is expected\n- The `?` operator creates a `TryExpr` node, not a method call\n';
|
|
198040
198428
|
|
|
198429
|
+
// src/resources/languages/rust_library_modeling.md
|
|
198430
|
+
var rust_library_modeling_default = "# Customizing Library Models for Rust\n\n## Purpose\n\nCustomize data-flow and taint analysis for Rust by modeling crates and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party crates not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\n\n> Rust MaD support in CodeQL is evolving; column layouts and supported predicates may change between CodeQL releases. Always cross-reference the upstream `codeql/rust-all` pack and the official [CodeQL docs for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-for-rust/) for the column layout in use by the CodeQL CLI version pinned in this repo.\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/rust-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## Model Format\n\nRust uses a **MaD (Models as Data)** format keyed on **crate path** (`crate::module::Type::method`-style canonical paths) rather than the namespace/type/name/signature columns used by Java/C#/C++/Go. Tuples are typically shorter than the MaD-tuple-format languages and closer in spirit to the API-graph access-path style used by JavaScript/Python/Ruby \u2014 but the exact column layout is defined by the `codeql/rust-all` pack.\n\n## Extensible Predicates for Rust\n\n| Predicate | Purpose |\n| -------------- | --------------------------------------------------------------------- |\n| `sourceModel` | Model sources of tainted data (e.g. data read from network or env) |\n| `sinkModel` | Model sinks where tainted data is used unsafely |\n| `summaryModel` | Model flow through opaque library functions (taint or value flow) |\n| `neutralModel` | Mark functions as having no dataflow impact (suppress generated rows) |\n\nRefer to `codeql/rust-all` (the `ext/*.model.yml` files in the upstream `codeql` repository under `rust/ql/lib/ext/`) for canonical examples of the exact tuple shape required by the current CodeQL CLI release.\n\n## Crate Path Column\n\nThe crate path identifies a function or method by its fully qualified Rust path:\n\n- Free function: `tokio::fs::read_to_string`\n- Inherent method: `<std::path::PathBuf>::push`\n- Trait method: `<T as core::iter::Iterator>::next`\n- Generic types may need to be normalised (e.g. lifetime/type parameters elided) per the upstream pack's conventions.\n\n## Access Paths\n\nRust models use access paths similar to other MaD languages, with `Argument[n]`, `Argument[self]`, `ReturnValue`, and (where supported) field/element selectors. Always validate against `codeql/rust-all` for which selectors are supported by the current release.\n\n## Common Sink Kinds\n\n`command-injection`, `path-injection`, `sql-injection`, `request-forgery`, `url-redirection`, `code-injection`\n\n## Sample Model\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/rust-all\n extensible: sinkModel\n data:\n - [\n 'repo:https://github.com/rust-lang/rust:std',\n '<crate::process::Command>::arg',\n 'Argument[0]',\n 'command-injection',\n 'manual'\n ]\n```\n\n> The exact column count and ordering above is **illustrative**; verify against the `codeql/rust-all` pack shipped with the CodeQL CLI version recorded in `.codeql-version`. Authoring a tuple with the wrong column count will fail to load (often silently).\n\n## Validation Workflow\n\n1. Place `*.model.yml` files in your model-pack directory (or under `.github/codeql/extensions/` for the single-repo path).\n2. Run `codeql_query_run` against a database that exercises the modelled APIs and confirm new findings appear (sources/sinks) or expected findings disappear (barriers/neutrals).\n3. Add a unit test that exercises the new chain end-to-end using `codeql_test_run`.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview (both model formats)\n- `codeql://languages/rust/ast` \u2014 Rust AST class reference\n- [CodeQL for Rust](https://codeql.github.com/docs/codeql-language-guides/codeql-for-rust/) \u2014 Official Rust language guide\n";
|
|
198431
|
+
|
|
198432
|
+
// src/resources/languages/swift_library_modeling.md
|
|
198433
|
+
var swift_library_modeling_default = "# Customizing Library Models for Swift\n\n## Purpose\n\nCustomize data-flow and taint analysis for Swift by modeling frameworks and libraries via data extensions (YAML) and model packs. This enables accurate flow tracking through third-party libraries not included in CodeQL databases.\n\nFor common guidance on data extensions (YAML structure, model packs, development workflow), see `codeql://learning/data-extensions`.\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/swift-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## Model Format\n\nSwift uses a **MaD (Models as Data)** format with multi-column tuples that identify callables by module/type/name/signature \u2014 the same structural family as Java/Kotlin, C#, C/C++, and Go. Methods are keyed on Swift's module-qualified type and method names (e.g. `Foundation.URLRequest.init(url:)`).\n\n## Extensible Predicates for Swift\n\n| Predicate | Purpose |\n| -------------- | --------------------------------------------------------------------- |\n| `sourceModel` | Model sources of tainted data |\n| `sinkModel` | Model sinks where tainted data is used unsafely |\n| `summaryModel` | Model flow through opaque library functions/methods |\n| `barrierModel` | Model barriers (sanitizers) that stop taint flow |\n| `neutralModel` | Mark callables as having no dataflow impact (suppress generated rows) |\n\nRefer to `codeql/swift-all` (the `ext/*.model.yml` files under `swift/ql/lib/ext/` in the upstream `codeql` repository) for the canonical column layout used by the current CodeQL CLI release. Authoring a tuple with the wrong column count will fail to load (often silently).\n\n## Identifier Columns\n\nSwift models typically identify a callable by:\n\n- **module** \u2014 Swift module name (e.g. `Foundation`, `UIKit`, the package/target name for third-party code)\n- **type** \u2014 Type name (`\"\"` for module-level free functions)\n- **subtypes** \u2014 Whether to apply to subtypes (`true`/`false`)\n- **name** \u2014 Method or function name (e.g. `init(url:)`, `data(using:)`)\n- **signature** \u2014 Parameter signature (`\"\"` for any)\n\nThe exact column count and order is defined by the `codeql/swift-all` pack \u2014 always cross-check before authoring rows.\n\n## Access Paths\n\nSwift access paths follow the same conventions as the other MaD-tuple languages:\n\n| Component | Description |\n| ---------------- | ----------------------------------------------- |\n| `Argument[n]` | Argument at index n (0-based, excluding `self`) |\n| `Argument[self]` | The receiver of a method call |\n| `Parameter[n]` | Parameter at index n (used by `summaryModel`) |\n| `ReturnValue` | Return value of a call |\n\n## Common Sink Kinds\n\n`command-injection`, `path-injection`, `sql-injection`, `request-forgery`, `url-redirection`, `code-injection`, `predicate-injection`\n\n## Sample Model\n\n```yaml\nextensions:\n - addsTo:\n pack: codeql/swift-all\n extensible: sinkModel\n data:\n - [\n 'Foundation',\n 'NSPredicate',\n false,\n 'init(format:argumentArray:)',\n '',\n '',\n 'Argument[0]',\n 'predicate-injection',\n 'manual'\n ]\n```\n\n> The exact column count above is **illustrative**; verify against the `codeql/swift-all` pack shipped with the CodeQL CLI version recorded in `.codeql-version`.\n\n## Validation Workflow\n\n1. Place `*.model.yml` files in your model-pack directory (or under `.github/codeql/extensions/` for the single-repo path).\n2. Run `codeql_query_run` against a database that exercises the modelled APIs and confirm new findings appear (sources/sinks) or expected findings disappear (barriers/neutrals).\n3. Add a unit test that exercises the new chain end-to-end using `codeql_test_run`.\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview (both model formats)\n- [CodeQL for Swift](https://codeql.github.com/docs/codeql-language-guides/codeql-for-swift/) \u2014 Official Swift language guide\n";
|
|
198434
|
+
|
|
198041
198435
|
// src/types/language-types.ts
|
|
198042
198436
|
var LANGUAGE_RESOURCES = [
|
|
198043
198437
|
{
|
|
@@ -198047,12 +198441,18 @@ var LANGUAGE_RESOURCES = [
|
|
|
198047
198441
|
{
|
|
198048
198442
|
language: "cpp",
|
|
198049
198443
|
astContent: cpp_ast_default,
|
|
198050
|
-
securityContent: cpp_security_query_guide_default
|
|
198444
|
+
securityContent: cpp_security_query_guide_default,
|
|
198445
|
+
additionalResources: {
|
|
198446
|
+
"library-modeling": cpp_library_modeling_default
|
|
198447
|
+
}
|
|
198051
198448
|
},
|
|
198052
198449
|
{
|
|
198053
198450
|
language: "csharp",
|
|
198054
198451
|
astContent: csharp_ast_default,
|
|
198055
|
-
securityContent: csharp_security_query_guide_default
|
|
198452
|
+
securityContent: csharp_security_query_guide_default,
|
|
198453
|
+
additionalResources: {
|
|
198454
|
+
"library-modeling": csharp_library_modeling_default
|
|
198455
|
+
}
|
|
198056
198456
|
},
|
|
198057
198457
|
{
|
|
198058
198458
|
language: "go",
|
|
@@ -198066,25 +198466,46 @@ var LANGUAGE_RESOURCES = [
|
|
|
198066
198466
|
},
|
|
198067
198467
|
{
|
|
198068
198468
|
language: "java",
|
|
198069
|
-
astContent: java_ast_default
|
|
198469
|
+
astContent: java_ast_default,
|
|
198470
|
+
additionalResources: {
|
|
198471
|
+
"library-modeling": java_library_modeling_default
|
|
198472
|
+
}
|
|
198070
198473
|
},
|
|
198071
198474
|
{
|
|
198072
198475
|
language: "javascript",
|
|
198073
198476
|
astContent: javascript_ast_default,
|
|
198074
|
-
securityContent: javascript_security_query_guide_default
|
|
198477
|
+
securityContent: javascript_security_query_guide_default,
|
|
198478
|
+
additionalResources: {
|
|
198479
|
+
"library-modeling": javascript_library_modeling_default
|
|
198480
|
+
}
|
|
198075
198481
|
},
|
|
198076
198482
|
{
|
|
198077
198483
|
language: "python",
|
|
198078
198484
|
astContent: python_ast_default,
|
|
198079
|
-
securityContent: python_security_query_guide_default
|
|
198485
|
+
securityContent: python_security_query_guide_default,
|
|
198486
|
+
additionalResources: {
|
|
198487
|
+
"library-modeling": python_library_modeling_default
|
|
198488
|
+
}
|
|
198080
198489
|
},
|
|
198081
198490
|
{
|
|
198082
198491
|
language: "ruby",
|
|
198083
|
-
astContent: ruby_ast_default
|
|
198492
|
+
astContent: ruby_ast_default,
|
|
198493
|
+
additionalResources: {
|
|
198494
|
+
"library-modeling": ruby_library_modeling_default
|
|
198495
|
+
}
|
|
198084
198496
|
},
|
|
198085
198497
|
{
|
|
198086
198498
|
language: "rust",
|
|
198087
|
-
astContent: rust_ast_default
|
|
198499
|
+
astContent: rust_ast_default,
|
|
198500
|
+
additionalResources: {
|
|
198501
|
+
"library-modeling": rust_library_modeling_default
|
|
198502
|
+
}
|
|
198503
|
+
},
|
|
198504
|
+
{
|
|
198505
|
+
language: "swift",
|
|
198506
|
+
additionalResources: {
|
|
198507
|
+
"library-modeling": swift_library_modeling_default
|
|
198508
|
+
}
|
|
198088
198509
|
}
|
|
198089
198510
|
];
|
|
198090
198511
|
|
|
@@ -198167,7 +198588,7 @@ function registerLanguageResources(server) {
|
|
|
198167
198588
|
|
|
198168
198589
|
// src/prompts/workflow-prompts.ts
|
|
198169
198590
|
import { access as access2 } from "fs/promises";
|
|
198170
|
-
import { basename as
|
|
198591
|
+
import { basename as basename10, isAbsolute as isAbsolute8, normalize, relative as relative3, resolve as resolve13, sep as sep4 } from "path";
|
|
198171
198592
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
198172
198593
|
|
|
198173
198594
|
// src/prompts/constants.ts
|
|
@@ -198183,17 +198604,28 @@ var SUPPORTED_LANGUAGES = [
|
|
|
198183
198604
|
"rust",
|
|
198184
198605
|
"swift"
|
|
198185
198606
|
];
|
|
198607
|
+
var MAD_SUPPORTED_LANGUAGES = [
|
|
198608
|
+
"cpp",
|
|
198609
|
+
"csharp",
|
|
198610
|
+
"go",
|
|
198611
|
+
"java",
|
|
198612
|
+
"javascript",
|
|
198613
|
+
"python",
|
|
198614
|
+
"ruby",
|
|
198615
|
+
"rust",
|
|
198616
|
+
"swift"
|
|
198617
|
+
];
|
|
198186
198618
|
|
|
198187
198619
|
// src/prompts/prompt-completions.ts
|
|
198188
198620
|
import { readdir, readFile as readFile4 } from "fs/promises";
|
|
198189
198621
|
import { homedir as homedir2 } from "os";
|
|
198190
|
-
import { dirname as dirname9, join as join22, relative, sep as
|
|
198622
|
+
import { dirname as dirname9, join as join22, relative as relative2, sep as sep3 } from "path";
|
|
198191
198623
|
init_logger();
|
|
198192
198624
|
init_package_paths();
|
|
198193
198625
|
var MAX_FILE_COMPLETIONS = 50;
|
|
198194
198626
|
var MAX_SCAN_DEPTH = 8;
|
|
198195
198627
|
var CACHE_TTL_MS = 5e3;
|
|
198196
|
-
var
|
|
198628
|
+
var SKIP_DIRS2 = getScanExcludeDirs();
|
|
198197
198629
|
var scanCache = /* @__PURE__ */ new Map();
|
|
198198
198630
|
function getCachedResults(cacheKey2) {
|
|
198199
198631
|
const entry = scanCache.get(cacheKey2);
|
|
@@ -198221,14 +198653,14 @@ async function findFilesByExtension(dir, baseDir, extensions, maxDepth, results)
|
|
|
198221
198653
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198222
198654
|
const fullPath = join22(dir, entry.name);
|
|
198223
198655
|
if (entry.isDirectory()) {
|
|
198224
|
-
if (
|
|
198656
|
+
if (SKIP_DIRS2.has(entry.name)) {
|
|
198225
198657
|
continue;
|
|
198226
198658
|
}
|
|
198227
198659
|
await findFilesByExtension(fullPath, baseDir, extensions, maxDepth - 1, results);
|
|
198228
198660
|
} else if (entry.isFile()) {
|
|
198229
198661
|
const lower = entry.name.toLowerCase();
|
|
198230
198662
|
if (extensions.some((ext) => lower.endsWith(ext))) {
|
|
198231
|
-
results.push(
|
|
198663
|
+
results.push(relative2(baseDir, fullPath));
|
|
198232
198664
|
}
|
|
198233
198665
|
}
|
|
198234
198666
|
}
|
|
@@ -198312,7 +198744,7 @@ async function completeDatabasePath(value) {
|
|
|
198312
198744
|
}
|
|
198313
198745
|
const lower = (value || "").toLowerCase();
|
|
198314
198746
|
const filtered = allResults.filter((p) => {
|
|
198315
|
-
const lastSeg = p.split(
|
|
198747
|
+
const lastSeg = p.split(sep3).pop() ?? "";
|
|
198316
198748
|
return p.toLowerCase().includes(lower) || lastSeg.toLowerCase().includes(lower);
|
|
198317
198749
|
}).sort();
|
|
198318
198750
|
return filtered.slice(0, MAX_FILE_COMPLETIONS);
|
|
@@ -198334,7 +198766,7 @@ async function findDatabaseDirs(dir, _baseDir, maxDepth, results) {
|
|
|
198334
198766
|
}
|
|
198335
198767
|
for (const entry of entries) {
|
|
198336
198768
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198337
|
-
if (entry.isDirectory() && !
|
|
198769
|
+
if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
|
|
198338
198770
|
await findDatabaseDirs(join22(dir, entry.name), _baseDir, maxDepth - 1, results);
|
|
198339
198771
|
}
|
|
198340
198772
|
}
|
|
@@ -198357,11 +198789,11 @@ async function completePackRoot(value) {
|
|
|
198357
198789
|
(e) => e.isFile() && e.name === "codeql-pack.yml"
|
|
198358
198790
|
);
|
|
198359
198791
|
if (hasPackYml) {
|
|
198360
|
-
results.push(
|
|
198792
|
+
results.push(relative2(workspace, dir) || ".");
|
|
198361
198793
|
}
|
|
198362
198794
|
for (const entry of entries) {
|
|
198363
198795
|
if (results.length >= MAX_FILE_COMPLETIONS) break;
|
|
198364
|
-
if (entry.isDirectory() && !
|
|
198796
|
+
if (entry.isDirectory() && !SKIP_DIRS2.has(entry.name)) {
|
|
198365
198797
|
await scan(join22(dir, entry.name), depth - 1);
|
|
198366
198798
|
}
|
|
198367
198799
|
}
|
|
@@ -198472,6 +198904,9 @@ var check_for_duplicated_code_prompt_default = '---\nagent: agent\n---\n\n# Chec
|
|
|
198472
198904
|
// src/prompts/compare-overlapping-alerts.prompt.md
|
|
198473
198905
|
var compare_overlapping_alerts_prompt_default = '---\nagent: agent\n---\n\n# Compare Overlapping Alerts\n\n## Goal\n\nCompare CodeQL SARIF alerts across **any combination** of SARIF files, analysis runs, CodeQL databases, CodeQL versions, or query packs. Detect overlapping, redundant, or divergent results and classify each finding to guide query development decisions.\n\nThis workflow supports:\n\n- Comparing alerts from **different rules** in the same SARIF (e.g., standard vs custom queries)\n- Comparing alerts from **different SARIF files** (e.g., two separate `codeql database analyze` runs)\n- Checking for **behavioral deviations** across CodeQL CLI versions or database rebuilds\n- Detecting **redundancy** between custom query packs and standard query packs\n\n## Workflow\n\n### Step 1: Discover available rules\n\nUse #sarif_list_rules on each SARIF source to understand what rules and result counts are present. When comparing within a single file, call it once:\n\n```\nsarif_list_rules(sarifPath="{{sarifPathA}}")\n```\n\nWhen comparing two different SARIF files, call it on both:\n\n```\nsarif_list_rules(sarifPath="{{sarifPathA}}")\nsarif_list_rules(sarifPath="{{sarifPathB}}")\n```\n\nThe response includes `ruleId`, `resultCount`, `kind`, `precision`, `severity`, and `tags` for each rule.\n\n### Step 2: Choose a comparison strategy\n\nDepending on the use case, choose the appropriate strategy:\n\n**Same-file, different rules** (custom vs standard overlap):\n\n- Use #sarif_extract_rule to extract each rule\'s results from the same file\n- Use #sarif_compare_alerts to compare individual alert pairs\n\n**Different files, same rule** (behavioral deviation across runs):\n\n- Use #sarif_diff_runs to get a high-level diff of added/removed/changed rules\n- For changed rules, use #sarif_extract_rule on both files and compare results\n\n**Different files, different rules** (cross-pack overlap):\n\n- Use #sarif_extract_rule on each file with the respective rule IDs\n- Use #sarif_compare_alerts with different `sarifPath` values for alertA and alertB\n\n### Step 3: Diff runs (for cross-run comparison)\n\nWhen comparing two analysis runs, start with a structural diff:\n\n```\nsarif_diff_runs(\n sarifPathA="{{sarifPathA}}",\n sarifPathB="{{sarifPathB}}",\n labelA="baseline",\n labelB="comparison"\n)\n```\n\nThis returns `addedRules`, `removedRules`, `changedRules` (with result count deltas), and `unchangedRules`. Focus investigation on `changedRules` and `addedRules`.\n\n### Step 4: Extract and visualize results\n\nFor rules of interest, extract full results and generate markdown reports:\n\n```\nsarif_extract_rule(sarifPath="{{sarifPathA}}", ruleId="<ruleId>")\nsarif_rule_to_markdown(sarifPath="{{sarifPathA}}", ruleId="<ruleId>")\n```\n\nThe markdown report includes:\n\n- Rule summary with severity, precision, tags\n- Query help text\n- Results table with file, line, and message\n- Mermaid `flowchart LR` diagrams for each dataflow path\n\n### Step 5: Compare specific alerts for overlap\n\nUse #sarif_compare_alerts to compare individual results between rules or files. Each alert specifier can reference a **different SARIF file**:\n\n```\nsarif_compare_alerts(\n alertA={sarifPath="{{sarifPathA}}", ruleId="<ruleIdA>", resultIndex=0},\n alertB={sarifPath="{{sarifPathB}}", ruleId="<ruleIdB>", resultIndex=0},\n overlapMode="sink"\n)\n```\n\nIf sink overlap is found, re-check with `source` and `full-path` modes:\n\n- **sink**: same primary alert location (file + line + column range overlap)\n- **source**: same dataflow source (first step in threadFlow)\n- **any-location**: any location in alertA overlaps any location in alertB (including intermediate steps)\n- **full-path**: Jaccard similarity on dataflow path steps; `pathSimilarity` 0.0\u20131.0\n\n### Step 6: Read source code context\n\nFor each overlapping pair, use #read_database_source to read the relevant source file from the CodeQL database. **Note**: the `filePath` parameter uses the URI from the SARIF alert location, not an absolute path:\n\n```\nread_database_source(databasePath="{{databasePath}}", filePath="<uri-from-alert>")\n```\n\nRead 10\u201320 lines around the flagged location for context. When comparing across databases, read from each database separately.\n\n### Step 7: Classify each finding\n\nFor each overlapping or divergent pair, classify as:\n\n1. **Redundant** \u2014 Same problem, same or very similar code path (`pathSimilarity > 0.7`). One query subsumes the other.\n - **Action**: add a `not` exclusion predicate to the more specific query, or configure alert suppression\n\n2. **Complementary** \u2014 Same sink but different source models or taint configurations (`pathSimilarity < 0.3`). Both queries add defensive value.\n - **Action**: keep both; document the overlap in query help text\n\n3. **False overlap** \u2014 Same file and line but semantically different issues (different arguments, different properties).\n - **Action**: no change needed\n\n4. **Behavioral regression** \u2014 A rule that previously found N results now finds fewer (or zero). Visible via #sarif_diff_runs `changedRules`.\n - **Action**: investigate query or library changes between CodeQL versions\n\n5. **New coverage** \u2014 A rule appears in `addedRules` or has increased results. Indicates improved detection.\n - **Action**: review new results for false positive rate\n\n### Step 8: Produce summary\n\nCreate a structured summary with:\n\n- SARIF sources compared (file paths, labels, tool versions)\n- Total alerts per rule per source\n- Run diff summary: added/removed/changed rule counts\n- For each overlap: classification, both alert messages, shared locations, path similarity\n- Recommendations: which queries to prioritize, exclusion predicates to add, follow-up analysis needed\n\n## Notes\n\n- `ruleId` values correspond to CodeQL query `@id` metadata (e.g., `js/sql-injection`)\n- #sarif_compare_alerts supports **cross-file** comparison: `alertA.sarifPath` and `alertB.sarifPath` can be different files\n- #sarif_diff_runs compares by rule ID, not by result content \u2014 use it for high-level structural comparison, then drill into individual alerts\n- #read_database_source requires the database path \u2014 pass via the `databasePath` parameter or resolve it with #list_codeql_databases\n- When working from cached results, substitute `cacheKey` for `sarifPath` in all tool calls\n- Path similarity above 0.7 usually indicates redundancy; below 0.3 indicates complementary coverage\n- For cross-version comparison, run `codeql database analyze` with two different CodeQL CLI versions against the same database, save both SARIF files, and use #sarif_diff_runs to compare\n';
|
|
198474
198906
|
|
|
198907
|
+
// src/prompts/data-extension-development.prompt.md
|
|
198908
|
+
var data_extension_development_prompt_default = '---\nagent: agent\n---\n\n# Data Extension Development Workflow\n\nUse this workflow to create CodeQL data extensions (Models-as-Data) for third-party libraries and frameworks. Data extensions let you customize taint tracking without writing QL code \u2014 you author YAML files that declare which functions are sources, sinks, summaries, barriers, or barrier guards.\n\nFor format reference, read the MCP resource: `codeql://learning/data-extensions`\nFor language-specific guidance, read the corresponding `codeql://languages/<language>/library-modeling` resource. Available for: `cpp`, `csharp`, `go`, `java`, `javascript`, `python`, `ruby`, `rust`, `swift`.\n\n## Workflow Checklist\n\n### Phase 1: Identify the Target\n\n- [ ] **Confirm the target library and language**\n - Library name and version: {{libraryName}}\n - Target language: {{language}}\n - Determine the model format:\n - **MaD tuple format** (9\u201310 column tuples): C/C++ (`codeql/cpp-all`), C# (`codeql/csharp-all`), Go (`codeql/go-all`), Java/Kotlin (`codeql/java-all`), Swift (`codeql/swift-all`)\n - **API Graph format** (3\u20135 column tuples): JavaScript/TypeScript (`codeql/javascript-all`), Python (`codeql/python-all`), Ruby (`codeql/ruby-all`)\n - **Rust format**: Rust (`codeql/rust-all`) uses its own crate-path-based model format; follow `codeql://languages/rust/library-modeling`\n - Using the wrong format will cause the extension to silently fail to load.\n\n- [ ] **Locate a CodeQL database**\n - Tool: #list_codeql_databases\n - Or create one: #codeql_database_create\n - The database must contain code that exercises the target library\n\n- [ ] **Explore the library\'s API surface**\n - Tool: #read_database_source \u2014 browse source files to identify relevant API calls\n - Tool: #codeql_query_run with `queryName="PrintAST"` \u2014 visualize how library calls are represented\n - Skim the library\'s public API docs, type stubs, or source code\n\n### Phase 2: Classify the API Surface\n\nFor each public function or method on the library, classify it:\n\n1. **Does it return data from outside the program** (network, file, env, stdin)? \u2192 `sourceModel` with `kind` matching the threat model (usually `"remote"`)\n2. **Does it consume data in a security-sensitive operation** (SQL, exec, path, redirect, eval, deserialize)? \u2192 `sinkModel` with `kind` matching the vulnerability class (e.g. `"sql-injection"`, `"command-injection"`)\n3. **Does it pass data through opaque library code** (encode, decode, wrap, copy, iterate)? \u2192 `summaryModel` with `kind: "taint"` (derived) or `kind: "value"` (identity)\n4. **Does it sanitize data so its output is safe for a specific sink kind?** \u2192 `barrierModel` with `kind` matching the sink kind it neutralizes\n5. **Does it return a boolean indicating whether data is safe?** \u2192 `barrierGuardModel` with the appropriate `acceptingValue` (`"true"` or `"false"`) and matching `kind`\n6. **Is the type a subclass of something already modeled?** \u2192 `typeModel` (API Graph languages) or set `subtypes: True` (MaD tuple languages)\n7. **Did the auto-generated model assign a wrong summary?** \u2192 `neutralModel` to suppress it\n\nA complete chain of **source \u2192 (summary\\*) \u2192 sink** is required for end-to-end findings; missing a single hop will cause false negatives.\n\n### Phase 3: Choose the Deployment Scope\n\nChoose between two paths:\n\n- **Single-repo shortcut** \u2014 drop `.model.yml` files under `.github/codeql/extensions/<pack-name>/` in the consuming repo. **No `codeql-pack.yml` is required**; Code Scanning auto-loads extensions from this directory. Use when the models only need to apply to one repo.\n- **Reusable model pack** \u2014 create a pack directory with a `codeql-pack.yml` declaring `extensionTargets` and `dataExtensions`. Use when models will be consumed by multiple repos or by org-wide Default Setup.\n\n### Phase 4: Author the `.model.yml` File(s)\n\n- [ ] **Create the model file**\n - Use naming convention `<library>-<module>.model.yml` (lowercase, hyphen-separated)\n - Split per logical module rather than putting an entire ecosystem in one file\n - Read `codeql://languages/{{language}}/library-modeling` for the exact column layout and examples\n\n- [ ] **Write the YAML with correct extensible predicates**\n\n ```yaml\n extensions:\n - addsTo:\n pack: codeql/{{language}}-all\n extensible: sinkModel\n data:\n # Add tuples here \u2014 column count must exactly match the predicate schema\n - [...]\n ```\n\n - Every row must have the **exact column count** for its extensible predicate \u2014 an invalid row will fail silently or cause errors\n - Use `provenance: \'manual\'` (MaD format) for hand-written rows\n - Ensure `kind` values match across the chain (e.g. a `"sql-injection"` barrier must guard a `"sql-injection"` sink)\n\n### Phase 5: Configure `codeql-pack.yml` (Model-Pack Path Only)\n\nSkip this step if you chose the `.github/codeql/extensions/` shortcut in Phase 3.\n\nFor a reusable pack, create or update `codeql-pack.yml`:\n\n```yaml\nname: <org>/<language>-<pack-name>\nversion: 0.0.1\nlibrary: true\nextensionTargets:\n codeql/<language>-all: \'*\'\ndataExtensions:\n - models/**/*.yml\n```\n\n- `library: true` \u2014 model packs are always libraries, never queries\n- `extensionTargets` \u2014 names the upstream pack the extensions extend\n- `dataExtensions` \u2014 a glob that picks up every `.model.yml` you author\n\n- [ ] **Install pack dependencies**\n - Tool: #codeql_pack_install \u2014 resolve dependencies for the model pack\n\n### Phase 6: Test with `codeql query run`\n\nValidate the model against a real database:\n\n- [ ] **Run a relevant security query with the extension applied**\n - Tool: #codeql_query_run\n - Pass the model pack directory via the `additionalPacks` parameter\n - Pick a query whose sink kind matches what you modeled (e.g. a `sql-injection` query when adding SQL sinks)\n - Decode results: #codeql_bqrs_decode or #codeql_bqrs_interpret\n\n- [ ] **Verify expected findings appear**\n - New sources/sinks should produce findings that were absent without the extension\n - Barriers/barrier guards should suppress findings that were previously reported\n\n### Phase 7: Run Unit Tests with `codeql test run`\n\n- [ ] **Create a test case for the extension**\n - Write a small test file that exercises the new source/sink/summary chain end-to-end\n - Include both positive cases (vulnerable code detected) and negative cases (safe code not flagged)\n\n- [ ] **Run the tests**\n - Tool: #codeql_test_run\n - Pass the model pack directory via the `additionalPacks` parameter\n - Note: `codeql test run` does **not** accept `--model-packs`; extensions must be wired via `codeql-pack.yml` or `--additional-packs`\n\n- [ ] **Accept correct results**\n - Tool: #codeql_test_accept \u2014 accept the `.actual` output as the `.expected` baseline once you confirm it is correct\n\n### Phase 8: Decide Next Steps\n\n- If the `.model.yml` lives under `.github/codeql/extensions/` of the consuming repo, you are **done** \u2014 Code Scanning will load it on the next analysis.\n- If you authored a reusable model pack and want it to apply across an organization, publish it to GHCR with `codeql pack publish` and configure it under org Code security \u2192 Global settings \u2192 CodeQL analysis \u2192 Model packs.\n\n## Validation Checklist\n\n- [ ] Correct tuple format for the language (API Graph vs MaD)\n- [ ] Every row has the exact column count for its extensible predicate\n- [ ] Sink/barrier `kind` values match across the chain\n- [ ] At least one end-to-end test exercises the new model and produces expected findings\n- [ ] `codeql-pack.yml` `dataExtensions` glob actually matches the new files\n- [ ] No regressions in pre-existing tests under the same pack\n\n## Related Resources\n\n- `codeql://learning/data-extensions` \u2014 Common data extensions overview (both model formats)\n- `codeql://languages/{{language}}/library-modeling` \u2014 Language-specific library modeling guide\n- `codeql://templates/security` \u2014 Security query templates\n- `codeql://learning/test-driven-development` \u2014 TDD workflow for CodeQL queries\n';
|
|
198909
|
+
|
|
198475
198910
|
// src/prompts/document-codeql-query.prompt.md
|
|
198476
198911
|
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, rust, 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';
|
|
198477
198912
|
|
|
@@ -198509,6 +198944,7 @@ var workshop_creation_workflow_prompt_default = '---\nagent: agent\n---\n\n# Cre
|
|
|
198509
198944
|
var PROMPT_TEMPLATES = {
|
|
198510
198945
|
"check-for-duplicated-code.prompt.md": check_for_duplicated_code_prompt_default,
|
|
198511
198946
|
"compare-overlapping-alerts.prompt.md": compare_overlapping_alerts_prompt_default,
|
|
198947
|
+
"data-extension-development.prompt.md": data_extension_development_prompt_default,
|
|
198512
198948
|
"document-codeql-query.prompt.md": document_codeql_query_prompt_default,
|
|
198513
198949
|
"explain-codeql-query.prompt.md": explain_codeql_query_prompt_default,
|
|
198514
198950
|
"find-overlapping-queries.prompt.md": find_overlapping_queries_prompt_default,
|
|
@@ -198599,11 +199035,11 @@ async function resolvePromptFilePath(filePath, workspaceRoot) {
|
|
|
198599
199035
|
}
|
|
198600
199036
|
const effectiveRoot = workspaceRoot ?? getUserWorkspaceDir();
|
|
198601
199037
|
const normalizedPath = normalize(effectivePath);
|
|
198602
|
-
const inputWasAbsolute =
|
|
199038
|
+
const inputWasAbsolute = isAbsolute8(normalizedPath);
|
|
198603
199039
|
const absolutePath = inputWasAbsolute ? normalizedPath : resolve13(effectiveRoot, normalizedPath);
|
|
198604
199040
|
if (!inputWasAbsolute) {
|
|
198605
|
-
const rel =
|
|
198606
|
-
if (rel === ".." || rel.startsWith(`..${
|
|
199041
|
+
const rel = relative3(effectiveRoot, absolutePath);
|
|
199042
|
+
if (rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute8(rel)) {
|
|
198607
199043
|
return {
|
|
198608
199044
|
blocked: true,
|
|
198609
199045
|
resolvedPath: "",
|
|
@@ -198621,6 +199057,11 @@ async function resolvePromptFilePath(filePath, workspaceRoot) {
|
|
|
198621
199057
|
}
|
|
198622
199058
|
return { resolvedPath: absolutePath };
|
|
198623
199059
|
}
|
|
199060
|
+
var dataExtensionDevelopmentSchema = external_exports.object({
|
|
199061
|
+
language: external_exports.enum(MAD_SUPPORTED_LANGUAGES).describe("Programming language for the data extension (Models-as-Data supported languages only)"),
|
|
199062
|
+
libraryName: external_exports.string().optional().describe("Name of the library or framework to model"),
|
|
199063
|
+
database: external_exports.string().optional().describe("Path to a CodeQL database for testing the extension")
|
|
199064
|
+
});
|
|
198624
199065
|
var testDrivenDevelopmentSchema = external_exports.object({
|
|
198625
199066
|
language: external_exports.enum(SUPPORTED_LANGUAGES).describe("Programming language for the query"),
|
|
198626
199067
|
queryName: external_exports.string().optional().describe("Name of the query to develop")
|
|
@@ -198770,6 +199211,7 @@ Please check your inputs and try again.`
|
|
|
198770
199211
|
var WORKFLOW_PROMPT_NAMES = [
|
|
198771
199212
|
"check_for_duplicated_code",
|
|
198772
199213
|
"compare_overlapping_alerts",
|
|
199214
|
+
"data_extension_development",
|
|
198773
199215
|
"document_codeql_query",
|
|
198774
199216
|
"explain_codeql_query",
|
|
198775
199217
|
"find_overlapping_queries",
|
|
@@ -198873,7 +199315,7 @@ ${content}`
|
|
|
198873
199315
|
const langResult = await getEffectiveLanguage("workshop_creation_workflow", language, resolvedQueryPath);
|
|
198874
199316
|
const effectiveLanguage = langResult.language;
|
|
198875
199317
|
if (langResult.warning) warnings.push(langResult.warning);
|
|
198876
|
-
const derivedName = workshopName ||
|
|
199318
|
+
const derivedName = workshopName || basename10(resolvedQueryPath).replace(/\.(ql|qlref)$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-") || "codeql-workshop";
|
|
198877
199319
|
const contextSection = buildWorkshopContext(
|
|
198878
199320
|
resolvedQueryPath,
|
|
198879
199321
|
effectiveLanguage ?? "unknown",
|
|
@@ -199127,6 +199569,54 @@ ${content}`
|
|
|
199127
199569
|
}
|
|
199128
199570
|
)
|
|
199129
199571
|
);
|
|
199572
|
+
server.prompt(
|
|
199573
|
+
"data_extension_development",
|
|
199574
|
+
"End-to-end workflow for creating CodeQL data extensions (Models-as-Data) for third-party libraries",
|
|
199575
|
+
addCompletions(toPermissiveShape(dataExtensionDevelopmentSchema.shape)),
|
|
199576
|
+
createSafePromptHandler(
|
|
199577
|
+
"data_extension_development",
|
|
199578
|
+
dataExtensionDevelopmentSchema,
|
|
199579
|
+
async ({ language, libraryName, database }) => {
|
|
199580
|
+
const template = loadPromptTemplate("data-extension-development.prompt.md");
|
|
199581
|
+
const warnings = [];
|
|
199582
|
+
let resolvedDatabase = database || "<database-path>";
|
|
199583
|
+
if (database) {
|
|
199584
|
+
const dbResult = await resolvePromptFilePath(database);
|
|
199585
|
+
if (dbResult.blocked) return blockedPathError(dbResult, "database path");
|
|
199586
|
+
resolvedDatabase = dbResult.resolvedPath;
|
|
199587
|
+
if (dbResult.warning) warnings.push(dbResult.warning);
|
|
199588
|
+
}
|
|
199589
|
+
const content = processPromptTemplate(template, {
|
|
199590
|
+
language,
|
|
199591
|
+
libraryName: libraryName || "<library-name>"
|
|
199592
|
+
});
|
|
199593
|
+
let contextSection = "## Data Extension Context\n\n";
|
|
199594
|
+
contextSection += `- **Language**: ${language}
|
|
199595
|
+
`;
|
|
199596
|
+
if (libraryName) {
|
|
199597
|
+
contextSection += `- **Library**: ${libraryName}
|
|
199598
|
+
`;
|
|
199599
|
+
}
|
|
199600
|
+
if (database) {
|
|
199601
|
+
contextSection += `- **Database**: ${markdownInlineCode(resolvedDatabase)}
|
|
199602
|
+
`;
|
|
199603
|
+
}
|
|
199604
|
+
contextSection += "\n";
|
|
199605
|
+
const warningSection = warnings.length > 0 ? warnings.join("\n") + "\n\n" : "";
|
|
199606
|
+
return {
|
|
199607
|
+
messages: [
|
|
199608
|
+
{
|
|
199609
|
+
role: "user",
|
|
199610
|
+
content: {
|
|
199611
|
+
type: "text",
|
|
199612
|
+
text: warningSection + contextSection + content
|
|
199613
|
+
}
|
|
199614
|
+
}
|
|
199615
|
+
]
|
|
199616
|
+
};
|
|
199617
|
+
}
|
|
199618
|
+
)
|
|
199619
|
+
);
|
|
199130
199620
|
server.prompt(
|
|
199131
199621
|
"document_codeql_query",
|
|
199132
199622
|
"Create or update documentation for a CodeQL query - generates standardized markdown documentation as a sibling file to the query",
|
|
@@ -200247,13 +200737,6 @@ function generateListRecommendations(sessions) {
|
|
|
200247
200737
|
// src/tools/annotation-tools.ts
|
|
200248
200738
|
init_logger();
|
|
200249
200739
|
function registerAnnotationTools(server) {
|
|
200250
|
-
const config2 = sessionDataManager.getConfig();
|
|
200251
|
-
if (!config2.enableAnnotationTools) {
|
|
200252
|
-
logger.info(
|
|
200253
|
-
"Annotation tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable annotation_* tools."
|
|
200254
|
-
);
|
|
200255
|
-
return;
|
|
200256
|
-
}
|
|
200257
200740
|
registerAnnotationCreateTool(server);
|
|
200258
200741
|
registerAnnotationGetTool(server);
|
|
200259
200742
|
registerAnnotationListTool(server);
|
|
@@ -200388,13 +200871,6 @@ function registerAnnotationSearchTool(server) {
|
|
|
200388
200871
|
init_logger();
|
|
200389
200872
|
var AUDIT_CATEGORY = "audit-finding";
|
|
200390
200873
|
function registerAuditTools(server) {
|
|
200391
|
-
const config2 = sessionDataManager.getConfig();
|
|
200392
|
-
if (!config2.enableAnnotationTools) {
|
|
200393
|
-
logger.info(
|
|
200394
|
-
"Audit tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable audit_* and annotation_* tools."
|
|
200395
|
-
);
|
|
200396
|
-
return;
|
|
200397
|
-
}
|
|
200398
200874
|
registerAuditStoreFindingsTool(server);
|
|
200399
200875
|
registerAuditListFindingsTool(server);
|
|
200400
200876
|
registerAuditAddNotesTool(server);
|
|
@@ -200562,13 +201038,6 @@ function registerAuditClearRepoTool(server) {
|
|
|
200562
201038
|
// src/tools/cache-tools.ts
|
|
200563
201039
|
init_logger();
|
|
200564
201040
|
function registerCacheTools(server) {
|
|
200565
|
-
const config2 = sessionDataManager.getConfig();
|
|
200566
|
-
if (!config2.enableAnnotationTools) {
|
|
200567
|
-
logger.info(
|
|
200568
|
-
"Cache tools are disabled (opt-in). Set ENABLE_ANNOTATION_TOOLS=true to enable query_results_cache_* tools."
|
|
200569
|
-
);
|
|
200570
|
-
return;
|
|
200571
|
-
}
|
|
200572
201041
|
registerQueryResultsCacheLookupTool(server);
|
|
200573
201042
|
registerQueryResultsCacheRetrieveTool(server);
|
|
200574
201043
|
registerQueryResultsCacheClearTool(server);
|
|
@@ -200615,8 +201084,14 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200615
201084
|
"Retrieve cached query results with optional subset selection. Supports line ranges (for graphtext/CSV) and SARIF result indices and file filtering to return only the relevant portion.",
|
|
200616
201085
|
{
|
|
200617
201086
|
cacheKey: external_exports.string().describe("The cache key of the result to retrieve."),
|
|
200618
|
-
lineRange: external_exports.
|
|
200619
|
-
|
|
201087
|
+
lineRange: external_exports.object({
|
|
201088
|
+
start: external_exports.number().int().min(1).describe("First line to include (1-indexed, inclusive)."),
|
|
201089
|
+
end: external_exports.number().int().min(1).describe("Last line to include (1-indexed, inclusive).")
|
|
201090
|
+
}).refine(({ start, end }) => start <= end, { message: "lineRange.start must be <= lineRange.end" }).optional().describe("Line range {start, end} (1-indexed, inclusive). For graphtext/CSV output only."),
|
|
201091
|
+
resultIndices: external_exports.object({
|
|
201092
|
+
start: external_exports.number().int().min(0).describe("First SARIF result index to include (0-indexed, inclusive)."),
|
|
201093
|
+
end: external_exports.number().int().min(0).describe("Last SARIF result index to include (0-indexed, inclusive).")
|
|
201094
|
+
}).refine(({ start, end }) => start <= end, { message: "resultIndices.start must be <= resultIndices.end" }).optional().describe("SARIF result index range {start, end} (0-indexed, inclusive). For SARIF output only."),
|
|
200620
201095
|
fileFilter: external_exports.string().optional().describe("For SARIF: only include results whose file path contains this string."),
|
|
200621
201096
|
maxLines: external_exports.number().int().positive().optional().describe("Maximum number of lines to return for line-based formats (default: 500)."),
|
|
200622
201097
|
maxResults: external_exports.number().int().positive().optional().describe("Maximum number of SARIF results to return (default: 100).")
|
|
@@ -200630,7 +201105,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200630
201105
|
const isSarif = meta.outputFormat.includes("sarif");
|
|
200631
201106
|
if (isSarif) {
|
|
200632
201107
|
const subset2 = store.getCacheSarifSubset(cacheKey2, {
|
|
200633
|
-
resultIndices,
|
|
201108
|
+
resultIndices: resultIndices ? [resultIndices.start, resultIndices.end] : void 0,
|
|
200634
201109
|
fileFilter,
|
|
200635
201110
|
maxResults
|
|
200636
201111
|
});
|
|
@@ -200661,7 +201136,7 @@ function registerQueryResultsCacheRetrieveTool(server) {
|
|
|
200661
201136
|
};
|
|
200662
201137
|
}
|
|
200663
201138
|
const subset = store.getCacheContentSubset(cacheKey2, {
|
|
200664
|
-
lineRange,
|
|
201139
|
+
lineRange: lineRange ? [lineRange.start, lineRange.end] : void 0,
|
|
200665
201140
|
maxLines: maxLines ?? 500
|
|
200666
201141
|
});
|
|
200667
201142
|
if (!subset) {
|
|
@@ -200758,26 +201233,25 @@ function registerQueryResultsCacheCompareTool(server) {
|
|
|
200758
201233
|
import { readFileSync as readFileSync13 } from "fs";
|
|
200759
201234
|
init_logger();
|
|
200760
201235
|
function registerSarifTools(server) {
|
|
200761
|
-
|
|
200762
|
-
|
|
200763
|
-
|
|
200764
|
-
|
|
200765
|
-
);
|
|
200766
|
-
return;
|
|
200767
|
-
}
|
|
201236
|
+
registerSarifCompareAlertsTool(server);
|
|
201237
|
+
registerSarifDeduplicateRulesTool(server);
|
|
201238
|
+
registerSarifDiffByCommitsTool(server);
|
|
201239
|
+
registerSarifDiffRunsTool(server);
|
|
200768
201240
|
registerSarifExtractRuleTool(server);
|
|
200769
201241
|
registerSarifListRulesTool(server);
|
|
200770
201242
|
registerSarifRuleToMarkdownTool(server);
|
|
200771
|
-
|
|
200772
|
-
registerSarifDiffRunsTool(server);
|
|
201243
|
+
registerSarifStoreTool(server);
|
|
200773
201244
|
logger.info("Registered SARIF analysis tools");
|
|
200774
201245
|
}
|
|
200775
|
-
function loadSarif(
|
|
200776
|
-
|
|
200777
|
-
|
|
201246
|
+
function loadSarif(opts) {
|
|
201247
|
+
const { cacheKey: cacheKey2, inlineContent, sarifPath } = opts;
|
|
201248
|
+
if (!sarifPath && !cacheKey2 && !inlineContent) {
|
|
201249
|
+
return { error: "No SARIF source provided." };
|
|
200778
201250
|
}
|
|
200779
201251
|
let content;
|
|
200780
|
-
if (
|
|
201252
|
+
if (inlineContent) {
|
|
201253
|
+
content = inlineContent;
|
|
201254
|
+
} else if (cacheKey2) {
|
|
200781
201255
|
const store = sessionDataManager.getStore();
|
|
200782
201256
|
const cached2 = store.getCacheContent(cacheKey2);
|
|
200783
201257
|
if (!cached2) {
|
|
@@ -200821,7 +201295,7 @@ function registerSarifExtractRuleTool(server) {
|
|
|
200821
201295
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200822
201296
|
},
|
|
200823
201297
|
async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
|
|
200824
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201298
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200825
201299
|
if (loaded.error) {
|
|
200826
201300
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200827
201301
|
}
|
|
@@ -200858,7 +201332,7 @@ function registerSarifListRulesTool(server) {
|
|
|
200858
201332
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200859
201333
|
},
|
|
200860
201334
|
async ({ sarifPath, cacheKey: cacheKey2 }) => {
|
|
200861
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201335
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200862
201336
|
if (loaded.error) {
|
|
200863
201337
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200864
201338
|
}
|
|
@@ -200886,7 +201360,7 @@ function registerSarifRuleToMarkdownTool(server) {
|
|
|
200886
201360
|
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
200887
201361
|
},
|
|
200888
201362
|
async ({ sarifPath, cacheKey: cacheKey2, ruleId }) => {
|
|
200889
|
-
const loaded = loadSarif(sarifPath, cacheKey2);
|
|
201363
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
200890
201364
|
if (loaded.error) {
|
|
200891
201365
|
return { content: [{ type: "text", text: loaded.error }] };
|
|
200892
201366
|
}
|
|
@@ -200917,18 +201391,18 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200917
201391
|
});
|
|
200918
201392
|
server.tool(
|
|
200919
201393
|
"sarif_compare_alerts",
|
|
200920
|
-
"Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location,
|
|
201394
|
+
"Compare code locations of two SARIF alerts to detect overlap. Supports sink, source, any-location, full-path, and fingerprint comparison modes.",
|
|
200921
201395
|
{
|
|
200922
201396
|
alertA: alertSpecSchema.describe("First alert to compare."),
|
|
200923
201397
|
alertB: alertSpecSchema.describe("Second alert to compare."),
|
|
200924
|
-
overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity).')
|
|
201398
|
+
overlapMode: external_exports.enum(["sink", "source", "any-location", "full-path", "fingerprint"]).optional().default("sink").describe('Comparison mode: "sink" (primary locations), "source" (first dataflow step), "any-location" (all locations), "full-path" (structural path similarity), "fingerprint" (partialFingerprints match, falls back to full-path).')
|
|
200925
201399
|
},
|
|
200926
201400
|
async ({ alertA, alertB, overlapMode }) => {
|
|
200927
|
-
const loadedA = loadSarif(alertA.sarifPath, alertA.cacheKey);
|
|
201401
|
+
const loadedA = loadSarif({ sarifPath: alertA.sarifPath, cacheKey: alertA.cacheKey });
|
|
200928
201402
|
if (loadedA.error) {
|
|
200929
201403
|
return { content: [{ type: "text", text: `Alert A: ${loadedA.error}` }] };
|
|
200930
201404
|
}
|
|
200931
|
-
const loadedB = loadSarif(alertB.sarifPath, alertB.cacheKey);
|
|
201405
|
+
const loadedB = loadSarif({ sarifPath: alertB.sarifPath, cacheKey: alertB.cacheKey });
|
|
200932
201406
|
if (loadedB.error) {
|
|
200933
201407
|
return { content: [{ type: "text", text: `Alert B: ${loadedB.error}` }] };
|
|
200934
201408
|
}
|
|
@@ -200967,6 +201441,12 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200967
201441
|
if (overlap.pathSimilarity !== void 0) {
|
|
200968
201442
|
response.pathSimilarity = overlap.pathSimilarity;
|
|
200969
201443
|
}
|
|
201444
|
+
if (overlap.fingerprintMatch !== void 0) {
|
|
201445
|
+
response.fingerprintMatch = overlap.fingerprintMatch;
|
|
201446
|
+
}
|
|
201447
|
+
if (overlap.matchedFingerprints !== void 0) {
|
|
201448
|
+
response.matchedFingerprints = overlap.matchedFingerprints;
|
|
201449
|
+
}
|
|
200970
201450
|
return {
|
|
200971
201451
|
content: [{
|
|
200972
201452
|
type: "text",
|
|
@@ -200976,6 +201456,81 @@ function registerSarifCompareAlertsTool(server) {
|
|
|
200976
201456
|
}
|
|
200977
201457
|
);
|
|
200978
201458
|
}
|
|
201459
|
+
function parseGitDiffOutput(diffOutput) {
|
|
201460
|
+
const files = [];
|
|
201461
|
+
let currentFile = null;
|
|
201462
|
+
for (const line of diffOutput.split(/\r?\n/)) {
|
|
201463
|
+
if (line.startsWith("+++ b/")) {
|
|
201464
|
+
if (currentFile) files.push(currentFile);
|
|
201465
|
+
currentFile = { hunks: [], path: line.substring(6) };
|
|
201466
|
+
continue;
|
|
201467
|
+
}
|
|
201468
|
+
if (currentFile && line.startsWith("@@")) {
|
|
201469
|
+
const match = line.match(/@@ [^ ]+ \+(\d+)(?:,(\d+))? @@/);
|
|
201470
|
+
if (match) {
|
|
201471
|
+
currentFile.hunksParsed = true;
|
|
201472
|
+
const startLine = parseInt(match[1], 10);
|
|
201473
|
+
const lineCount = match[2] !== void 0 ? parseInt(match[2], 10) : 1;
|
|
201474
|
+
if (lineCount > 0) {
|
|
201475
|
+
currentFile.hunks.push({ startLine, lineCount });
|
|
201476
|
+
}
|
|
201477
|
+
}
|
|
201478
|
+
}
|
|
201479
|
+
}
|
|
201480
|
+
if (currentFile) files.push(currentFile);
|
|
201481
|
+
return files;
|
|
201482
|
+
}
|
|
201483
|
+
function registerSarifDiffByCommitsTool(server) {
|
|
201484
|
+
server.tool(
|
|
201485
|
+
"sarif_diff_by_commits",
|
|
201486
|
+
'Correlate SARIF results with a git diff to classify findings as "new" (introduced in the diff) or "pre-existing". Accepts a SARIF file and a git ref range (e.g. "main..HEAD"). Supports file-level or line-level granularity.',
|
|
201487
|
+
{
|
|
201488
|
+
cacheKey: external_exports.string().optional().describe("Cache key to read SARIF from (alternative to sarifPath)."),
|
|
201489
|
+
granularity: external_exports.enum(["file", "line"]).optional().default("file").describe('Matching granularity: "file" classifies any result in a changed file as new; "line" additionally checks that the result line falls within a changed hunk. Default: "file".'),
|
|
201490
|
+
refRange: external_exports.string().describe('Git ref range for the diff (e.g. "main..HEAD", "abc123..def456"). Passed directly to `git diff`.'),
|
|
201491
|
+
repoPath: external_exports.string().optional().describe("Path to the git repository. Defaults to the current working directory."),
|
|
201492
|
+
sarifPath: external_exports.string().optional().describe("Path to the SARIF file.")
|
|
201493
|
+
},
|
|
201494
|
+
async ({ sarifPath, cacheKey: cacheKey2, refRange, repoPath, granularity }) => {
|
|
201495
|
+
if (/^\s*-/.test(refRange) || /\s/.test(refRange)) {
|
|
201496
|
+
return {
|
|
201497
|
+
content: [{
|
|
201498
|
+
type: "text",
|
|
201499
|
+
text: 'Invalid refRange: must not start with "-" or contain whitespace.'
|
|
201500
|
+
}]
|
|
201501
|
+
};
|
|
201502
|
+
}
|
|
201503
|
+
const loaded = loadSarif({ sarifPath, cacheKey: cacheKey2 });
|
|
201504
|
+
if (loaded.error) {
|
|
201505
|
+
return { content: [{ type: "text", text: loaded.error }] };
|
|
201506
|
+
}
|
|
201507
|
+
const { executeCLICommand: executeCLICommand2 } = await Promise.resolve().then(() => (init_cli_executor(), cli_executor_exports));
|
|
201508
|
+
const gitArgs = ["diff", "--unified=0", "--diff-filter=ACMR", "--no-color", refRange];
|
|
201509
|
+
const gitResult = await executeCLICommand2({
|
|
201510
|
+
args: gitArgs,
|
|
201511
|
+
command: "git",
|
|
201512
|
+
cwd: repoPath
|
|
201513
|
+
});
|
|
201514
|
+
if (!gitResult.success) {
|
|
201515
|
+
return {
|
|
201516
|
+
content: [{
|
|
201517
|
+
type: "text",
|
|
201518
|
+
text: `git diff failed: ${gitResult.error ?? gitResult.stderr}`
|
|
201519
|
+
}]
|
|
201520
|
+
};
|
|
201521
|
+
}
|
|
201522
|
+
const diffFiles = parseGitDiffOutput(gitResult.stdout);
|
|
201523
|
+
const g = granularity;
|
|
201524
|
+
const result = diffSarifByCommits(loaded.sarif, diffFiles, refRange, g);
|
|
201525
|
+
return {
|
|
201526
|
+
content: [{
|
|
201527
|
+
type: "text",
|
|
201528
|
+
text: JSON.stringify(result, null, 2)
|
|
201529
|
+
}]
|
|
201530
|
+
};
|
|
201531
|
+
}
|
|
201532
|
+
);
|
|
201533
|
+
}
|
|
200979
201534
|
function registerSarifDiffRunsTool(server) {
|
|
200980
201535
|
server.tool(
|
|
200981
201536
|
"sarif_diff_runs",
|
|
@@ -200989,11 +201544,11 @@ function registerSarifDiffRunsTool(server) {
|
|
|
200989
201544
|
sarifPathB: external_exports.string().optional().describe("Path to the second (comparison) SARIF file.")
|
|
200990
201545
|
},
|
|
200991
201546
|
async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, labelA, labelB }) => {
|
|
200992
|
-
const loadedA = loadSarif(sarifPathA, cacheKeyA);
|
|
201547
|
+
const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
|
|
200993
201548
|
if (loadedA.error) {
|
|
200994
201549
|
return { content: [{ type: "text", text: `Run A: ${loadedA.error}` }] };
|
|
200995
201550
|
}
|
|
200996
|
-
const loadedB = loadSarif(sarifPathB, cacheKeyB);
|
|
201551
|
+
const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
|
|
200997
201552
|
if (loadedB.error) {
|
|
200998
201553
|
return { content: [{ type: "text", text: `Run B: ${loadedB.error}` }] };
|
|
200999
201554
|
}
|
|
@@ -201011,6 +201566,165 @@ function registerSarifDiffRunsTool(server) {
|
|
|
201011
201566
|
}
|
|
201012
201567
|
);
|
|
201013
201568
|
}
|
|
201569
|
+
function registerSarifStoreTool(server) {
|
|
201570
|
+
server.tool(
|
|
201571
|
+
"sarif_store",
|
|
201572
|
+
"Store SARIF content in the session cache for use by other sarif_* tools. Returns a cache key that can be passed to sarifPath/cacheKey parameters of other tools.",
|
|
201573
|
+
{
|
|
201574
|
+
label: external_exports.string().optional().describe('Human-readable label for this SARIF (e.g. "dubbo-java-2025-03").'),
|
|
201575
|
+
sarifContent: external_exports.string().optional().describe("SARIF JSON content as a string (alternative to sarifPath)."),
|
|
201576
|
+
sarifPath: external_exports.string().optional().describe("Path to a SARIF file on disk.")
|
|
201577
|
+
},
|
|
201578
|
+
async ({ sarifContent, sarifPath, label }) => {
|
|
201579
|
+
if (!sarifContent && !sarifPath) {
|
|
201580
|
+
return { content: [{ type: "text", text: "Either sarifContent or sarifPath is required." }] };
|
|
201581
|
+
}
|
|
201582
|
+
let content;
|
|
201583
|
+
if (sarifPath) {
|
|
201584
|
+
try {
|
|
201585
|
+
content = readFileSync13(sarifPath, "utf8");
|
|
201586
|
+
} catch {
|
|
201587
|
+
return { content: [{ type: "text", text: `Failed to read SARIF file: ${sarifPath}` }] };
|
|
201588
|
+
}
|
|
201589
|
+
} else {
|
|
201590
|
+
content = sarifContent;
|
|
201591
|
+
}
|
|
201592
|
+
const loaded = loadSarif({ inlineContent: content });
|
|
201593
|
+
if (loaded.error) {
|
|
201594
|
+
return { content: [{ type: "text", text: loaded.error }] };
|
|
201595
|
+
}
|
|
201596
|
+
const { createHash: createHash3 } = await import("crypto");
|
|
201597
|
+
const hash = createHash3("sha256").update(content).digest("hex").slice(0, 16);
|
|
201598
|
+
const cacheKey2 = `sarif-store-${hash}`;
|
|
201599
|
+
const sarif = loaded.sarif;
|
|
201600
|
+
const resultCount = sarif.runs[0]?.results?.length ?? 0;
|
|
201601
|
+
const ruleCount = sarif.runs[0]?.tool.driver.rules?.length ?? 0;
|
|
201602
|
+
const toolName = sarif.runs[0]?.tool.driver.name ?? "unknown";
|
|
201603
|
+
const store = sessionDataManager.getStore();
|
|
201604
|
+
store.putCacheEntry({
|
|
201605
|
+
cacheKey: cacheKey2,
|
|
201606
|
+
codeqlVersion: sarif.runs[0]?.tool.driver.version ?? "unknown",
|
|
201607
|
+
databasePath: sarifPath ?? "inline",
|
|
201608
|
+
language: "sarif",
|
|
201609
|
+
outputFormat: "sarif",
|
|
201610
|
+
queryName: "sarif_store",
|
|
201611
|
+
queryPath: sarifPath ?? "inline",
|
|
201612
|
+
resultContent: content,
|
|
201613
|
+
resultCount
|
|
201614
|
+
});
|
|
201615
|
+
return {
|
|
201616
|
+
content: [{
|
|
201617
|
+
type: "text",
|
|
201618
|
+
text: JSON.stringify({
|
|
201619
|
+
cacheKey: cacheKey2,
|
|
201620
|
+
label: label ?? null,
|
|
201621
|
+
resultCount,
|
|
201622
|
+
ruleCount,
|
|
201623
|
+
source: sarifPath ? "file" : "inline",
|
|
201624
|
+
toolName
|
|
201625
|
+
}, null, 2)
|
|
201626
|
+
}]
|
|
201627
|
+
};
|
|
201628
|
+
}
|
|
201629
|
+
);
|
|
201630
|
+
}
|
|
201631
|
+
function registerSarifDeduplicateRulesTool(server) {
|
|
201632
|
+
server.tool(
|
|
201633
|
+
"sarif_deduplicate_rules",
|
|
201634
|
+
"Identify duplicate alerts across two SARIF files by comparing rules pairwise. Uses fingerprint matching first, then full-path location overlap as fallback. Useful for cleanup after query changes or pack upgrades.",
|
|
201635
|
+
{
|
|
201636
|
+
cacheKeyA: external_exports.string().optional().describe("Cache key for the first SARIF."),
|
|
201637
|
+
cacheKeyB: external_exports.string().optional().describe("Cache key for the second SARIF."),
|
|
201638
|
+
overlapThreshold: external_exports.number().min(0).max(1).optional().default(0.8).describe("Minimum overlap score (0-1) to consider a rule pair as duplicates. Default: 0.8."),
|
|
201639
|
+
sarifPathA: external_exports.string().optional().describe("Path to the first SARIF file."),
|
|
201640
|
+
sarifPathB: external_exports.string().optional().describe("Path to the second SARIF file.")
|
|
201641
|
+
},
|
|
201642
|
+
async ({ sarifPathA, sarifPathB, cacheKeyA, cacheKeyB, overlapThreshold }) => {
|
|
201643
|
+
const loadedA = loadSarif({ sarifPath: sarifPathA, cacheKey: cacheKeyA });
|
|
201644
|
+
if (loadedA.error) {
|
|
201645
|
+
return { content: [{ type: "text", text: `SARIF A: ${loadedA.error}` }] };
|
|
201646
|
+
}
|
|
201647
|
+
const loadedB = loadSarif({ sarifPath: sarifPathB, cacheKey: cacheKeyB });
|
|
201648
|
+
if (loadedB.error) {
|
|
201649
|
+
return { content: [{ type: "text", text: `SARIF B: ${loadedB.error}` }] };
|
|
201650
|
+
}
|
|
201651
|
+
const rulesA = listSarifRules(loadedA.sarif);
|
|
201652
|
+
const rulesB = listSarifRules(loadedB.sarif);
|
|
201653
|
+
const duplicateGroups = [];
|
|
201654
|
+
const ruleDataA = /* @__PURE__ */ new Map();
|
|
201655
|
+
for (const rA of rulesA) {
|
|
201656
|
+
if (rA.resultCount === 0) continue;
|
|
201657
|
+
const extracted = extractRuleFromSarif(loadedA.sarif, rA.ruleId);
|
|
201658
|
+
ruleDataA.set(rA.ruleId, {
|
|
201659
|
+
results: extracted.runs[0]?.results ?? [],
|
|
201660
|
+
ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rA.ruleId }
|
|
201661
|
+
});
|
|
201662
|
+
}
|
|
201663
|
+
const ruleDataB = /* @__PURE__ */ new Map();
|
|
201664
|
+
for (const rB of rulesB) {
|
|
201665
|
+
if (rB.resultCount === 0) continue;
|
|
201666
|
+
const extracted = extractRuleFromSarif(loadedB.sarif, rB.ruleId);
|
|
201667
|
+
ruleDataB.set(rB.ruleId, {
|
|
201668
|
+
results: extracted.runs[0]?.results ?? [],
|
|
201669
|
+
ruleObj: extracted.runs[0]?.tool.driver.rules?.[0] ?? { id: rB.ruleId }
|
|
201670
|
+
});
|
|
201671
|
+
}
|
|
201672
|
+
for (const rA of rulesA) {
|
|
201673
|
+
const dataA = ruleDataA.get(rA.ruleId);
|
|
201674
|
+
if (!dataA) continue;
|
|
201675
|
+
for (const rB of rulesB) {
|
|
201676
|
+
const dataB = ruleDataB.get(rB.ruleId);
|
|
201677
|
+
if (!dataB) continue;
|
|
201678
|
+
const { results: resultsA, ruleObj: ruleObjA } = dataA;
|
|
201679
|
+
const { results: resultsB, ruleObj: ruleObjB } = dataB;
|
|
201680
|
+
const overlaps = findOverlappingAlerts(resultsA, ruleObjA, resultsB, ruleObjB, "full-path");
|
|
201681
|
+
const matchedAIndices = /* @__PURE__ */ new Set();
|
|
201682
|
+
for (let ai = 0; ai < resultsA.length; ai++) {
|
|
201683
|
+
for (const rResultB of resultsB) {
|
|
201684
|
+
const fpResult = computeFingerprintOverlap(resultsA[ai], rResultB);
|
|
201685
|
+
if (fpResult.fingerprintMatch) {
|
|
201686
|
+
matchedAIndices.add(ai);
|
|
201687
|
+
break;
|
|
201688
|
+
}
|
|
201689
|
+
}
|
|
201690
|
+
}
|
|
201691
|
+
const matchedAlerts = Math.max(overlaps.length, matchedAIndices.size);
|
|
201692
|
+
const minResults = Math.min(resultsA.length, resultsB.length);
|
|
201693
|
+
const cappedMatched = Math.min(matchedAlerts, minResults);
|
|
201694
|
+
const totalUnique = resultsA.length + resultsB.length - cappedMatched;
|
|
201695
|
+
const overlapScore = totalUnique > 0 ? cappedMatched / totalUnique : 0;
|
|
201696
|
+
if (overlapScore >= (overlapThreshold ?? 0.8)) {
|
|
201697
|
+
duplicateGroups.push({
|
|
201698
|
+
matchedAlerts: cappedMatched,
|
|
201699
|
+
overlapScore: Math.round(overlapScore * 1e3) / 1e3,
|
|
201700
|
+
ruleIdA: rA.ruleId,
|
|
201701
|
+
ruleIdB: rB.ruleId,
|
|
201702
|
+
totalA: resultsA.length,
|
|
201703
|
+
totalB: resultsB.length,
|
|
201704
|
+
unmatchedA: Math.max(0, resultsA.length - cappedMatched),
|
|
201705
|
+
unmatchedB: Math.max(0, resultsB.length - cappedMatched)
|
|
201706
|
+
});
|
|
201707
|
+
}
|
|
201708
|
+
}
|
|
201709
|
+
}
|
|
201710
|
+
duplicateGroups.sort((a, b) => b.overlapScore - a.overlapScore);
|
|
201711
|
+
return {
|
|
201712
|
+
content: [{
|
|
201713
|
+
type: "text",
|
|
201714
|
+
text: JSON.stringify({
|
|
201715
|
+
duplicateGroups,
|
|
201716
|
+
summary: {
|
|
201717
|
+
duplicatePairsFound: duplicateGroups.length,
|
|
201718
|
+
overlapThreshold: overlapThreshold ?? 0.8,
|
|
201719
|
+
totalRulesA: rulesA.length,
|
|
201720
|
+
totalRulesB: rulesB.length
|
|
201721
|
+
}
|
|
201722
|
+
}, null, 2)
|
|
201723
|
+
}]
|
|
201724
|
+
};
|
|
201725
|
+
}
|
|
201726
|
+
);
|
|
201727
|
+
}
|
|
201014
201728
|
|
|
201015
201729
|
// src/lib/tool-validation.ts
|
|
201016
201730
|
function formatAllValidationErrors(error2) {
|
|
@@ -201079,7 +201793,7 @@ init_package_paths();
|
|
|
201079
201793
|
init_logger();
|
|
201080
201794
|
import_dotenv.default.config({ path: resolve14(packageRootDir, ".env"), quiet: true });
|
|
201081
201795
|
var PACKAGE_NAME = "codeql-development-mcp-server";
|
|
201082
|
-
var VERSION = "2.25.
|
|
201796
|
+
var VERSION = "2.25.4";
|
|
201083
201797
|
async function startServer(mode = "stdio") {
|
|
201084
201798
|
logger.info(`Starting CodeQL Development MCP McpServer v${VERSION} in ${mode} mode`);
|
|
201085
201799
|
const codeqlBinary = resolveCodeQLBinary();
|
|
@@ -201141,7 +201855,7 @@ async function startServer(mode = "stdio") {
|
|
|
201141
201855
|
return new Promise((resolve15, reject) => {
|
|
201142
201856
|
const httpServer = app.listen(port, host, () => {
|
|
201143
201857
|
logger.info(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
201144
|
-
resolve15();
|
|
201858
|
+
resolve15(server);
|
|
201145
201859
|
});
|
|
201146
201860
|
httpServer.on("error", (error2) => {
|
|
201147
201861
|
logger.error("HTTP server error:", error2);
|