Add libraries modeling dependencies

This commit is contained in:
Sauyon Lee
2020-03-04 01:24:38 -08:00
parent d92e49fb17
commit 6c78490bbe
3 changed files with 175 additions and 0 deletions

View 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() }
}

View File

@@ -0,0 +1 @@

View 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)
}
}