Skip to content

Repository files navigation

GitHub Actions Buildkite plugin

Note

Running GitHub Actions workflows in Buildkite is currently in public preview. To report issues with the preview, open an issue in the buildkite-gha repository. For help migrating to native Buildkite Pipelines steps, contact the Buildkite Support team.

The plugin and runtime are under active development. Review the buildkite-gha v0.12.1 compatibility guide before adding a workflow.

The GitHub Actions Buildkite plugin converts a supported GitHub Actions workflow into native Buildkite Pipelines jobs without creating a GitHub Actions workflow run. This lets you start migrating a workflow before converting it into native Buildkite Pipelines steps.

During the preview, start with a workflow in a public github.com repository that targets Linux x86-64 and does not need secrets. Private repository checkout and temporary GitHub tokens are available in limited cases but require extra setup. Check the supported functionality and limitations before you begin.

Add workflows to a pipeline

Add the plugin to a keyed command step in your pipeline configuration. Select the workflow you want to import explicitly:

steps:
  - label: ":github: GitHub Actions"
    key: "github-actions"
    agents:
      queue: importer-linux
    plugins:
      - github-actions#latest:
          workflow: .github/workflows/ci.yml

The selector must be an explicit path to a tracked .yml or .yaml workflow file. When this importer step runs, the plugin uploads one dynamic pipeline containing a Buildkite group for each directly runnable workflow. Each workflow job and static matrix entry becomes a Buildkite Pipelines job that depends on the importer step. The importer step must have a key and must be scheduled explicitly on either a Linux amd64 or native macOS arm64 agent. The plugin's runners mappings schedule generated workflow jobs only; they do not select or change the importer agent.

The Git ref after github-actions# selects the plugin code. Use a specific release such as github-actions#v0.11.0 for an immutable pin, or use github-actions#latest to follow the newest stable plugin release that has passed the required validation. This is separate from the version property below, which selects the buildkite-gha runtime.

Configure runtime selection with the following properties:

Option Required Default Description
workflow One of workflow or workflows One explicit tracked .yml or .yaml workflow path.
workflows One of workflow or workflows Non-empty array of explicit tracked .yml or .yaml workflow paths.
version No latest Latest stable or an exact buildkite-gha release from 0.9.0 onward.
source-ref No Full buildkite-gha source commit to build for development testing; mutually exclusive with version.
minimum-release-age No 0s Minimum release age used by mise when resolving latest.
runners No Exact runs-on mappings to Buildkite queues and optional immutable Linux image overrides.

Note

Plugin and runtime versions are independent. Pin version to keep release-version selection stable, or use latest to follow stable runtime releases. Increase minimum-release-age (for example, to 24h) to delay newly published releases. If you update the runtime version, use its matching compatibility guide.

To test unreleased runtime behavior, set source-ref to a full lowercase 40-character commit from the public buildkite/buildkite-gha repository and omit version. The plugin uses mise and Go 1.26.5 to build Linux amd64 and Darwin arm64 executables from that exact source, runs the executable native to the importer agent, and supplies the counterpart to generated jobs. Source commits are for development only and do not use release checksums, attestations, or minimum-release-age.

The plugin schema requires exactly one of workflow or workflows and validates its explicit paths, along with the runtime-acquisition fields version, source-ref, and minimum-release-age. It passes behavioral configuration through to the selected buildkite-gha runtime, which validates the complete configuration strictly. This allows runtime releases to extend the supported syntax without requiring a companion plugin release.

Select workflows

Use workflow as the simple form for one explicit path:

plugins:
  - github-actions#latest:
      workflow: .github/workflows/ci.yml

Use the non-empty workflows array when importing multiple explicit paths:

plugins:
  - github-actions#latest:
      workflows:
        - .github/workflows/ci.yml
        - .github/workflows/release.yml

