1
+ /**
2
+ * Dependencies module for Infrastructure as Code languages.
3
+ */
1
4
private import codeql.Locations
2
5
private import codeql.hcl.Terraform
3
6
4
7
/**
5
8
* Dependency for all Infrastructure as Code languages.
6
9
*/
7
- class Dependency extends Location {
10
+ abstract class Dependency extends Location {
11
+ /**
12
+ * Gets the name of the dependency.
13
+ */
14
+ abstract string getName ( ) ;
15
+ /**
16
+ * Gets the version of the dependency (in a format that is human-readable).
17
+ */
18
+ abstract string getVersion ( ) ;
19
+ /**
20
+ * Gets the raw version of the dependency (in a format that is machine-readable).
21
+ */
22
+ abstract string getRawVersion ( ) ;
23
+ /**
24
+ * Gets the semantic version of the dependency.
25
+ */
26
+ abstract SemanticVersion getSemanticVersion ( ) ;
27
+ }
28
+
29
+
30
+ /**
31
+ * Dependency for Terraform.
32
+ */
33
+ class TerraformDependency extends Dependency {
8
34
string name ;
9
35
string version ;
10
36
11
- Dependency ( ) {
37
+ TerraformDependency ( ) {
12
38
// Terraform Provider
13
39
exists ( Terraform:: Terraform tf , Terraform:: RequiredProvider rp | rp = tf .getRequiredProvider ( ) |
14
40
this = rp .getLocation ( ) and
@@ -19,21 +45,87 @@ class Dependency extends Location {
19
45
20
46
override string toString ( ) { result = this .getName ( ) + "@" + this .getVersion ( ) }
21
47
48
+ override string getName ( ) { result = name }
49
+
50
+
51
+ override string getVersion ( ) { result = this .getSemanticVersion ( ) .getPretty ( ) }
52
+
53
+
54
+ override string getRawVersion ( ) { result = version }
55
+
56
+ override SemanticVersion getSemanticVersion ( ) { result = version }
57
+ }
58
+
59
+ class SemanticVersion extends string {
60
+ Dependency dep ;
61
+ string normalized ;
62
+ string pretty ;
63
+
64
+ SemanticVersion ( ) {
65
+ this = dep .getRawVersion ( ) and
66
+ normalized = normalizeSemver ( this ) and
67
+ pretty = prettySemver ( this )
68
+ }
69
+
22
70
/**
23
- * Gets the name of the dependency .
71
+ * Holds if this version may be before `last` .
24
72
*/
25
- string getName ( ) { result = name }
73
+ bindingset [ last]
74
+ predicate maybeBefore ( string last ) { normalized < normalizeSemver ( last ) }
26
75
27
76
/**
28
- * Gets the version of the dependency .
77
+ * Holds if this version may be after `first` .
29
78
*/
30
- string getVersion ( ) { result = version .replaceAll ( "=" , "" ) }
79
+ bindingset [ first]
80
+ predicate maybeAfter ( string first ) { normalizeSemver ( first ) < normalized }
31
81
32
- SemanticVersion getSemanticVersion ( ) { result = this .getVersion ( ) }
82
+ /**
83
+ * Holds if this version may be between `first` (inclusive) and `last` (exclusive).
84
+ */
85
+ bindingset [ first, last]
86
+ predicate maybeBetween ( string first , string last ) {
87
+ normalizeSemver ( first ) <= normalized and
88
+ normalized < normalizeSemver ( last )
89
+ }
90
+
91
+ /**
92
+ * Holds if this version is equivalent to `other`.
93
+ */
94
+ bindingset [ other]
95
+ predicate is ( string other ) { normalized = normalizeSemver ( other ) }
96
+
97
+ string getPretty ( ) { result = pretty }
33
98
}
34
99
35
- class SemanticVersion extends string {
36
- private Dependency dep ;
100
+ bindingset [ str ]
101
+ private string leftPad ( string str ) { result = ( "000" + str ) . suffix ( str . length ( ) ) }
37
102
38
- SemanticVersion ( ) { this = dep .getVersion ( ) }
103
+ /**
104
+ * Normalizes a SemVer string such that the lexicographical ordering
105
+ * of two normalized strings is consistent with the SemVer ordering.
106
+ *
107
+ * Pre-release information and build metadata is not yet supported.
108
+ */
109
+ bindingset [ orig]
110
+ private string normalizeSemver ( string orig ) {
111
+ exists ( string pattern , string major , string minor , string patch |
112
+ pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
113
+ major = orig .regexpCapture ( pattern , 2 ) and
114
+ minor = orig .regexpCapture ( pattern , 3 ) and
115
+ patch = orig .regexpCapture ( pattern , 4 )
116
+ |
117
+ result = leftPad ( major ) + "." + leftPad ( minor ) + "." + leftPad ( patch )
118
+ )
39
119
}
120
+
121
+ bindingset [ orig]
122
+ private string prettySemver ( string orig ) {
123
+ exists ( string pattern , string major , string minor , string patch |
124
+ pattern = "(=|~>|^)(\\d+)\\.(\\d+)\\.(\\d+)" and
125
+ major = orig .regexpCapture ( pattern , 2 ) and
126
+ minor = orig .regexpCapture ( pattern , 3 ) and
127
+ patch = orig .regexpCapture ( pattern , 4 )
128
+ |
129
+ result = major + "." + minor + "." + patch
130
+ )
131
+ }
0 commit comments