Skip to content

Compile fails on local composite actions (uses: ./...) after auto-pin change (#40475): "unversioned action has no available pin" #40886

Description

@sg650

Summary

Since the auto-pin change in #40475 (shipped in v0.80.x), gh aw compile fails for any workflow whose steps reference a local composite action via a relative path, e.g.:

steps:
  - uses: ./.github/actions/my-setup

Compilation aborts with:

error: imported steps: unversioned action "./.github/actions/my-setup" has no available pin; add a @ref (e.g. @v1) or include it in action-pins.json

This worked on the prior release. Local actions compiled fine before the new "fail when no pin is available" behavior was added.

Why this is a regression (and why the suggested fixes don't apply)

#40475 was intended to catch unversioned remote actions (e.g. uses: actions/checkout with no @ref) and auto-pin them, failing only when no pin exists. But the check does not special-case local actions, which are a first-class, documented GitHub Actions feature.

Neither remediation in the error message is valid for a local action:

  • "add a @ref" — local action paths cannot carry a ref. uses: ./path@v1 is invalid GitHub Actions syntax; local actions are resolved from the repository at the workflow's own checked-out SHA.
  • "include it in action-pins.json" — pins are keyed by owner/repo + version + commit SHA. A local action has no upstream repo and no independent SHA to pin to, so there is no meaningful entry to add.

So local composite actions currently have no way to compile under v0.80.x.

Root cause (code pointer)

In pkg/workflow/action_pins.go, applyActionPinToTypedStep calls extractActionRepo(step.Uses) / extractActionVersion(step.Uses). For uses: ./.github/actions/my-setup:

  • ExtractRepo (in pkg/actionpins/actionpins.go) does strings.Cut(uses, "@"); with no @, it returns the whole string (the local path) as the "repo" — non-empty.
  • ExtractVersion returns "".
  • With an empty version, the code resolves a pin via getCachedActionPin, gets "" (no embedded/cached pin for a local path), and returns the new hard error.

There's no guard for uses: values that are local action references (./..., ../...) or Docker refs (docker://...).

Minimal repro

  1. Create a local composite action at .github/actions/my-setup/action.yml:

    name: My Setup
    description: Example local composite action
    runs:
      using: composite
      steps:
        - shell: bash
          run: echo "hello"
  2. Reference it from a workflow's steps (directly, or via an imported shared component's steps:):

    steps:
      - uses: ./.github/actions/my-setup
  3. Run gh aw compile.

Expected: compiles; the local uses: ./... is emitted as-is (it's already valid Actions syntax and inherently tied to the repo SHA).

Actual: compilation fails with unversioned action "./.github/actions/my-setup" has no available pin; ....

Suggested fix

In applyActionPinToTypedStep (and the typed-steps variant), skip pin resolution entirely when step.Uses is a local action reference — i.e. starts with ./ or ../ — and emit it unchanged. (Docker docker:// references likely warrant the same passthrough.) Local actions are valid, ref-less by design, and cannot/should not be pinned.

Environment

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions