diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 621ffc1..74af670 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -22,12 +22,10 @@ The Buildkite pipeline's required released-default smoke test: 3. Uploads `.github/workflows/plugin-smoke.yml` 4. Checks out the same commit in a generated hosted job and verifies the release defaults -This lane requires Linux x86-64 Hosted Agents, but no configured secrets, provider tokens, or cache service. Cache integration is tested separately in the `buildkite/buildkite-gha` demo pipeline. +This lane requires Linux x86-64 Hosted Agents, but no configured secrets or cache service. Cache integration is tested separately in the `buildkite/buildkite-gha` demo pipeline. Set `GITHUB_ACTIONS_SOURCE_REF` to `latest` or a full lowercase 40-character CLI commit on a manually created Buildkite build to run the optional source smoke instead. This lane uses the repository's `mise.toml` to install pinned mise 2026.5.12 and Go 1.26.5, pins the plugin to the build's exact commit, and exercises `buildkite-gha-source-ref` end to end. Ordinary builds continue to prove the released archive and installation path. -The smoke tests leave `private-checkout` unset so they remain service-free. Bats covers its argument wiring; the `buildkite/buildkite-gha` repository tests its runtime behavior with GHAC minting. - ## Release Plugin releases are Git tags and contain no generated assets. Before creating a `v0.x.y` tag, verify that: diff --git a/README.md b/README.md index 4b71d0b..01c39f8 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,11 @@ The importer step must have a `key`. Each workflow job and static matrix entry b | `workflow` | Yes | — | Path to the GitHub Actions workflow. | | `version` | No | `0.6.0` | Exact pre-1.0 `buildkite-gha` CLI version. | | `buildkite-gha-source-ref` | No | — | `latest` or a full lowercase commit for unreleased CLI testing. | -| `private-checkout` | No | `false` | Enable read-only checkout of the pipeline's private GitHub repository. | The plugin release (`github-actions#v0.6.0`) and CLI `version` are independent. Set `version` only when you need a CLI release other than the default. `version` and `buildkite-gha-source-ref` are mutually exclusive. +Repository checkout behavior is owned by `buildkite-gha` and Buildkite's repository-provider backend. Workflow permissions remain separate: checkout credentials do not populate `GITHUB_TOKEN` or `github.token`, enable private actions, or permit alternate repositories or refs. + ## Compatibility `buildkite-gha` intentionally supports a subset of GitHub Actions. For the default CLI, see the [`v0.6.0` compatibility guide](https://github.com/buildkite/buildkite-gha/blob/v0.6.0/docs/compatibility.md) before migrating a workflow. Unsupported behavior fails explicitly rather than silently choosing a substitute. @@ -41,24 +42,6 @@ Configure branch, tag, schedule, and pull request triggers in Buildkite. The wor Released mode downloads the selected public `buildkite/buildkite-gha` release without a GitHub token and does not require importer-side mise. Downloads and cached copies are verified before execution. Generated jobs prepare mise only when their resolved action trees can execute JavaScript; shell-only, native-adapter-only, and Docker-only jobs skip that setup. -## Private repositories - -By default, generated `actions/checkout` steps perform a credential-free, shallow checkout, so the workflow repository must be public. Set `private-checkout` to give verified checkout jobs read-only access to the pipeline's exact GitHub repository: - -```yaml -steps: - - label: ":github: GitHub Actions" - key: "github-actions" - plugins: - - github-actions#v0.6.0: - workflow: .github/workflows/ci.yml - private-checkout: true -``` - -This requires Buildkite's job-bound GitHub scoped access-token service. The CLI requests fixed `contents:read` authority, and the service independently requires the event repository to match the pipeline's GitHub repository. The credential is redacted before use and supplied only to Git through a one-shot askpass pipe. - -This option does not populate `GITHUB_TOKEN` or `github.token`, grant write access, enable private actions, or permit alternate repositories or refs. - ## Caching On hosted agents, attach the plugin's cache volume to speed up the importer: diff --git a/hooks/command b/hooks/command index 20ffb49..8e3c8f7 100755 --- a/hooks/command +++ b/hooks/command @@ -10,7 +10,6 @@ PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" workflow="${BUILDKITE_PLUGIN_GITHUB_ACTIONS_WORKFLOW:-${BUILDKITE_PLUGIN__WORKFLOW:-}}" configured_version="${BUILDKITE_PLUGIN_GITHUB_ACTIONS_VERSION:-${BUILDKITE_PLUGIN__VERSION:-}}" source_ref="${BUILDKITE_PLUGIN_GITHUB_ACTIONS_BUILDKITE_GHA_SOURCE_REF:-${BUILDKITE_PLUGIN__BUILDKITE_GHA_SOURCE_REF:-}}" -private_checkout="${BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT:-${BUILDKITE_PLUGIN__PRIVATE_CHECKOUT:-false}}" if [[ -z "$workflow" ]]; then echo "github-actions plugin: workflow is required" >&2 @@ -20,12 +19,6 @@ if [[ "$workflow" == -* || "$workflow" == *$'\n'* || "$workflow" == *$'\r'* ]]; echo "github-actions plugin: workflow must be a path, not an option or multiline value" >&2 exit 1 fi -# An unrecognised value must not silently select either behaviour: treating it as -# false hides the opt-in, and treating it as true would widen authority. -case "$private_checkout" in - true|false) ;; - *) echo "github-actions plugin: private-checkout must be true or false" >&2; exit 1 ;; -esac if [[ -n "$source_ref" && -n "$configured_version" ]]; then echo "github-actions plugin: version and buildkite-gha-source-ref are mutually exclusive" >&2 exit 1 @@ -55,11 +48,7 @@ fi echo "~~~ :github: Prepare workflow" -upload_args=(upload) -if [[ "$private_checkout" == true ]]; then - upload_args+=(--private-checkout) -fi -upload_args+=(--runtime-queue hosted "$workflow") +upload_args=(upload "$workflow") if [[ -n "$source_ref" ]]; then resolved_source_ref="$source_ref" diff --git a/plugin.yml b/plugin.yml index 32fcb2f..7deb4a3 100644 --- a/plugin.yml +++ b/plugin.yml @@ -27,10 +27,6 @@ configuration: type: string pattern: "^(latest|[0-9a-f]{40})$" description: Build buildkite-gha from the latest main commit or an exact full commit using config-free mise and pinned Go. Mutually exclusive with version. - private-checkout: - type: boolean - default: false - description: Opt verified checkout jobs into read-only authority for the pipeline's exact GitHub repository. required: - workflow additionalProperties: false diff --git a/tests/command.bats b/tests/command.bats index 9f01161..adfe234 100755 --- a/tests/command.bats +++ b/tests/command.bats @@ -10,6 +10,7 @@ setup() { export BUILDKITE_COMMIT=1111111111111111111111111111111111111111 unset BUILDKITE_PLUGIN_GITHUB_ACTIONS_VERSION BUILDKITE_PLUGIN__VERSION unset BUILDKITE_PLUGIN_GITHUB_ACTIONS_BUILDKITE_GHA_SOURCE_REF BUILDKITE_PLUGIN__BUILDKITE_GHA_SOURCE_REF + unset BUILDKITE_USE_REPOSITORY_PROVIDER_GIT_CREDENTIALS BUILDKITE_USE_GITHUB_APP_GIT_CREDENTIALS export MOCK_LOG="$TMP/mock.log" mkdir -p "$TMP/bin" "$TMP/payload" : > "$MOCK_LOG" @@ -94,7 +95,9 @@ teardown() { rm -rf "$TMP"; } mkdir -p "$TMPDIR" run "$REPO/hooks/command" [ "$status" -eq 0 ] || { echo "$output"; false; } - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" + grep -Fx 'upload .github/workflows/ci.yml' "$MOCK_LOG" + ! grep -q -- '--runtime-queue' "$MOCK_LOG" + ! grep -q -- '--private-checkout' "$MOCK_LOG" grep -Fx 'https://github.com/buildkite/buildkite-gha/releases/download/v0.6.0/buildkite-gha_Linux_x86_64.tar.gz' "$MOCK_LOG" grep -Fx 'https://github.com/buildkite/buildkite-gha/releases/download/v0.6.0/checksums.txt' "$MOCK_LOG" grep -Fx "path=$EXPECTED_PATH" "$MOCK_LOG" @@ -131,41 +134,18 @@ teardown() { rm -rf "$TMP"; } ! grep -q '^upload ' "$MOCK_LOG" } -@test "opts into private checkout only when explicitly enabled" { - export BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT=true - run "$REPO/hooks/command" - [ "$status" -eq 0 ] || { echo "$output"; false; } - grep -Fx 'upload --private-checkout --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" - - : > "$MOCK_LOG" - export BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT=false - run "$REPO/hooks/command" - [ "$status" -eq 0 ] || { echo "$output"; false; } - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" - - : > "$MOCK_LOG" - unset BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT - run "$REPO/hooks/command" - [ "$status" -eq 0 ] || { echo "$output"; false; } - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" - - # An empty value falls back to the unprivileged default, as `version` does. - : > "$MOCK_LOG" - export BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT= - run "$REPO/hooks/command" - [ "$status" -eq 0 ] || { echo "$output"; false; } - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" -} - -@test "rejects a non-boolean private-checkout without running importer" { - for value in yes 1 TRUE ' true' '--event-path'; do - : > "$MOCK_LOG" - export BUILDKITE_PLUGIN_GITHUB_ACTIONS_PRIVATE_CHECKOUT="$value" - run "$REPO/hooks/command" - [ "$status" -ne 0 ] || { echo "accepted '$value'"; false; } - [[ "$output" == *"private-checkout must be true or false"* ]] - run grep -q '^upload ' "$MOCK_LOG" - [ "$status" -eq 1 ] +@test "repository-provider credential signals do not alter the upload command" { + for signal in BUILDKITE_USE_REPOSITORY_PROVIDER_GIT_CREDENTIALS BUILDKITE_USE_GITHUB_APP_GIT_CREDENTIALS; do + for value in true false; do + : > "$MOCK_LOG" + export "$signal"="$value" + run "$REPO/hooks/command" + [ "$status" -eq 0 ] || { echo "$output"; false; } + grep -Fx 'upload .github/workflows/ci.yml' "$MOCK_LOG" + ! grep -q -- '--runtime-queue' "$MOCK_LOG" + ! grep -q -- '--private-checkout' "$MOCK_LOG" + done + unset "$signal" done } @@ -194,7 +174,9 @@ teardown() { rm -rf "$TMP"; } [ "$status" -eq 0 ] || { echo "$output"; false; } [[ "$output" == *"buildkite-gha source latest resolved to $MOCK_SOURCE_SHA"* ]] grep -Fx 'git:ls-remote --exit-code --refs https://github.com/buildkite/buildkite-gha.git refs/heads/main' "$MOCK_LOG" - grep -Fx "mise:--no-config x go@1.26.5 -- env CGO_ENABLED=0 GOTOOLCHAIN=local go run -trimpath github.com/buildkite/buildkite-gha/cmd/buildkite-gha@$MOCK_SOURCE_SHA upload --runtime-queue hosted .github/workflows/ci.yml" "$MOCK_LOG" + grep -Fx "mise:--no-config x go@1.26.5 -- env CGO_ENABLED=0 GOTOOLCHAIN=local go run -trimpath github.com/buildkite/buildkite-gha/cmd/buildkite-gha@$MOCK_SOURCE_SHA upload .github/workflows/ci.yml" "$MOCK_LOG" + ! grep -q -- '--runtime-queue' "$MOCK_LOG" + ! grep -q -- '--private-checkout' "$MOCK_LOG" grep -Fx 'source-env:MISE_YES=1' "$MOCK_LOG" run grep -F 'releases/download' "$MOCK_LOG" [ "$status" -eq 1 ] @@ -206,7 +188,9 @@ teardown() { rm -rf "$TMP"; } run "$REPO/hooks/command" [ "$status" -eq 0 ] || { echo "$output"; false; } ! grep -q '^git:' "$MOCK_LOG" - grep -Fx 'mise:--no-config x go@1.26.5 -- env CGO_ENABLED=0 GOTOOLCHAIN=local go run -trimpath github.com/buildkite/buildkite-gha/cmd/buildkite-gha@abcdef0123456789abcdef0123456789abcdef01 upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" + grep -Fx 'mise:--no-config x go@1.26.5 -- env CGO_ENABLED=0 GOTOOLCHAIN=local go run -trimpath github.com/buildkite/buildkite-gha/cmd/buildkite-gha@abcdef0123456789abcdef0123456789abcdef01 upload .github/workflows/ci.yml' "$MOCK_LOG" + ! grep -q -- '--runtime-queue' "$MOCK_LOG" + ! grep -q -- '--private-checkout' "$MOCK_LOG" } @test "rejects invalid or ambiguous source configuration without running importer" { @@ -362,7 +346,7 @@ EOF run "$REPO/hooks/command" [ "$status" -eq 0 ] || { echo "$output"; false; } [[ "$output" == *"cache '$BUILDKITE_GITHUB_ACTIONS_PLUGIN_CACHE_ROOT' is unavailable; using a temporary cache"* ]] - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" + grep -Fx 'upload .github/workflows/ci.yml' "$MOCK_LOG" } @test "continues when the verified CLI archive cannot be cached" { @@ -379,7 +363,7 @@ EOF run "$REPO/hooks/command" [ "$status" -eq 0 ] || { echo "$output"; false; } [[ "$output" == *"continuing without caching"* ]] - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" + grep -Fx 'upload .github/workflows/ci.yml' "$MOCK_LOG" [ ! -e "$BUILDKITE_GITHUB_ACTIONS_PLUGIN_CACHE_ROOT/v0.6.0/Linux_x86_64" ] } @@ -400,7 +384,7 @@ EOF run "$REPO/hooks/command" [ "$status" -eq 0 ] || { echo "$output"; false; } grep -Fx 'https://github.com/buildkite/buildkite-gha/releases/download/v0.6.0/buildkite-gha_Linux_x86_64.tar.gz' "$MOCK_LOG" - grep -Fx 'upload --runtime-queue hosted .github/workflows/ci.yml' "$MOCK_LOG" + grep -Fx 'upload .github/workflows/ci.yml' "$MOCK_LOG" } @test "concurrent installs converge on one valid cache" { @@ -414,7 +398,7 @@ EOF [ -f "$cached_archive" ] expected="$(awk '$2 == "buildkite-gha_Linux_x86_64.tar.gz" { print $1 }' "$TMP/checksums.txt")" [ "$(/usr/bin/sha256sum "$cached_archive" | awk '{ print $1 }')" = "$expected" ] - [ "$(grep -c '^upload --runtime-queue hosted ' "$MOCK_LOG")" -eq 2 ] + [ "$(grep -c '^upload .github/workflows/ci.yml$' "$MOCK_LOG")" -eq 2 ] } @test "propagates importer failure and never runs importer after install failure" {