Skip to content

Commit 826b8e6

Browse files
authored
Merge pull request github#14067 from RasmusWL/modern-dataflowquerytests
Python: Adopt tests to new `DataflowQueryTest`
2 parents e7dbe9f + 889cb7a commit 826b8e6

File tree

5 files changed

+107
-44
lines changed

5 files changed

+107
-44
lines changed
Lines changed: 103 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,117 @@
11
import python
22
import semmle.python.dataflow.new.DataFlow
3+
import semmle.python.dataflow.new.TaintTracking
34
import TestUtilities.InlineExpectationsTest
45
private import semmle.python.dataflow.new.internal.PrintNode
56

6-
module DataFlowQueryTest implements TestSig {
7-
string getARelevantTag() { result = "result" }
7+
signature module QueryTestSig {
8+
predicate isSink(DataFlow::Node sink);
89

9-
predicate hasActualResult(Location location, string element, string tag, string value) {
10-
exists(DataFlow::Configuration cfg, DataFlow::Node sink | cfg.hasFlowTo(sink) |
11-
location = sink.getLocation() and
12-
tag = "result" and
13-
value = "BAD" and
14-
element = sink.toString()
15-
)
10+
predicate flowTo(DataFlow::Node sink);
11+
}
12+
13+
module MakeQueryTest<QueryTestSig Impl> {
14+
module DataFlowQueryTest implements TestSig {
15+
string getARelevantTag() { result = "result" }
16+
17+
predicate hasActualResult(Location location, string element, string tag, string value) {
18+
exists(DataFlow::Node sink | Impl::flowTo(sink) |
19+
location = sink.getLocation() and
20+
tag = "result" and
21+
value = "BAD" and
22+
element = sink.toString()
23+
)
24+
}
25+
26+
// We allow annotating any sink with `result=OK` to signal
27+
// safe sinks.
28+
// Sometimes a line contains both an alert and a safe sink.
29+
// In this situation, the annotation form `OK(safe sink)`
30+
// can be useful.
31+
predicate hasOptionalResult(Location location, string element, string tag, string value) {
32+
exists(DataFlow::Node sink | Impl::isSink(sink) |
33+
location = sink.getLocation() and
34+
tag = "result" and
35+
value in ["OK", "OK(" + prettyNode(sink) + ")"] and
36+
element = sink.toString()
37+
)
38+
}
1639
}
1740

18-
// We allow annotating any sink with `result=OK` to signal
19-
// safe sinks.
20-
// Sometimes a line contains both an alert and a safe sink.
21-
// In this situation, the annotation form `OK(safe sink)`
22-
// can be useful.
23-
predicate hasOptionalResult(Location location, string element, string tag, string value) {
24-
exists(DataFlow::Configuration cfg, DataFlow::Node sink |
25-
cfg.isSink(sink) or cfg.isSink(sink, _)
26-
|
41+
import MakeTest<DataFlowQueryTest>
42+
43+
query predicate missingAnnotationOnSink(Location location, string error, string element) {
44+
error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
45+
exists(DataFlow::Node sink |
46+
exists(sink.getLocation().getFile().getRelativePath()) and
47+
Impl::isSink(sink) and
2748
location = sink.getLocation() and
28-
tag = "result" and
29-
value in ["OK", "OK(" + prettyNode(sink) + ")"] and
30-
element = sink.toString()
49+
element = prettyExpr(sink.asExpr()) and
50+
not Impl::flowTo(sink) and
51+
not exists(FalseNegativeTestExpectation missingResult |
52+
missingResult.getTag() = "result" and
53+
missingResult.getValue() = "BAD" and
54+
missingResult.getLocation().getFile() = location.getFile() and
55+
missingResult.getLocation().getStartLine() = location.getStartLine()
56+
) and
57+
not exists(GoodTestExpectation okResult |
58+
okResult.getTag() = "result" and
59+
okResult.getValue() in ["OK", "OK(" + prettyNode(sink) + ")"] and
60+
okResult.getLocation().getFile() = location.getFile() and
61+
okResult.getLocation().getStartLine() = location.getStartLine()
62+
)
3163
)
3264
}
3365
}
3466

35-
import MakeTest<DataFlowQueryTest>
36-
37-
query predicate missingAnnotationOnSink(Location location, string error, string element) {
38-
error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
39-
exists(DataFlow::Node sink |
40-
exists(sink.getLocation().getFile().getRelativePath()) and
41-
exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _)) and
42-
location = sink.getLocation() and
43-
element = prettyExpr(sink.asExpr()) and
44-
not exists(DataFlow::Configuration cfg | cfg.hasFlowTo(sink)) and
45-
not exists(FalseNegativeTestExpectation missingResult |
46-
missingResult.getTag() = "result" and
47-
missingResult.getValue() = "BAD" and
48-
missingResult.getLocation().getFile() = location.getFile() and
49-
missingResult.getLocation().getStartLine() = location.getStartLine()
50-
) and
51-
not exists(GoodTestExpectation okResult |
52-
okResult.getTag() = "result" and
53-
okResult.getValue() in ["OK", "OK(" + prettyNode(sink) + ")"] and
54-
okResult.getLocation().getFile() = location.getFile() and
55-
okResult.getLocation().getStartLine() = location.getStartLine()
56-
)
57-
)
67+
module FromDataFlowConfig<DataFlow::ConfigSig C> {
68+
module Impl implements QueryTestSig {
69+
predicate isSink(DataFlow::Node sink) { C::isSink(sink) }
70+
71+
predicate flowTo(DataFlow::Node sink) { DataFlow::Global<C>::flowTo(sink) }
72+
}
73+
74+
import MakeQueryTest<Impl>
75+
}
76+
77+
module FromDataFlowStateConfig<DataFlow::StateConfigSig C> {
78+
module Impl implements QueryTestSig {
79+
predicate isSink(DataFlow::Node sink) { C::isSink(sink) or C::isSink(sink, _) }
80+
81+
predicate flowTo(DataFlow::Node sink) { DataFlow::GlobalWithState<C>::flowTo(sink) }
82+
}
83+
84+
import MakeQueryTest<Impl>
85+
}
86+
87+
module FromTaintTrackingConfig<DataFlow::ConfigSig C> {
88+
module Impl implements QueryTestSig {
89+
predicate isSink(DataFlow::Node sink) { C::isSink(sink) }
90+
91+
predicate flowTo(DataFlow::Node sink) { TaintTracking::Global<C>::flowTo(sink) }
92+
}
93+
94+
import MakeQueryTest<Impl>
95+
}
96+
97+
module FromTaintTrackingStateConfig<DataFlow::StateConfigSig C> {
98+
module Impl implements QueryTestSig {
99+
predicate isSink(DataFlow::Node sink) { C::isSink(sink) or C::isSink(sink, _) }
100+
101+
predicate flowTo(DataFlow::Node sink) { TaintTracking::GlobalWithState<C>::flowTo(sink) }
102+
}
103+
104+
import MakeQueryTest<Impl>
105+
}
106+
107+
signature class LegacyConfiguration extends DataFlow::Configuration;
108+
109+
module FromLegacyConfiguration<LegacyConfiguration C> {
110+
module Impl implements QueryTestSig {
111+
predicate isSink(DataFlow::Node sink) { any(C c).isSink(sink) or any(C c).isSink(sink, _) }
112+
113+
predicate flowTo(DataFlow::Node sink) { any(C c).hasFlowTo(sink) }
114+
}
115+
116+
import MakeQueryTest<Impl>
58117
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import python
22
import experimental.dataflow.TestUtil.DataflowQueryTest
33
import experimental.Security.UnsafeUnpackQuery
4+
import FromLegacyConfiguration<UnsafeUnpackingConfig>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import python
22
import experimental.dataflow.TestUtil.DataflowQueryTest
33
import semmle.python.security.dataflow.PathInjectionQuery
4+
import FromLegacyConfiguration<Configuration>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import python
22
import experimental.dataflow.TestUtil.DataflowQueryTest
33
import semmle.python.security.dataflow.CommandInjectionQuery
4+
import FromLegacyConfiguration<Configuration>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
import python
22
import experimental.dataflow.TestUtil.DataflowQueryTest
33
import semmle.python.security.dataflow.UnsafeShellCommandConstructionQuery
4+
import FromLegacyConfiguration<Configuration>

0 commit comments

Comments
 (0)