|
2 | 2 | * Provides classes for working with GitHub Actions lockfiles. |
3 | 3 | */ |
4 | 4 |
|
| 5 | +private import actions |
5 | 6 | private import codeql.actions.ast.internal.Yaml |
6 | 7 |
|
7 | | -/** An `actions.lock` file. */ |
8 | | -class ActionsLock extends YamlDocument { |
9 | | - ActionsLock() { this.getFile().getBaseName() = "actions.lock" } |
| 8 | +/** A `.github/workflows/actions.lock` file. */ |
| 9 | +class ActionsLock extends YamlDocument, YamlMapping { |
| 10 | + ActionsLock() { this.getFile().getRelativePath() = ".github/workflows/actions.lock" } |
| 11 | + |
| 12 | + pragma[nomagic] |
| 13 | + private predicate pins0(string workflowPath, string pinnedNwo, string ref) { |
| 14 | + exists(YamlSequence workflowPins, YamlScalar pinNode, YamlMapping dependency, string pin | |
| 15 | + this.lookup("workflows").(YamlMapping).lookup(workflowPath) = workflowPins and |
| 16 | + workflowPins.getElement(_) = pinNode and |
| 17 | + pin = pinNode.getValue() and |
| 18 | + pinnedNwo = pin.regexpCapture("^([^/@:]+/[^/@:]+)@([^:]+)$", 1) and |
| 19 | + ref = pin.regexpCapture("^([^/@:]+/[^/@:]+)@([^:]+)$", 2) and |
| 20 | + this.lookup("dependencies").(YamlMapping).lookup(pin) = dependency and |
| 21 | + dependency.lookup("ref").(YamlScalar).getValue() = ref and |
| 22 | + dependency |
| 23 | + .lookup("commit") |
| 24 | + .(YamlScalar) |
| 25 | + .getValue() |
| 26 | + .regexpMatch("^(sha1-[A-Fa-f0-9]{40}|sha256-[A-Fa-f0-9]{64})$") |
| 27 | + ) |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * Holds if this lockfile pins the use at `uses` to `ref` with a full commit digest. |
| 32 | + * Repository pins also cover sub-actions such as `actions/cache/save`. |
| 33 | + */ |
| 34 | + predicate pins(UsesStep uses, string ref) { |
| 35 | + exists(string workflowPath, string pinnedNwo, string nwo | |
| 36 | + this.pins0(workflowPath, pinnedNwo, ref) and |
| 37 | + workflowPath = uses.getLocation().getFile().getRelativePath() and |
| 38 | + nwo = uses.getCallee() |
| 39 | + | |
| 40 | + nwo.toLowerCase() = pinnedNwo.toLowerCase() |
| 41 | + or |
| 42 | + nwo.toLowerCase().prefix(pinnedNwo.length() + 1) = pinnedNwo.toLowerCase() + "/" |
| 43 | + ) |
| 44 | + } |
10 | 45 | } |
0 commit comments