-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathYaml.qll
More file actions
159 lines (130 loc) · 4.68 KB
/
Yaml.qll
File metadata and controls
159 lines (130 loc) · 4.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/**
* Provides classes for working with YAML data.
*
* YAML documents are represented as abstract syntax trees whose nodes
* are either YAML values or alias nodes referring to another YAML value.
*/
private import codeql.yaml.Yaml as LibYaml
private import codeql.files.FileSystem
private module YamlSig implements LibYaml::InputSig {
import codeql.Locations
class LocatableBase extends @yaml_locatable {
Location getLocation() { yaml_locations(this, result) }
string toString() { none() }
}
class NodeBase extends LocatableBase, @yaml_node {
NodeBase getChildNode(int i) { yaml(result, _, this, i, _, _) }
string getTag() { yaml(this, _, _, _, result, _) }
string getAnchor() { yaml_anchors(this, result) }
override string toString() { yaml(this, _, _, _, _, result) }
}
class ScalarNodeBase extends NodeBase, @yaml_scalar_node {
int getStyle() { yaml_scalars(this, result, _) }
string getValue() { yaml_scalars(this, _, result) }
}
class CollectionNodeBase extends NodeBase, @yaml_collection_node { }
class MappingNodeBase extends CollectionNodeBase, @yaml_mapping_node { }
class SequenceNodeBase extends CollectionNodeBase, @yaml_sequence_node { }
class AliasNodeBase extends NodeBase, @yaml_alias_node {
string getTarget() { yaml_aliases(this, result) }
}
class ParseErrorBase extends LocatableBase, @yaml_error {
string getMessage() { yaml_errors(this, result) }
}
}
import LibYaml::Make<YamlSig>
/** A `qlpack.yml` document. */
class QlPackDocument extends YamlDocument {
QlPackDocument() { this.getFile().getBaseName() = ["qlpack.yml", "qlpack.test.yml"] }
/** Gets the name of this QL pack. */
string getPackName() {
exists(YamlMapping n |
n.getDocument() = this and
result = n.lookup("name").(YamlScalar).getValue()
)
}
private string getADependencyName() {
exists(YamlMapping n, YamlScalar key |
n.getDocument() = this and
n.lookup("dependencies").(YamlMapping).maps(key, _) and
result = key.getValue()
)
}
/** Gets a dependency of this QL pack. */
QlPackDocument getADependency() { result.getPackName() = this.getADependencyName() }
private Folder getRootFolder() { result = this.getFile().getParentContainer() }
/** Gets a folder inside this QL pack. */
pragma[nomagic]
Folder getAFolder() {
result = this.getRootFolder()
or
exists(Folder mid |
mid = this.getAFolder() and
result.getParentContainer() = mid and
not result = any(QlPackDocument other).getRootFolder()
)
}
}
/**
* Holds if `qlref` is a `.qlref` YAML document referencing a query
* at relative path `relativePath`, and `f` is a candidate folder
* in which to lookup the referenced query.
*
* `f` is either:
* - the root of the QL pack containing `qlref`,
* - the root of a QL pack that is a dependency of the QL pack containing `qlref`, or
* - the folder containing `qlref`.
*/
private predicate shouldAppend(QlRefDocument qlref, Folder f, string relativePath) {
relativePath = qlref.getRelativeQueryPath() and
(
exists(QlPackDocument pack |
pack.getAFolder() = qlref.getFile().getParentContainer() and
f = [pack, pack.getADependency()].getFile().getParentContainer()
)
or
f = qlref.getFile().getParentContainer()
)
}
private predicate shouldAppend(Folder f, string relativePath) { shouldAppend(_, f, relativePath) }
/** A `.qlref` YAML document. */
class QlRefDocument extends YamlDocument {
QlRefDocument() { this.getFile().getExtension() = "qlref" }
/** Holds if this `.qlref` file uses inline test expectations. */
predicate usesInlineExpectations() {
exists(YamlMapping n, YamlScalar value |
n.getDocument() = this and
value.getValue().matches("%InlineExpectations%")
|
value = n.lookup("postprocess")
or
value = n.lookup("postprocess").(YamlSequence).getElement(_)
)
}
/** Gets the relative path of the query in this `.qlref` file. */
string getRelativeQueryPath() {
exists(YamlMapping n | n.getDocument() = this |
result = n.lookup("query").(YamlScalar).getValue()
)
or
not exists(YamlMapping n | n.getDocument() = this) and
result = this.eval().(YamlScalar).getValue()
}
/** Gets the query file referenced in this `.qlref` file. */
File getQueryFile() {
exists(Folder f, string relativePath |
shouldAppend(this, f, relativePath) and
result = Folder::Append<shouldAppend/2>::append(f, relativePath)
)
}
predicate isPrintAst() {
this.getFile().getStem() = "PrintAst"
or
exists(YamlMapping n, YamlScalar value |
n.getDocument() = this and
value.getValue().matches("%PrintAst%")
|
value = n.lookup("query")
)
}
}