codeql-development-mcp-server 2.24.3 → 2.25.0
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/dist/codeql-development-mcp-server.js +48111 -49526
- package/dist/codeql-development-mcp-server.js.map +4 -4
- package/package.json +9 -9
- package/ql/actions/tools/src/PrintCFG/PrintCFG.ql +1 -3
- 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/CallGraphFrom/CallGraphFrom.ql +6 -20
- package/ql/cpp/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/cpp/tools/src/CallGraphFromTo/CallGraphFromTo.ql +77 -0
- package/ql/cpp/tools/src/CallGraphTo/CallGraphTo.ql +6 -20
- package/ql/cpp/tools/src/ExternalPredicates.qll +14 -0
- package/ql/cpp/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/cpp/tools/src/PrintCFG/PrintCFG.ql +1 -3
- 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/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/csharp/tools/src/CallGraphFromTo/CallGraphFromTo.md +49 -0
- package/ql/csharp/tools/src/CallGraphFromTo/CallGraphFromTo.ql +64 -0
- package/ql/csharp/tools/src/CallGraphTo/CallGraphTo.ql +4 -19
- package/ql/csharp/tools/src/ExternalPredicates.qll +14 -0
- package/ql/csharp/tools/src/PrintAST/PrintAST.ql +9 -17
- 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/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/go/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/go/tools/src/CallGraphFromTo/CallGraphFromTo.ql +53 -0
- package/ql/go/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/go/tools/src/ExternalPredicates.qll +14 -0
- package/ql/go/tools/src/PrintAST/PrintAST.ql +132 -22
- 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/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/java/tools/src/CallGraphFromTo/CallGraphFromTo.md +49 -0
- package/ql/java/tools/src/CallGraphFromTo/CallGraphFromTo.ql +64 -0
- package/ql/java/tools/src/CallGraphTo/CallGraphTo.ql +4 -19
- package/ql/java/tools/src/ExternalPredicates.qll +14 -0
- package/ql/java/tools/src/PrintAST/PrintAST.ql +9 -17
- package/ql/java/tools/src/PrintCFG/PrintCFG.ql +11 -10
- 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/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/javascript/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/javascript/tools/src/CallGraphFromTo/CallGraphFromTo.ql +69 -0
- package/ql/javascript/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/javascript/tools/src/ExternalPredicates.qll +14 -0
- package/ql/javascript/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/javascript/tools/src/PrintCFG/PrintCFG.ql +1 -3
- 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/CallGraphFrom/CallGraphFrom.ql +3 -17
- package/ql/python/tools/src/CallGraphFromTo/CallGraphFromTo.md +46 -0
- package/ql/python/tools/src/CallGraphFromTo/CallGraphFromTo.ql +71 -0
- package/ql/python/tools/src/CallGraphTo/CallGraphTo.ql +6 -22
- package/ql/python/tools/src/ExternalPredicates.qll +14 -0
- package/ql/python/tools/src/PrintAST/PrintAST.ql +9 -20
- package/ql/python/tools/src/PrintCFG/PrintCFG.ql +1 -3
- 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/CallGraphFrom/CallGraphFrom.ql +4 -19
- package/ql/ruby/tools/src/CallGraphFromTo/CallGraphFromTo.md +48 -0
- package/ql/ruby/tools/src/CallGraphFromTo/CallGraphFromTo.ql +50 -0
- package/ql/ruby/tools/src/CallGraphTo/CallGraphTo.ql +4 -20
- package/ql/ruby/tools/src/ExternalPredicates.qll +14 -0
- package/ql/ruby/tools/src/PrintAST/PrintAST.ql +9 -17
- package/ql/ruby/tools/src/PrintCFG/PrintCFG.ql +1 -3
- package/ql/ruby/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/ruby/tools/src/codeql-pack.yml +2 -2
- package/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.ql +7 -16
- package/ql/swift/tools/src/CallGraphFromTo/CallGraphFromTo.md +47 -0
- package/ql/swift/tools/src/CallGraphFromTo/CallGraphFromTo.ql +80 -0
- package/ql/swift/tools/src/CallGraphTo/CallGraphTo.ql +8 -14
- package/ql/swift/tools/src/ExternalPredicates.qll +14 -0
- package/ql/swift/tools/src/PrintAST/PrintAST.ql +5 -15
- package/ql/swift/tools/src/PrintCFG/PrintCFG.ql +5 -15
- package/ql/swift/tools/src/codeql-pack.lock.yml +10 -10
- package/ql/swift/tools/src/codeql-pack.yml +2 -2
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From To for python
|
|
3
|
+
* @description Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
* @id python/tools/call-graph-from-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import python
|
|
11
|
+
import ExternalPredicates
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Gets a single source function name from the comma-separated list.
|
|
15
|
+
*/
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets a single target function name from the comma-separated list.
|
|
22
|
+
*/
|
|
23
|
+
string getTargetFunctionName() {
|
|
24
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Gets a function by matching against the selected source function names.
|
|
29
|
+
*/
|
|
30
|
+
Function getSourceFunction() {
|
|
31
|
+
exists(string selectedFunc |
|
|
32
|
+
selectedFunc = getSourceFunctionName() and
|
|
33
|
+
result.getName() = selectedFunc
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Gets a function by matching against the selected target function names.
|
|
39
|
+
*/
|
|
40
|
+
Function getTargetFunction() {
|
|
41
|
+
exists(string selectedFunc |
|
|
42
|
+
selectedFunc = getTargetFunctionName() and
|
|
43
|
+
result.getName() = selectedFunc
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Holds if function `caller` directly calls function `callee` by name.
|
|
49
|
+
*/
|
|
50
|
+
predicate calls(Function caller_, Function callee_) {
|
|
51
|
+
exists(CallNode c |
|
|
52
|
+
c.getScope() = caller_ and
|
|
53
|
+
c.getNode().(Call).getFunc().(Name).getId() = callee_.getName()
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
from CallNode call, Function caller
|
|
58
|
+
where
|
|
59
|
+
call.getScope() = caller and
|
|
60
|
+
exists(Function source, Function target |
|
|
61
|
+
source = getSourceFunction() and
|
|
62
|
+
target = getTargetFunction() and
|
|
63
|
+
calls*(source, caller) and
|
|
64
|
+
exists(Function callee |
|
|
65
|
+
call.getNode().(Call).getFunc().(Name).getId() = callee.getName() and
|
|
66
|
+
calls*(callee, target)
|
|
67
|
+
)
|
|
68
|
+
)
|
|
69
|
+
select call.getNode(),
|
|
70
|
+
"Reachable call from `" + caller.getName() + "` to `" +
|
|
71
|
+
call.getNode().(Call).getFunc().(Name).getId() + "`"
|
|
@@ -8,40 +8,24 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import python
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the target function name for which to generate the call graph.
|
|
14
|
-
* Can be a single function name or comma-separated list of function names.
|
|
15
|
-
*/
|
|
16
|
-
external string targetFunction();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single target function name from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getTargetFunctionName() {
|
|
22
|
-
|
|
17
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
26
21
|
* Gets the caller name for a call expression.
|
|
27
22
|
*/
|
|
28
23
|
string getCallerName(CallNode call) {
|
|
29
|
-
if exists(call.getScope())
|
|
30
|
-
then result = call.getScope().getName()
|
|
31
|
-
else result = "Module"
|
|
24
|
+
if exists(call.getScope()) then result = call.getScope().getName() else result = "Module"
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
from CallNode call
|
|
35
|
-
where
|
|
36
|
-
(
|
|
37
|
-
// Use external predicate if available
|
|
38
|
-
call.getNode().(Call).getFunc().(Name).getId() = getTargetFunctionName()
|
|
39
|
-
or
|
|
40
|
-
// Fallback for unit tests: include test files
|
|
41
|
-
(
|
|
42
|
-
not exists(getTargetFunctionName()) and
|
|
43
|
-
call.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
44
|
-
)
|
|
45
|
-
)
|
|
28
|
+
where call.getNode().(Call).getFunc().(Name).getId() = getTargetFunctionName()
|
|
46
29
|
select call.getNode(),
|
|
47
|
-
"Call to `" + call.getNode().(Call).getFunc().(Name).getId() + "` from `" + getCallerName(call) +
|
|
30
|
+
"Call to `" + call.getNode().(Call).getFunc().(Name).getId() + "` from `" + getCallerName(call) +
|
|
31
|
+
"`"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared extensible predicate declarations for MCP server tools queries.
|
|
3
|
+
* Values are provided via dataExtensions YAML files during testing,
|
|
4
|
+
* or via a temporary data extension pack at runtime from the MCP server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Holds for each source function name for call graph analysis. */
|
|
8
|
+
extensible predicate sourceFunction(string name);
|
|
9
|
+
|
|
10
|
+
/** Holds for each target function name for call graph analysis. */
|
|
11
|
+
extensible predicate targetFunction(string name);
|
|
12
|
+
|
|
13
|
+
/** Holds for each selected source file path for AST/CFG printing. */
|
|
14
|
+
extensible predicate selectedSourceFiles(string path);
|
|
@@ -7,18 +7,13 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import semmle.python.PrintAst
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Gets the source files to generate AST from.
|
|
13
|
-
* Can be a single file path or comma-separated list of file paths.
|
|
14
|
-
*/
|
|
15
|
-
external string selectedSourceFiles();
|
|
10
|
+
import ExternalPredicates
|
|
16
11
|
|
|
17
12
|
/**
|
|
18
13
|
* Gets a single source file from the comma-separated list.
|
|
19
14
|
*/
|
|
20
15
|
string getSelectedSourceFile() {
|
|
21
|
-
|
|
16
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
22
17
|
}
|
|
23
18
|
|
|
24
19
|
/**
|
|
@@ -29,11 +24,14 @@ File getSelectedFile() {
|
|
|
29
24
|
selectedFile = getSelectedSourceFile() and
|
|
30
25
|
(
|
|
31
26
|
// Match by exact relative path from source root
|
|
32
|
-
result.getRelativePath() = selectedFile
|
|
27
|
+
result.getRelativePath() = selectedFile
|
|
28
|
+
or
|
|
33
29
|
// Match by file name if no path separators
|
|
34
|
-
|
|
30
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
31
|
+
or
|
|
35
32
|
// Match by ending path component
|
|
36
|
-
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
33
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
34
|
+
selectedFile
|
|
37
35
|
)
|
|
38
36
|
)
|
|
39
37
|
}
|
|
@@ -45,16 +43,7 @@ File getSelectedFile() {
|
|
|
45
43
|
class Cfg extends PrintAstConfiguration {
|
|
46
44
|
override predicate shouldPrint(AstNode e, Location l) {
|
|
47
45
|
super.shouldPrint(e, l) and
|
|
48
|
-
(
|
|
49
|
-
// Use external predicate if available
|
|
50
|
-
l.getFile() = getSelectedFile()
|
|
51
|
-
or
|
|
52
|
-
// Fallback for unit tests: include test files
|
|
53
|
-
(
|
|
54
|
-
not exists(getSelectedFile()) and
|
|
55
|
-
l.getFile().getParent().getParent().getBaseName() = "test"
|
|
56
|
-
)
|
|
57
|
-
) and
|
|
46
|
+
l.getFile() = getSelectedFile() and
|
|
58
47
|
// Exclude the "Name" class so that results are deterministic
|
|
59
48
|
// for a given source file, which is required for reproducible results
|
|
60
49
|
not e.getAQlClass() = "Name"
|
|
@@ -16,6 +16,4 @@ query predicate nodes(ControlFlowNode node, string property, string value) {
|
|
|
16
16
|
value = node.toString()
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
query predicate edges(ControlFlowNode pred, ControlFlowNode succ) {
|
|
20
|
-
pred.getASuccessor() = succ
|
|
21
|
-
}
|
|
19
|
+
query predicate edges(ControlFlowNode pred, ControlFlowNode succ) { pred.getASuccessor() = succ }
|
|
@@ -2,29 +2,29 @@
|
|
|
2
2
|
lockVersion: 1.0.0
|
|
3
3
|
dependencies:
|
|
4
4
|
codeql/concepts:
|
|
5
|
-
version: 0.0.
|
|
5
|
+
version: 0.0.18
|
|
6
6
|
codeql/controlflow:
|
|
7
|
-
version: 2.0.
|
|
7
|
+
version: 2.0.28
|
|
8
8
|
codeql/dataflow:
|
|
9
|
-
version: 2.0
|
|
9
|
+
version: 2.1.0
|
|
10
10
|
codeql/mad:
|
|
11
|
-
version: 1.0.
|
|
11
|
+
version: 1.0.44
|
|
12
12
|
codeql/python-all:
|
|
13
|
-
version:
|
|
13
|
+
version: 7.0.1
|
|
14
14
|
codeql/regex:
|
|
15
|
-
version: 1.0.
|
|
15
|
+
version: 1.0.44
|
|
16
16
|
codeql/ssa:
|
|
17
|
-
version: 2.0.
|
|
17
|
+
version: 2.0.20
|
|
18
18
|
codeql/threat-models:
|
|
19
|
-
version: 1.0.
|
|
19
|
+
version: 1.0.44
|
|
20
20
|
codeql/tutorial:
|
|
21
|
-
version: 1.0.
|
|
21
|
+
version: 1.0.44
|
|
22
22
|
codeql/typetracking:
|
|
23
|
-
version: 2.0.25
|
|
24
|
-
codeql/util:
|
|
25
23
|
version: 2.0.28
|
|
24
|
+
codeql/util:
|
|
25
|
+
version: 2.0.31
|
|
26
26
|
codeql/xml:
|
|
27
|
-
version: 1.0.
|
|
27
|
+
version: 1.0.44
|
|
28
28
|
codeql/yaml:
|
|
29
|
-
version: 1.0.
|
|
29
|
+
version: 1.0.44
|
|
30
30
|
compiled: false
|
|
@@ -9,32 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
private import codeql.ruby.AST
|
|
11
11
|
private import codeql.ruby.DataFlow
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Gets the source method name for which to generate the call graph.
|
|
15
|
-
* Can be a single method name or comma-separated list of method names.
|
|
16
|
-
*/
|
|
17
|
-
external string sourceFunction();
|
|
12
|
+
import ExternalPredicates
|
|
18
13
|
|
|
19
14
|
/**
|
|
20
15
|
* Gets a single source method name from the comma-separated list.
|
|
21
16
|
*/
|
|
22
17
|
string getSourceFunctionName() {
|
|
23
|
-
|
|
18
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
24
19
|
}
|
|
25
20
|
|
|
26
21
|
from MethodCall call, MethodBase source
|
|
27
22
|
where
|
|
28
23
|
call.getEnclosingMethod() = source and
|
|
29
|
-
(
|
|
30
|
-
|
|
31
|
-
source.getName() = getSourceFunctionName()
|
|
32
|
-
or
|
|
33
|
-
// Fallback for unit tests: include test files
|
|
34
|
-
(
|
|
35
|
-
not exists(getSourceFunctionName()) and
|
|
36
|
-
source.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
37
|
-
)
|
|
38
|
-
)
|
|
39
|
-
select call,
|
|
40
|
-
"Call from `" + source.getName() + "` to `" + call.getMethodName() + "`"
|
|
24
|
+
source.getName() = getSourceFunctionName()
|
|
25
|
+
select call, "Call from `" + source.getName() + "` to `" + call.getMethodName() + "`"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# CallGraphFromTo for Ruby
|
|
2
|
+
|
|
3
|
+
Displays calls on reachable paths from a source method to a target method, showing transitive call graph connectivity.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all method calls that lie on any transitive call path from a specified source method to a specified target method. Given both a source and target method name, it reports each call site along the connecting paths, which is useful for understanding indirect call chains, security-relevant data flow paths, and method reachability.
|
|
8
|
+
|
|
9
|
+
The query uses transitive closure (`calls*`) to determine reachability, then reports only the direct call sites that contribute to paths between the source and target. It accepts method names via extensible predicates (`sourceFunction` and `targetFunction`) populated via CodeQL data extensions / model packs (see `ExternalPredicates.qll`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Determining if a call path exists between two methods
|
|
16
|
+
- Mapping indirect call chains from a source to a target method
|
|
17
|
+
- Analyzing security-relevant paths (e.g., from user input handlers to sensitive operations)
|
|
18
|
+
- Understanding transitive dependencies between methods
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
The following Ruby code demonstrates a transitive call chain from `source` through `intermediate` to `target`:
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
def target
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def intermediate
|
|
29
|
+
target
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def source
|
|
33
|
+
intermediate
|
|
34
|
+
end
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Running with `sourceFunction = "source"` and `targetFunction = "target"` produces results showing each call site on the path with a message like: "Reachable call from `source` to `intermediate`".
|
|
38
|
+
|
|
39
|
+
## Output Format
|
|
40
|
+
|
|
41
|
+
The query is a `@kind problem` query producing rows of:
|
|
42
|
+
|
|
43
|
+
- ``select call, "Reachable call from `caller` to `callee`"``
|
|
44
|
+
|
|
45
|
+
## References
|
|
46
|
+
|
|
47
|
+
- [Ruby Methods](https://ruby-doc.org/3.2.0/syntax/methods_rdoc.html)
|
|
48
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name Call Graph From To for ruby
|
|
3
|
+
* @description Displays calls on reachable paths from a source method to a target method, showing transitive call graph connectivity.
|
|
4
|
+
* @id ruby/tools/call-graph-from-to
|
|
5
|
+
* @kind problem
|
|
6
|
+
* @problem.severity recommendation
|
|
7
|
+
* @tags call-graph
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
private import codeql.ruby.AST
|
|
11
|
+
private import codeql.ruby.DataFlow
|
|
12
|
+
import ExternalPredicates
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Gets a single source method name from the comma-separated list.
|
|
16
|
+
*/
|
|
17
|
+
string getSourceFunctionName() {
|
|
18
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Gets a single target method name from the comma-separated list.
|
|
23
|
+
*/
|
|
24
|
+
string getTargetFunctionName() {
|
|
25
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Holds if method `caller` directly calls method `callee` by name.
|
|
30
|
+
*/
|
|
31
|
+
predicate calls(MethodBase caller_, MethodBase callee_) {
|
|
32
|
+
exists(MethodCall c |
|
|
33
|
+
c.getEnclosingMethod() = caller_ and
|
|
34
|
+
c.getMethodName() = callee_.getName()
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
from MethodCall call, MethodBase caller
|
|
39
|
+
where
|
|
40
|
+
call.getEnclosingMethod() = caller and
|
|
41
|
+
exists(MethodBase source, MethodBase target |
|
|
42
|
+
source.getName() = getSourceFunctionName() and
|
|
43
|
+
target.getName() = getTargetFunctionName() and
|
|
44
|
+
calls*(source, caller) and
|
|
45
|
+
exists(MethodBase callee |
|
|
46
|
+
call.getMethodName() = callee.getName() and
|
|
47
|
+
calls*(callee, target)
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
select call, "Reachable call from `" + caller.getName() + "` to `" + call.getMethodName() + "`"
|
|
@@ -9,18 +9,13 @@
|
|
|
9
9
|
|
|
10
10
|
private import codeql.ruby.AST
|
|
11
11
|
private import codeql.ruby.DataFlow
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Gets the target method name for which to generate the call graph.
|
|
15
|
-
* Can be a single method name or comma-separated list of method names.
|
|
16
|
-
*/
|
|
17
|
-
external string targetFunction();
|
|
12
|
+
import ExternalPredicates
|
|
18
13
|
|
|
19
14
|
/**
|
|
20
15
|
* Gets a single target method name from the comma-separated list.
|
|
21
16
|
*/
|
|
22
17
|
string getTargetFunctionName() {
|
|
23
|
-
|
|
18
|
+
exists(string s | targetFunction(s) | result = s.splitAt(",").trim())
|
|
24
19
|
}
|
|
25
20
|
|
|
26
21
|
/**
|
|
@@ -33,16 +28,5 @@ string getCallerName(MethodCall call) {
|
|
|
33
28
|
}
|
|
34
29
|
|
|
35
30
|
from MethodCall call
|
|
36
|
-
where
|
|
37
|
-
|
|
38
|
-
// Use external predicate if available
|
|
39
|
-
call.getMethodName() = getTargetFunctionName()
|
|
40
|
-
or
|
|
41
|
-
// Fallback for unit tests: include test files
|
|
42
|
-
(
|
|
43
|
-
not exists(getTargetFunctionName()) and
|
|
44
|
-
call.getLocation().getFile().getParentContainer().getParentContainer().getBaseName() = "test"
|
|
45
|
-
)
|
|
46
|
-
)
|
|
47
|
-
select call,
|
|
48
|
-
"Call to `" + call.getMethodName() + "` from `" + getCallerName(call) + "`"
|
|
31
|
+
where call.getMethodName() = getTargetFunctionName()
|
|
32
|
+
select call, "Call to `" + call.getMethodName() + "` from `" + getCallerName(call) + "`"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared extensible predicate declarations for MCP server tools queries.
|
|
3
|
+
* Values are provided via dataExtensions YAML files during testing,
|
|
4
|
+
* or via a temporary data extension pack at runtime from the MCP server.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Holds for each source function name for call graph analysis. */
|
|
8
|
+
extensible predicate sourceFunction(string name);
|
|
9
|
+
|
|
10
|
+
/** Holds for each target function name for call graph analysis. */
|
|
11
|
+
extensible predicate targetFunction(string name);
|
|
12
|
+
|
|
13
|
+
/** Holds for each selected source file path for AST/CFG printing. */
|
|
14
|
+
extensible predicate selectedSourceFiles(string path);
|
|
@@ -8,18 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
private import codeql.ruby.AST
|
|
10
10
|
private import codeql.ruby.printAst
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source files to generate AST from.
|
|
14
|
-
* Can be a single file path or comma-separated list of file paths.
|
|
15
|
-
*/
|
|
16
|
-
external string selectedSourceFiles();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single source file from the comma-separated list.
|
|
20
15
|
*/
|
|
21
16
|
string getSelectedSourceFile() {
|
|
22
|
-
|
|
17
|
+
exists(string s | selectedSourceFiles(s) | result = s.splitAt(",").trim())
|
|
23
18
|
}
|
|
24
19
|
|
|
25
20
|
/**
|
|
@@ -30,11 +25,14 @@ File getSelectedFile() {
|
|
|
30
25
|
selectedFile = getSelectedSourceFile() and
|
|
31
26
|
(
|
|
32
27
|
// Match by exact relative path from source root
|
|
33
|
-
result.getRelativePath() = selectedFile
|
|
28
|
+
result.getRelativePath() = selectedFile
|
|
29
|
+
or
|
|
34
30
|
// Match by file name if no path separators
|
|
35
|
-
|
|
31
|
+
not selectedFile.matches("%/%") and result.getBaseName() = selectedFile
|
|
32
|
+
or
|
|
36
33
|
// Match by ending path component
|
|
37
|
-
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
34
|
+
result.getAbsolutePath().suffix(result.getAbsolutePath().length() - selectedFile.length()) =
|
|
35
|
+
selectedFile
|
|
38
36
|
)
|
|
39
37
|
)
|
|
40
38
|
}
|
|
@@ -46,12 +44,6 @@ File getSelectedFile() {
|
|
|
46
44
|
class Cfg extends PrintAstConfiguration {
|
|
47
45
|
override predicate shouldPrintNode(AstNode n) {
|
|
48
46
|
super.shouldPrintNode(n) and
|
|
49
|
-
(
|
|
50
|
-
// Use external predicate if available
|
|
51
|
-
n.getLocation().getFile() = getSelectedFile()
|
|
52
|
-
or
|
|
53
|
-
// Fallback for unit tests: include all files
|
|
54
|
-
not exists(getSelectedFile())
|
|
55
|
-
)
|
|
47
|
+
n.getLocation().getFile() = getSelectedFile()
|
|
56
48
|
}
|
|
57
49
|
}
|
|
@@ -17,6 +17,4 @@ query predicate nodes(CfgNode node, string property, string value) {
|
|
|
17
17
|
value = node.toString()
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
query predicate edges(CfgNode pred, CfgNode succ) {
|
|
21
|
-
pred.getASuccessor() = succ
|
|
22
|
-
}
|
|
20
|
+
query predicate edges(CfgNode pred, CfgNode succ) { pred.getASuccessor() = succ }
|
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
lockVersion: 1.0.0
|
|
3
3
|
dependencies:
|
|
4
4
|
codeql/concepts:
|
|
5
|
-
version: 0.0.
|
|
5
|
+
version: 0.0.18
|
|
6
6
|
codeql/controlflow:
|
|
7
|
-
version: 2.0.
|
|
7
|
+
version: 2.0.28
|
|
8
8
|
codeql/dataflow:
|
|
9
|
-
version: 2.0
|
|
9
|
+
version: 2.1.0
|
|
10
10
|
codeql/mad:
|
|
11
|
-
version: 1.0.
|
|
11
|
+
version: 1.0.44
|
|
12
12
|
codeql/regex:
|
|
13
|
-
version: 1.0.
|
|
13
|
+
version: 1.0.44
|
|
14
14
|
codeql/ruby-all:
|
|
15
|
-
version: 5.1.
|
|
15
|
+
version: 5.1.12
|
|
16
16
|
codeql/ssa:
|
|
17
|
-
version: 2.0.
|
|
17
|
+
version: 2.0.20
|
|
18
18
|
codeql/tutorial:
|
|
19
|
-
version: 1.0.
|
|
19
|
+
version: 1.0.44
|
|
20
20
|
codeql/typetracking:
|
|
21
|
-
version: 2.0.25
|
|
22
|
-
codeql/util:
|
|
23
21
|
version: 2.0.28
|
|
22
|
+
codeql/util:
|
|
23
|
+
version: 2.0.31
|
|
24
24
|
compiled: false
|
|
@@ -8,25 +8,23 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import swift
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Gets the source function name for which to generate the call graph.
|
|
14
|
-
* Can be a single function name or comma-separated list of function names.
|
|
15
|
-
*/
|
|
16
|
-
external string sourceFunction();
|
|
11
|
+
import ExternalPredicates
|
|
17
12
|
|
|
18
13
|
/**
|
|
19
14
|
* Gets a single source function name from the comma-separated list.
|
|
20
15
|
*/
|
|
21
|
-
string getSourceFunctionName() {
|
|
16
|
+
string getSourceFunctionName() {
|
|
17
|
+
exists(string s | sourceFunction(s) | result = s.splitAt(",").trim())
|
|
18
|
+
}
|
|
22
19
|
|
|
23
20
|
/**
|
|
24
21
|
* Gets a function by matching against the selected source function names.
|
|
22
|
+
* Supports both base names (e.g. "sourceFunc") and full Swift signatures (e.g. "sourceFunc()").
|
|
25
23
|
*/
|
|
26
24
|
Function getSourceFunction() {
|
|
27
25
|
exists(string selectedFunc |
|
|
28
26
|
selectedFunc = getSourceFunctionName() and
|
|
29
|
-
result.getName() = selectedFunc
|
|
27
|
+
(result.getName() = selectedFunc or result.getName().matches(selectedFunc + "(%"))
|
|
30
28
|
)
|
|
31
29
|
}
|
|
32
30
|
|
|
@@ -42,12 +40,5 @@ string getCalleeName(CallExpr call) {
|
|
|
42
40
|
from CallExpr call, Function source
|
|
43
41
|
where
|
|
44
42
|
call.getEnclosingFunction() = source and
|
|
45
|
-
(
|
|
46
|
-
// Use external predicate if available
|
|
47
|
-
source = getSourceFunction()
|
|
48
|
-
or
|
|
49
|
-
// Fallback for unit tests: include specific test files
|
|
50
|
-
not exists(getSourceFunction()) and
|
|
51
|
-
source.getFile().getBaseName() = "Example1.swift"
|
|
52
|
-
)
|
|
43
|
+
source = getSourceFunction()
|
|
53
44
|
select call, "Call from `" + source.getName() + "` to `" + getCalleeName(call) + "`"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# CallGraphFromTo for Swift
|
|
2
|
+
|
|
3
|
+
Displays calls on reachable paths from a source function to a target function, showing transitive call graph connectivity.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This query identifies all function calls that lie on any transitive call path from a specified source function to a specified target function. Given both a source and target function name, it reports each call site along the connecting paths, which is useful for understanding indirect call chains, security-relevant data flow paths, and function reachability.
|
|
8
|
+
|
|
9
|
+
The query uses transitive closure (`calls*`) to determine reachability, then reports only the direct call sites that contribute to paths between the source and target. It accepts function names via extensible predicates (`sourceFunction` and `targetFunction`) populated via CodeQL data extensions / model packs (see `ExternalPredicates.qll`).
|
|
10
|
+
|
|
11
|
+
## Use Cases
|
|
12
|
+
|
|
13
|
+
This query is primarily used for:
|
|
14
|
+
|
|
15
|
+
- Determining if a call path exists between two functions
|
|
16
|
+
- Mapping indirect call chains from a source to a target function
|
|
17
|
+
- Analyzing security-relevant paths (e.g., from user input handlers to sensitive operations)
|
|
18
|
+
- Understanding transitive dependencies between functions
|
|
19
|
+
|
|
20
|
+
## Example
|
|
21
|
+
|
|
22
|
+
The following Swift code demonstrates a transitive call chain from `source` through `intermediate` to `target`:
|
|
23
|
+
|
|
24
|
+
```swift
|
|
25
|
+
func target() {}
|
|
26
|
+
|
|
27
|
+
func intermediate() {
|
|
28
|
+
target()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func source() {
|
|
32
|
+
intermediate()
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Running with `sourceFunction = "source"` and `targetFunction = "target"` produces results showing each call site on the path with a message like: "Reachable call from `source` to `intermediate`".
|
|
37
|
+
|
|
38
|
+
## Output Format
|
|
39
|
+
|
|
40
|
+
The query is a `@kind problem` query producing rows of:
|
|
41
|
+
|
|
42
|
+
- ``select call, "Reachable call from `caller` to `callee`"``
|
|
43
|
+
|
|
44
|
+
## References
|
|
45
|
+
|
|
46
|
+
- [Swift Functions](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions)
|
|
47
|
+
- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/)
|