Skip to content

Commit 65f4fcd

Browse files
committed
feat(iac): Update Dependencies and add better Semver support
1 parent f754bc9 commit 65f4fcd

3 files changed

Lines changed: 85 additions & 4 deletions

File tree

ql/lib/codeql/iac/Dependencies.qll

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,89 @@ class Dependency extends Location {
2727
/**
2828
* Gets the version of the dependency.
2929
*/
30-
string getVersion() { result = version.replaceAll("=", "") }
30+
string getVersion() { result = this.getSemanticVersion().getPretty() }
3131

32-
SemanticVersion getSemanticVersion() { result = this.getVersion() }
32+
/**
33+
* Gets the raw version of the dependency.
34+
*/
35+
string getRawVersion() { result = version }
36+
37+
/**
38+
* Gets the semantic version of the dependency.
39+
*/
40+
SemanticVersion getSemanticVersion() { result = version }
3341
}
3442

3543
class SemanticVersion extends string {
36-
private Dependency dep;
44+
Dependency dep;
45+
string normalized;
46+
string pretty;
47+
48+
SemanticVersion() {
49+
this = dep.getRawVersion() and
50+
normalized = normalizeSemver(this) and
51+
pretty = prettySemver(this)
52+
}
53+
54+
/**
55+
* Holds if this version may be before `last`.
56+
*/
57+
bindingset[last]
58+
predicate maybeBefore(string last) { normalized < normalizeSemver(last) }
59+
60+
/**
61+
* Holds if this version may be after `first`.
62+
*/
63+
bindingset[first]
64+
predicate maybeAfter(string first) { normalizeSemver(first) < normalized }
3765

38-
SemanticVersion() { this = dep.getVersion() }
66+
/**
67+
* Holds if this version may be between `first` (inclusive) and `last` (exclusive).
68+
*/
69+
bindingset[first, last]
70+
predicate maybeBetween(string first, string last) {
71+
normalizeSemver(first) <= normalized and
72+
normalized < normalizeSemver(last)
73+
}
74+
75+
/**
76+
* Holds if this version is equivalent to `other`.
77+
*/
78+
bindingset[other]
79+
predicate is(string other) { normalized = normalizeSemver(other) }
80+
81+
string getPretty() { result = pretty }
3982
}
83+
84+
bindingset[str]
85+
private string leftPad(string str) { result = ("000" + str).suffix(str.length()) }
86+
87+
/**
88+
* Normalizes a SemVer string such that the lexicographical ordering
89+
* of two normalized strings is consistent with the SemVer ordering.
90+
*
91+
* Pre-release information and build metadata is not yet supported.
92+
*/
93+
bindingset[orig]
94+
private string normalizeSemver(string orig) {
95+
exists(string pattern, string major, string minor, string patch |
96+
pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
97+
major = orig.regexpCapture(pattern, 2) and
98+
minor = orig.regexpCapture(pattern, 3) and
99+
patch = orig.regexpCapture(pattern, 4)
100+
|
101+
result = leftPad(major) + "." + leftPad(minor) + "." + leftPad(patch)
102+
)
103+
}
104+
105+
bindingset[orig]
106+
private string prettySemver(string orig) {
107+
exists(string pattern, string major, string minor, string patch |
108+
pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
109+
major = orig.regexpCapture(pattern, 2) and
110+
minor = orig.regexpCapture(pattern, 3) and
111+
patch = orig.regexpCapture(pattern, 4)
112+
|
113+
result = major + "." + minor + "." + patch
114+
)
115+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
dependencies
12
| providers.tf:5:15:8:5 | hashicorp/azurerm@3.0.0 |
23
| providers.tf:9:14:9:22 | hashicorp/time@~>0.7.2 |
34
| providers.tf:10:14:10:22 | hashicorp/random@~>3.3.1 |
5+
semver
6+
| 3.0.0 |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import hcl
22

33
query predicate dependencies(Dependency d) { any() }
4+
5+
query predicate semver(Dependency d, SemanticVersion v) { d.getSemanticVersion() = v }

0 commit comments

Comments
 (0)