mirror of
https://github.com/github/codeql.git
synced 2026-01-29 22:32:58 +01:00
Add libraries modeling dependencies
This commit is contained in:
78
ql/src/semmle/go/dependencies/Dependencies.qll
Normal file
78
ql/src/semmle/go/dependencies/Dependencies.qll
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Provides classes for modeling go.mod dependencies.
|
||||
*/
|
||||
|
||||
import go
|
||||
private import semmle.go.dependencies.DependencyCustomizations
|
||||
|
||||
/**
|
||||
* An abstract representation of a dependency.
|
||||
*/
|
||||
abstract class Dependency extends Locatable {
|
||||
/**
|
||||
* Holds if this dependency has package path `path` and version `v`.
|
||||
*
|
||||
* If the version cannot be determined, `v` is bound to the string
|
||||
* `"unknown"`.
|
||||
*/
|
||||
abstract predicate info(string path, string v);
|
||||
|
||||
/** Gets the package path of this dependency. */
|
||||
string getDepPath() { this.info(result, _) }
|
||||
|
||||
/** Gets the version of this dependency. */
|
||||
string getDepVer() { this.info(_, result) }
|
||||
|
||||
/**
|
||||
* An import of this dependency.
|
||||
*/
|
||||
ImportSpec getAnImport() { result.getPath() = this.getDepPath() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A dependency from a go.mod file.
|
||||
*/
|
||||
class GoModDependency extends Dependency, GoModRequireLine {
|
||||
override predicate info(string path, string v) {
|
||||
this.replacementInfo(path, v)
|
||||
or
|
||||
not this.replacementInfo(_, _) and
|
||||
this.originalInfo(path, v)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a replace line that replaces this dependency with a dependency to `path`,
|
||||
* version `v`.
|
||||
*/
|
||||
predicate replacementInfo(string path, string v) {
|
||||
exists(GoModReplaceLine replace |
|
||||
replace.getFile() = this.getFile() and
|
||||
replace.getOriginalPath() = this.getPath()
|
||||
|
|
||||
path = replace.getReplacementPath() and
|
||||
(
|
||||
v = replace.getReplacementVer()
|
||||
or
|
||||
not exists(replace.getReplacementVer()) and
|
||||
v = "unknown"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a version that was excluded for this dependency.
|
||||
*/
|
||||
string getAnExcludedVer() {
|
||||
exists(GoModExcludeLine exclude |
|
||||
exclude.getFile() = this.getFile() and
|
||||
exclude.getPath() = this.getPath()
|
||||
|
|
||||
result = exclude.getVer()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this require line originally states dependency `path` had version `ver`.
|
||||
*/
|
||||
predicate originalInfo(string path, string v) { path = this.getPath() and v = this.getVer() }
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
96
ql/src/semmle/go/dependencies/SemVer.qll
Normal file
96
ql/src/semmle/go/dependencies/SemVer.qll
Normal file
@@ -0,0 +1,96 @@
|
||||
import semmle.go.dependencies.Dependencies
|
||||
|
||||
/**
|
||||
* A SemVer-formatted version string in a dependency.
|
||||
*
|
||||
* Pre-release information and build metadata is not yet supported.
|
||||
*/
|
||||
class DependencySemVer extends string {
|
||||
Dependency dep;
|
||||
string normalized;
|
||||
|
||||
DependencySemVer() {
|
||||
this = dep.getDepVer() and
|
||||
normalized = normalizeSemver(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this version may be before `last`.
|
||||
*/
|
||||
bindingset[last]
|
||||
predicate maybeBefore(string last) { normalized < normalizeSemver(last) }
|
||||
|
||||
/**
|
||||
* Holds if this version may be after `first`.
|
||||
*/
|
||||
bindingset[first]
|
||||
predicate maybeAfter(string first) { normalizeSemver(first) < normalized }
|
||||
|
||||
/**
|
||||
* Holds if this version may be between `first` (inclusive) and `last` (exclusive).
|
||||
*/
|
||||
bindingset[first, last]
|
||||
predicate maybeBetween(string first, string last) {
|
||||
normalizeSemver(first) <= normalized and
|
||||
normalized < normalizeSemver(last)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this version is equivalent to `other`.
|
||||
*/
|
||||
bindingset[other]
|
||||
predicate is(string other) { normalized = normalizeSemver(other) }
|
||||
|
||||
/**
|
||||
* Gets the dependency that uses this string.
|
||||
*/
|
||||
Dependency getDependency() { result = dep }
|
||||
}
|
||||
|
||||
bindingset[str]
|
||||
private string leftPad(string str) { result = ("000" + str).suffix(str.length()) }
|
||||
|
||||
/**
|
||||
* Normalizes a SemVer string such that the lexicographical ordering
|
||||
* of two normalized strings is consistent with the SemVer ordering.
|
||||
*
|
||||
* Pre-release information and build metadata is not yet supported.
|
||||
*/
|
||||
bindingset[orig]
|
||||
private string normalizeSemver(string orig) {
|
||||
exists(string pattern, string major, string minor, string patch |
|
||||
pattern = "v?(\\d+)\\.(\\d+)\\.(\\d+)(\\D.*)?" and
|
||||
major = orig.regexpCapture(pattern, 1) and
|
||||
minor = orig.regexpCapture(pattern, 2) and
|
||||
patch = orig.regexpCapture(pattern, 3)
|
||||
|
|
||||
result = leftPad(major) + "." + leftPad(minor) + "." + leftPad(patch)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A version string in a dependency that has a SemVer, but also contains a git commit SHA.
|
||||
*
|
||||
* This class is useful for interacting with go.mod versions, which use SemVer, but can also contain
|
||||
* SHAs if no useful tags are found, or when a user wishes to specify a commit SHA.
|
||||
*
|
||||
* Pre-release information and build metadata is not yet supported.
|
||||
*/
|
||||
class DependencySemShaVer extends DependencySemVer {
|
||||
string sha;
|
||||
|
||||
DependencySemShaVer() { sha = this.regexpCapture(".*-([0-9a-f]+)", 1) }
|
||||
|
||||
/**
|
||||
* Gets the commit SHA associated with this version.
|
||||
*/
|
||||
string getSha() { result = sha }
|
||||
|
||||
bindingset[other]
|
||||
override predicate is(string other) {
|
||||
this.getSha() = other.(DependencySemShaVer).getSha()
|
||||
or
|
||||
not other instanceof DependencySemShaVer and
|
||||
super.is(other)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user