Skip to content

Extend actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)#21692

Open
Copilot wants to merge 5 commits intomainfrom
copilot/update-codeql-query-for-composite-actions
Open

Extend actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml)#21692
Copilot wants to merge 5 commits intomainfrom
copilot/update-codeql-query-for-composite-actions

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 10, 2026

actions/unpinned-tag currently only reports uses: refs from workflow files because it filters on getEnclosingWorkflow(). 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)

    • Refactored container-name resolution into a helper predicate that accepts either:
      • UsesStep in a Workflow (existing logic retained: workflow name, else workflow file basename), or
      • UsesStep in a CompositeAction (new logic: composite metadata file basename, e.g. action.yml).
    • Main query now uses this generalized predicate instead of requiring uses.getEnclosingWorkflow() = workflow.
  • Behavior preserved for existing workflow alerts

    • Workflow matching and formatting remain unchanged for existing cases.
    • Existing immutable/pinned checks and trusted-owner filtering are untouched.
  • CWE-829 test coverage extended

    • Added composite action fixture with:
      • unpinned tag (foo/bar@v2) → alert expected
      • pinned SHA (foo/bar@<40-hex>) → no alert expected
    • Updated UnpinnedActionsTag.expected with the new composite action alert.
private predicate getStepContainerName(UsesStep uses, string name) {
  exists(Workflow workflow | ... )
  or
  exists(CompositeAction action |
    uses.getEnclosingCompositeAction() = action and
    name = action.getLocation().getFile().getBaseName()
  )
}

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
    • Triggering command: /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 /usr/local/lib/node_modules/@bazel/bazelisk/bazelisk-linux_amd64 query kind(&#34;.*test&#34;, //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 the actions/unpinned-tag CodeQL query so that unpinned action refs used in composite actions are reported.

Context:

  • Current query: actions/ql/src/Security/CWE-829/UnpinnedActionsTag.ql in github/codeql requires uses.getEnclosingWorkflow() = workflow, so it only reports workflow uses steps.
  • Support escalation issue: github/codeql-team#4594 requests the rule also evaluate composite actions’ metadata.

Requirements:

  1. Update the query (and/or shared library predicates) so that uses: references inside composite action metadata files are included.
    • Composite actions are defined in action.yml / action.yaml and contain runs.steps[].uses.
    • Ensure both workflow steps and composite action steps are analyzed.
  2. Preserve existing behavior for workflows and ensure message formatting remains reasonable.
    • Ideally include a “name” for the container: for workflows use workflow name/file base name; for composite actions use something like the file base name (action.yml) or action name: if present.
  3. Add/extend tests under actions/ql/test/... to cover:
    • A workflow file with an unpinned tag should still alert.
    • A composite action metadata file with an unpinned tag should now alert.
    • A pinned SHA should not alert.
  4. Run/adjust any query suite expected files or baselines if needed.

Notes:

  • Prefer using existing Actions AST classes. Look for CompositeAction or UsesStep context APIs.
  • If needed, refactor by introducing a helper predicate (e.g., uses.getEnclosingWorkflow() OR uses.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-tag query: it’s (effectively) a workflow-only check today, so it will flag uses: owner/repo@tag inside .github/workflows/*.yml|*.yaml, but it won’t (currently) evaluate composite action metadata (action.yml / action.yaml) for runs.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 workflows

In semmle-code there’s explicit “Actions workflow” handling that’s scoped to .github/workflows (even in internal tooling). For example, the repo’s actionlint genrule only targets .github/workflows/*.yml and doesn’t mention action.yml at all:

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.ql in github/semmle-code via code search and didn’t get a hit in this repo snapshot, so I can’t point at the exact ql/actions/.../UnpinnedActionsTag.ql implementation here. (The issue links to github/codeql, not semmle-code, which likely explains the mismatch.)

2) github/codeql-action: it runs CodeQL CLI, but it doesn’t add special handling for composite action metadata

From 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.

So: if the query pack for the actions language doesn’t model action.yml, codeql-action won’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 placing uses: owner/repo@tag inside runs.steps in the action metadata file.

Recommendation / what Engineering should do next

  1. Confirm intended scope: If the goal of `actions/unpinned...

This pull request was created from Copilot chat.

Copilot AI changed the title [WIP] Update CodeQL query to support composite action metadata Extend actions/unpinned-tag to analyze composite action metadata (action.yml / action.yaml) Apr 10, 2026
Copilot AI requested a review from oscarsj April 10, 2026 11:21
@github-actions github-actions bot added the Actions Analysis of GitHub Actions label Apr 15, 2026
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) {
@oscarsj oscarsj force-pushed the copilot/update-codeql-query-for-composite-actions branch from e5f4b09 to e598c56 Compare April 20, 2026 10:38
@oscarsj oscarsj marked this pull request as ready for review April 20, 2026 10:43
@oscarsj oscarsj requested a review from a team as a code owner April 20, 2026 10:43
Copilot AI review requested due to automatic review settings April 20, 2026 10:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 UsesStep in either a Workflow or a CompositeAction can 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

Comment on lines +34 to +38
private predicate getStepContainerName(UsesStep uses, string name) {
exists(Workflow workflow |
uses.getEnclosingWorkflow() = workflow and
(
workflow.getName() = name
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
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.

Updated in commit b204603: the query header @name now reflects the expanded scope (workflow or composite action).

Comment on lines +1 to +6
name: Composite unpinned tag test
runs:
using: "composite"
steps:
- uses: foo/bar@v2
- uses: foo/bar@25b062c917b0c75f8b47d8469aff6c94ffd89abb
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines 10 to 12
| .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 |
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Agent-Logs-Url: https://github.com/github/codeql/sessions/5425ff86-b998-4c7b-9447-52c8ae74a7a2

Co-authored-by: oscarsj <1410188+oscarsj@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Actions Analysis of GitHub Actions documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants