Visitar URL original
Make actions/unpinned-tag lockfile- and $/-aware by nodeselector · Pull Request #22155 · github/codeql · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7fedff2
actions: stop unpinned-tag flagging $/ self-references
nodeselector Jul 10, 2026
180c109
actions: scaffold lockfile-aware pinning for unpinned-tag
nodeselector Jul 10, 2026
e80ae35
actions: add lockfile-to-data-extension generator for unpinned-tag
nodeselector Jul 10, 2026
9f8032d
actions: generate lockfile-pinned data extension during extraction
nodeselector Jul 10, 2026
9e7133b
actions: drop machine-specific replace, document lockfile generator l…
nodeselector Jul 10, 2026
d425c27
actions: keep lockfile generator go.mod free of local replace
nodeselector Jul 10, 2026
feed864
actions: rename self-reference to self repository in unpinned-tag
nodeselector Jul 10, 2026
c17aea9
actions: make lockfile-extension generation atomic
nodeselector Jul 10, 2026
287a59c
actions: drop private actions-lockfile dependency from generator
nodeselector Jul 10, 2026
b6a8394
actions: emit empty data list for zero-row lockfile extension
nodeselector Jul 10, 2026
f8f8aa8
actions/unpinned-tag: match lockfile pins case-insensitively on owner…
nodeselector Jul 13, 2026
2db34d2
actions: use US spelling in lockfile-aware pinning comments
nodeselector Jul 13, 2026
77ac6d9
actions: drop lockfile-extension generator from unpinned-tag PR
nodeselector Jul 23, 2026
91faa26
actions/unpinned-tag: normalize lockfile action identity
nodeselector Aug 31, 2026
45a6dd7
actions/unpinned-tag: regenerate expected results after sync
nodeselector Aug 31, 2026
2e04003
Actions: consume extracted lockfile pins
nodeselector Sep 2, 2026
24a18e4
Actions tests: add lockfile inline expectations
nodeselector Sep 2, 2026
e005d15
Actions tests: share inline expectations utility
nodeselector Sep 2, 2026
38f59df
Actions tests: keep inline adapter outside library API
nodeselector Sep 3, 2026
2b7e7ab
Actions lockfiles: ignore schema version value
nodeselector Sep 3, 2026
a2213ae
Actions lockfiles: match repository casing
nodeselector Sep 3, 2026
ff9bf5d
Code review suggestions
hvitved Sep 3, 2026
53a7851
Actions: address lockfile review feedback
nodeselector Sep 11, 2026
85d5925
Actions tests: move integration lockfile fixture
nodeselector Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Code review suggestions
  • Loading branch information
hvitved authored and nodeselector committed Sep 9, 2026
commit ff9bf5db531f4a503d08ead85014f68f747493b4
46 changes: 24 additions & 22 deletions actions/ql/lib/codeql/actions/Lock.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,21 @@
* Provides classes for working with GitHub Actions lockfiles.
*/

private import actions
private import codeql.actions.ast.internal.Yaml

/** An `actions.lock` file. */
class ActionsLock extends YamlDocument {
ActionsLock() { this.getFile().getBaseName() = "actions.lock" }
/** A `.github/workflows/actions.lock` file. */
class ActionsLock extends YamlDocument, YamlMapping {
ActionsLock() { this.getFile().getRelativePath() = ".github/workflows/actions.lock" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because of this change, actions/ql/test/library-tests/actions-lock/actions.lock needs to be moved into actions/ql/test/library-tests/actions-lock/.github/workflows/actions.lock, and actions/ql/test/library-tests/actions-lock/test.expected needs to be updated accordingly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out that actions/ql/integration-tests/actions-lock/src/actions.lock also needs to be moved (into actions/ql/integration-tests/actions-lock/src/.github/workflows/actions.lock).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got eager to rerequest review before checks finished, and then distracted by something else. Thanks.


/**
* Holds if the lockfile records `nwo` at `ref` for `workflowPath` with a full commit digest.
* Repository pins also cover sub-actions such as `actions/cache/save`.
*/
bindingset[nwo]
predicate pins(string workflowPath, string nwo, string ref) {
this.getFile().getRelativePath() = ".github/workflows/actions.lock" and
exists(
YamlMapping root, YamlSequence workflowPins, YamlScalar pinNode, YamlMapping dependency,
string pin, string pinnedNwo
|
root = this and
root.lookup("workflows").(YamlMapping).lookup(workflowPath) = workflowPins and
private predicate pins0(string workflowPath, string pinnedNwo, string ref) {
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
exists(YamlSequence workflowPins, YamlScalar pinNode, YamlMapping dependency, string pin |
this.lookup("workflows").(YamlMapping).lookup(workflowPath) = workflowPins and
workflowPins.getElement(_) = pinNode and
pin = pinNode.getValue() and
pinnedNwo = pin.regexpCapture("^([^/@:]+/[^/@:]+)@([^:]+)$", 1) and
ref = pin.regexpCapture("^([^/@:]+/[^/@:]+)@([^:]+)$", 2) and
(
nwo.toLowerCase() = pinnedNwo.toLowerCase()
or
nwo.toLowerCase().prefix(pinnedNwo.length() + 1) = pinnedNwo.toLowerCase() + "/"
) and
root.lookup("dependencies").(YamlMapping).lookup(pin) = dependency and
this.lookup("dependencies").(YamlMapping).lookup(pin) = dependency and
dependency.lookup("ref").(YamlScalar).getValue() = ref and
dependency
.lookup("commit")
Expand All @@ -39,4 +25,20 @@
.regexpMatch("^(sha1-[A-Fa-f0-9]{40}|sha256-[A-Fa-f0-9]{64})$")
Comment thread
nodeselector marked this conversation as resolved.
)
}

/**
* Holds if this lockfile pins the use at `uses` to `ref` with a full commit digest.
* Repository pins also cover sub-actions such as `actions/cache/save`.
*/
predicate pins(UsesStep uses, string ref) {
exists(string workflowPath, string pinnedNwo, string nwo |
this.pins0(workflowPath, pinnedNwo, ref) and
workflowPath = uses.getLocation().getFile().getRelativePath() and
nwo = uses.getCallee()
|
nwo.toLowerCase() = pinnedNwo.toLowerCase()
or
nwo.toLowerCase().prefix(pinnedNwo.length() + 1) = pinnedNwo.toLowerCase() + "/"
)
}
}
7 changes: 1 addition & 6 deletions actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,7 @@ where
uses.getVersion() = version and
not isTrustedOwner(nwo) and
not isSelfRepository(nwo) and
not exists(UsesStep step |
uses = step and
exists(ActionsLock lock |
lock.pins(step.getLocation().getFile().getRelativePath(), nwo, version)
)
) and
not any(ActionsLock lock).pins(uses, version) and
not (
if uses instanceof UsesStep and isContainerImage(nwo)
then isPinnedContainer(version)
Expand Down
Loading