Configure exactly one selector form. Each value must identify one regular, tracked .yml or .yaml file inside the repository. Empty values and arrays, directories, globs, and wildcard selectors are not accepted. Selected paths are canonicalized, sorted, and deduplicated before upload.

Matched workflows are compiled and uploaded atomically. Workflow groups use the workflow's name, falling back to its repository path. Reusable workflows whose only trigger is workflow_call do not create groups, but remain available to matched callers. The upload fails if a selector matches no tracked files, the selection contains no directly runnable workflows, or a workflow's trigger cannot be represented safely.

The supported top-level triggers map to group if expressions as follows:

GitHub Actions trigger Buildkite condition
push GitHub push webhook, including supported branch and tag filters
pull_request GitHub pull_request webhook, including base-branch and activity-type filters
workflow_dispatch Buildkite UI or API build
schedule Buildkite scheduled build

The effective event selects which workflow groups apply. Applicable workflows use only the matching event's condition; triggers for other events are not ORed into that group. Path filters and unsupported events or filters fail the upload rather than broadening when the workflow runs. GitHub and Buildkite use different path-diff semantics, so paths and paths-ignore are not translated.

These conditions select groups in a Buildkite build; they do not configure which GitHub webhooks create builds. Configure the corresponding webhook events in the Buildkite pipeline settings. Buildkite also retains ownership of cron schedules: every workflow with on.schedule is eligible during any Buildkite scheduled build.

Migrate incrementally

Imported workflow jobs and native Buildkite Pipelines steps can run in the same build. In this example, the native Deploy step waits for all imported test jobs to finish:

steps:
  - label: ":github: Tests"
    key: "github-actions-tests"
    plugins:
      - github-actions#latest:
          workflow: .github/workflows/ci.yml

  - label: "Deploy"
    key: "deploy"
    depends_on: "github-actions-tests"
    command: ".buildkite/deploy.sh"

As you replace jobs with native Buildkite Pipelines steps, the remaining supported workflow jobs can keep running through the plugin.

How the plugin works

The plugin and the buildkite-gha runtime work together to run the workflow:

  • The plugin uses an existing compatible mise, or installs a pinned verified copy, then asks mise to select and run the configured buildkite-gha release or source commit.
  • The hidden buildkite-gha plugin command reads the plugin configuration, checks that the workflow is supported, converts its jobs into Buildkite Pipelines command jobs, uploads them, and runs each generated job.

You do not need to install mise or buildkite-gha. Mise selects, verifies, and caches the release asset matching the importer host: Linux amd64 or Darwin arm64. The importer then verifies and stages the missing same-release counterpart runtime only when a generated job needs it.

Generated jobs that use JavaScript actions also prepare a verified, managed mise installation for the supported Node.js versions. Shell-only generated jobs and jobs that use only native adapters or Docker do not install mise.

The importer passes the runtime and compiled execution plans to generated jobs using Buildkite Pipelines artifacts. Each job verifies these files before using them. Buildkite Pipelines handles scheduling, logs, retries, cancellation, and build status.

Requirements

The importer step needs:

  • A Linux amd64 or Darwin arm64 agent, selected by the importer's own agents configuration. Generated-job runners mappings do not schedule this step.
  • Buildkite agent v3.34.1 or later in the v3 release series. Agent v4 is not supported because the runtime uses the --reject-secrets option, which Agent v4 does not provide.
  • Bash, curl, tar, mktemp, cp, and either sha256sum on Linux or shasum on macOS, as listed in plugin.yml. The download tools are used only when a compatible mise is not already on PATH.
  • Git when BUILDKITE_COMMIT is not already a full commit SHA.
  • Outbound HTTPS access to public GitHub release and action sources.

Generated jobs need Buildkite agent v3.130.0 or later and an execution environment matching their runner mapping. Linux x86-64 jobs can run on Buildkite hosted agents, the Agent Stack for Kubernetes, or other self-hosted agents that provide the workflow's tools. Supported macOS labels require a native Darwin arm64 queue. The runtime tells the agent to skip its usual repository checkout so that it can prepare the workflow workspace instead.

