Extend actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)#21692
Extend actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)#21692
actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)#21692Conversation
Agent-Logs-Url: https://github.com/github/codeql/sessions/c52790be-00f6-4250-b46b-38c05365ddd7 Co-authored-by: oscarsj <1410188+oscarsj@users.noreply.github.com>
actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)
| private predicate isContainerImage(string nwo) { nwo.regexpMatch("^docker://.+") } | ||
|
|
||
| from UsesStep uses, string nwo, string version, Workflow workflow, string name | ||
| private predicate getStepContainerName(UsesStep uses, string name) { |
e5f4b09 to
e598c56
Compare
There was a problem hiding this comment.
Pull request overview
This PR expands the actions/unpinned-tag query’s coverage so it can also report unpinned uses: references found in composite action metadata (action.yml / action.yaml), not just workflow files.
Changes:
- Generalized the “container name” resolution logic so
UsesStepin either aWorkflowor aCompositeActioncan be reported consistently. - Extended CWE-829 query-test fixtures/expectations to include a composite action with an unpinned tag (and a pinned-SHA negative case).
- Added a change note documenting the expanded analysis scope.
Show a summary per file
| File | Description |
|---|---|
| actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql | Broadens query scope to include composite actions via a new helper predicate. |
| actions/ql/test/query-tests/Security/CWE-829/UnpinnedActionsTag.expected | Adds the expected alert for the new composite-action fixture. |
| actions/ql/test/query-tests/Security/CWE-829/.github/actions/unpinned-tag/action.yml | New composite action fixture containing both unpinned-tag and pinned-SHA uses: refs. |
| actions/ql/test/query-tests/Security/CWE-829/UntrustedCheckoutCritical.expected | Updates expected output impacted by the newly added composite-action fixture. |
| actions/ql/src/change-notes/2026-04-20-unpinned-tag-composite-actions.md | Documents the query’s expanded coverage in release notes. |
Copilot's findings
- Files reviewed: 5/5 changed files
- Comments generated: 3
| private predicate getStepContainerName(UsesStep uses, string name) { | ||
| exists(Workflow workflow | | ||
| uses.getEnclosingWorkflow() = workflow and | ||
| ( | ||
| workflow.getName() = name |
There was a problem hiding this comment.
The query’s metadata comment at the top of the file still describes this as a workflow-only check (for example, the @name says “in workflow”), but the query now also analyzes composite action metadata. Please update the header comment to reflect the expanded scope so the rendered query docs aren’t misleading.
There was a problem hiding this comment.
Updated in commit b204603: the query header @name now reflects the expanded scope (workflow or composite action).
| name: Composite unpinned tag test | ||
| runs: | ||
| using: "composite" | ||
| steps: | ||
| - uses: foo/bar@v2 | ||
| - uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb |
There was a problem hiding this comment.
Test coverage for the new composite-action support only exercises action.yml. Since the intended scope is action.yml and action.yaml, add a second composite-action fixture using the .yaml extension with an unpinned uses: ref (and update the expected results) to ensure both metadata filenames are handled.
| | .github/actions/download-artifact/action.yaml:29:7:32:18 | Run Step | .github/workflows/resolve-args.yml:22:9:36:13 | Run Step: resolve-step | | ||
| | .github/actions/unpinned-tag/action.yml:5:7:6:4 | Uses Step | .github/actions/unpinned-tag/action.yml:6:7:6:61 | Uses Step | | ||
| | .github/workflows/actor_trusted_checkout.yml:9:7:14:4 | Uses Step | .github/workflows/actor_trusted_checkout.yml:14:7:15:4 | Uses Step | |
There was a problem hiding this comment.
The PR description mentions updating UnpinnedActionsTag.expected, but this change set also updates UntrustedCheckoutCritical.expected (likely due to the new composite-action fixture affecting that query’s graph). Consider noting this in the PR description to avoid confusion for reviewers and future archaeology.
Agent-Logs-Url: https://github.com/github/codeql/sessions/5425ff86-b998-4c7b-9447-52c8ae74a7a2 Co-authored-by: oscarsj <1410188+oscarsj@users.noreply.github.com>
actions/unpinned-tagcurrently only reportsuses:refs from workflow files because it filters ongetEnclosingWorkflow(). This change broadens coverage to also report unpinned refs in composite action metadata (runs.steps[].uses) while preserving existing workflow behavior and message shape.Query scope expansion (workflow + composite action)
UsesStepin aWorkflow(existing logic retained: workflowname, else workflow file basename), orUsesStepin aCompositeAction(new logic: composite metadata file basename, e.g.action.yml).uses.getEnclosingWorkflow() = workflow.Behavior preserved for existing workflow alerts
CWE-829 test coverage extended
foo/bar@v2) → alert expectedfoo/bar@<40-hex>) → no alert expectedUnpinnedActionsTag.expectedwith the new composite action alert.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
releases.bazel.build/usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 query kind(".*test", //actions/...)(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
Implement support for scanning composite action metadata files (
action.yml/action.yaml) in theactions/unpinned-tagCodeQL query so that unpinned action refs used in composite actions are reported.Context:
actions/ql/src/Security/CWE-829/UnpinnedActionsTag.qlingithub/codeqlrequiresuses.getEnclosingWorkflow() = workflow, so it only reports workflow uses steps.Requirements:
uses:references inside composite action metadata files are included.action.yml/action.yamland containruns.steps[].uses.action.yml) or actionname:if present.actions/ql/test/...to cover:Notes:
CompositeActionorUsesStepcontext APIs.uses.getEnclosingWorkflow()ORuses.getEnclosingCompositeAction()), or generalizing to a shared “step container”.Repository: github/codeql
The following is the prior conversation context from the user's chat exploration (may be truncated):
User: can you answer the question on the support escalation? use https://github.com/github/semmle-code and https://github.com/github/codeql-action codebases to investigate
Assistant: This looks like expected behavior of the current
actions/unpinned-tagquery: it’s (effectively) a workflow-only check today, so it will flaguses: owner/repo@taginside.github/workflows/*.yml|*.yaml, but it won’t (currently) evaluate composite action metadata (action.yml/action.yaml) forruns.steps[].uses. Your repro matches that gap.What I found from the two codebases you asked me to use
1)
github/semmle-code: the Actions “surface” being targeted is workflowsIn
semmle-codethere’s explicit “Actions workflow” handling that’s scoped to.github/workflows(even in internal tooling). For example, the repo’sactionlintgenrule only targets.github/workflows/*.ymland doesn’t mentionaction.ymlat all:builduses.github/workflows/*.ymlas the input globs for the GitHub Actions workflow linting target.(See
buildaround theactionlintgenrule.)Source: https://github.com/github/semmle-code/blob/4b5f72d62dadeb9ca073d12cadefd41c0ebc5472/build#L827-L871
That doesn’t prove the CodeQL query itself filters to workflows, but it’s consistent with what you’re seeing: “Actions language” checks in this repo historically center on workflow files, not composite-action metadata.
Also: I attempted to locate
UnpinnedActionsTag.qlingithub/semmle-codevia code search and didn’t get a hit in this repo snapshot, so I can’t point at the exactql/actions/.../UnpinnedActionsTag.qlimplementation here. (The issue links togithub/codeql, notsemmle-code, which likely explains the mismatch.)2)
github/codeql-action: it runs CodeQL CLI, but it doesn’t add special handling for composite action metadataFrom
codeql-action, the “analyze” step orchestrates database finalization and then runs queries (runQueries(...)). Nothing I found suggests it separately enumerates “workflow vs action metadata” files itself; it delegates that to the CodeQL CLI and the selected query packs/suites.src/analyze-action.tscallsrunQueries(...)to execute the configured queries/packs.Source: https://github.com/github/codeql-action/blob/597e12aa85c95194dbf8a83c0e3a649444a119bc/src/analyze-action.ts#L325-L355
So: if the query pack for the
actionslanguage doesn’t modelaction.yml,codeql-actionwon’t “pick it up” magically.Direct answer to the escalation question (“is this expected?”)
Yes, this is expected given the current implementation/coverage of the rule: it is designed (or at least currently implemented) to analyze workflow files and doesn’t currently treat composite action metadata (
action.yml/action.yaml) as part of the analyzed surface for this query. That means a composite action can bypass the check today by placinguses: owner/repo@taginsideruns.stepsin the action metadata file.Recommendation / what Engineering should do next
This pull request was created from Copilot chat.