Depending on the workflow, generated-job hosts also need:

  • git available on PATH for actions/checkout.
  • Docker and Docker Buildx available on PATH for Dockerfile actions. The default Buildx builder must use the local docker driver.

Map runner labels to queues and images

Use runners to map an exact GitHub runs-on label to a Buildkite queue. Configured ubuntu-latest and ubuntu-24.04 profiles use the Noble hosted-toolchains image by default; ubuntu-22.04 uses Jammy. A Linux mapping may override that default with another digest-pinned image:

steps:
  - label: ":github: GitHub Actions"
    key: "github-actions"
    agents:
      queue: importer-macos-arm64
    plugins:
      - github-actions#latest:
          workflow: .github/workflows/ci.yml
          runners:
            - runs-on: ubuntu-latest
              queue: hosted
              image: buildkite.namespace-images.com/agent-base@sha256:62a45683afffaae9edfd669c16d2fee23b5a571679f31715e1063dada667ea24
            - runs-on: macos-14
              queue: macos-sonoma-arm64

The top-level agents.queue above schedules the importer on macOS arm64; it is independent of the queues under runners. runs-on is matched after static expressions and matrices are resolved. An explicit image applies only to the matching Linux label, must be an immutable @sha256: reference, and replaces the label's hosted-toolchains default. macOS mappings select a native queue and cannot specify an image. Duplicate labels, unsupported labels, malformed queues or images, and conflicting multi-label targets fail admission. Unmapped supported Linux labels retain default Buildkite agent targeting without an image; unmapped macOS labels fail rather than falling back to a Linux queue.

Warning

Generated jobs may execute untrusted workflow or action code. The selected queue must provide whole-job isolation, no ambient protected credentials, and a clean machine for each untrusted job. Persistent self-hosted agents can expose host resources and state left by earlier jobs.

Configure generated-job runtimes

Generated jobs need network access for anything they download at runtime:

  • Jobs that use public GitHub Actions need outbound HTTPS access to codeload.github.com, where the runtime downloads each action's source archive.
  • Jobs that use JavaScript actions need outbound HTTPS access to the managed Node.js and mise downloads. Actions that declare node16 run on managed Node 16.20.2 and produce a deprecation warning. Actions that declare node20 or node24 run on managed Node 24.18.0. Managed Node binaries require glibc 2.28 or newer. Shell-only workflows do not have this glibc requirement.

When resolving a mutable tag or branch for a public action, the importer uses a dedicated action-source token only for public GitHub metadata requests and reuses it across the selected workflows and nested composite actions. If it cannot obtain the token, it reports a warning and retries anonymously. A lowercase, full 40-character commit SHA does not require an API request. Credential-repository metadata requests and all action archive downloads from codeload.github.com remain anonymous.

Configured Linux profiles select an immutable hosted-toolchains image and enable its /opt/hostedtoolcache. An explicit runners[].image override must provide the same tool-cache path and is supported only when the matching jobs run on Buildkite hosted agents or Agent Stack for Kubernetes controller v0.30.0 or later. Do not configure Linux profiles for other self-hosted environments that cannot provision the generated job image. macOS profiles never select an image.

Configure triggers and GitHub context

Buildkite Pipelines controls when builds run. Configure branch, tag, schedule, and pull request triggers in Buildkite. The workflows' on keys select groups after a build exists; they do not create Buildkite Pipelines triggers.

For manual and scheduled builds, the plugin finds the exact commit from the checked-out repository when BUILDKITE_COMMIT does not already contain a full commit SHA.

Pull request builds receive pull_request context. Branch and tag builds receive push context. Buildkite scheduled builds select workflows with a schedule trigger, while manual UI or API builds select workflows with workflow_dispatch; dispatch inputs are not available.

Configure checkout and credentials

Supported, audited actions/checkout revisions can check out the exact event repository and commit from github.com. Checkout runs anonymously when repository-provider credentials are not enabled. Private checkout uses Buildkite repository-provider Git credentials when they are enabled and authorized for the job.

Checkout credentials do not populate GITHUB_TOKEN or github.token, enable private actions, or allow alternate repositories or refs. A workflow can receive a temporary GitHub token only when it makes a supported static token reference and both the Buildkite organization feature and the pipeline's default-off token setting are enabled. When the workflow omits permissions, the runtime requests exactly contents: read without inheriting GitHub repository or organization defaults. Write access requires an explicit top-level permissions map; an empty map or scopes set to none mint no token. The compatibility guide describes the complete credential boundary.

Warning

Temporary token issuance verifies the workflow and build provenance. Job-level permissions and reusable-workflow jobs are rejected, pull request ancestry is capped at contents: read, and merge queue ancestry is denied. Review the workflow-token restrictions before enabling the service.

Cache mise installations

On Buildkite hosted agents, attach a mise data cache to avoid reinstalling mise and buildkite-gha:

steps:
  - label: ":github: GitHub Actions"
    key: "github-actions"
    cache: "/cache/bkcache/mise"
    plugins:
      - github-actions#latest:
          workflow: .github/workflows/ci.yml

Without this volume, mise uses the agent or user data directory. Treat the mise data directory as executable state: do not share it with untrusted jobs or principals that can modify it. This importer cache is separate from generated-job runtime caching and the workflow's actions/cache behavior.

Supported functionality and limitations

The public preview supports an evolving subset of GitHub Actions. Common supported features include:

  • Linux x86-64 jobs using ubuntu-latest, ubuntu-24.04, or ubuntu-22.04. These labels identify a compatible runner but do not provide the same tools or image layout as a GitHub-hosted runner.
  • Native macOS Apple Silicon jobs using macos-latest, macos-15, or macos-14 when each used label has an explicit Darwin arm64 queue mapping.
  • Bash and sh run steps.
  • Static job dependencies and matrices, including include and exclude, up to 256 expanded instances per job.
  • Supported job and step conditions, outputs, timeouts, literal job-level continue-on-error, and step-level continue-on-error behavior. Job-level expressions are not supported.
  • Workspace-confined hashFiles() in supported step conditions and step runtime fields, with bounded patterns, matches, and input size.
  • Public JavaScript, composite, local, and compiler-verified Dockerfile actions.
  • Local reusable workflows with statically resolvable inputs.
  • Supported, audited revisions of actions/checkout, actions/upload-artifact, actions/download-artifact, and actions/cache.

Important limitations include:

  • General workflow secrets, ambient GITHUB_TOKEN, private actions, private reusable workflows, alternate-repository or alternate-ref checkout, and GitHub-compatible OIDC are not available.
  • Windows and Linux arm64 jobs are not supported.
  • macOS does not provide GitHub-hosted image or Xcode inventory parity. Docker actions, job containers, and service containers are not supported on macOS.
  • Job and service containers are not available through the production plugin path.
  • Dynamic matrices and remote reusable workflows are not supported.
  • The runtime accepts strategy.fail-fast but does not enforce it, so a failed matrix job does not cancel the other matrix jobs.
  • The complete github.event payload and GitHub-specific event behavior are not available at runtime.
  • Unaudited revisions of actions with native support are rejected.

If a feature is not listed in the buildkite-gha v0.12.1 compatibility guide, treat it as unsupported.

Warning

All steps in an imported job share a workspace, environment changes, processes, and action lifecycle. Docker actions provide packaging, not a security boundary. Review the buildkite-gha v0.12.1 security model before running untrusted workflow code.

Develop the plugin

See the development guide for local tests, CI smoke tests, and release instructions.

License

This project uses the MIT License. See LICENSE.

About

Run GitHub Actions workflows as native Buildkite builds

Topics

Resources

Stars

4 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages