diff --git a/.github/workflows/bash-checks.yml b/.github/workflows/bash-checks.yml index 15094a5..e2c14db 100644 --- a/.github/workflows/bash-checks.yml +++ b/.github/workflows/bash-checks.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v4 - name: Lint - run: docker-compose run --rm lint + run: docker compose run --rm lint - name: Test - run: docker-compose run --rm tests + run: docker compose run --rm tests diff --git a/README.md b/README.md index ce7a611..73f7539 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# github-app-auth-buildkite-plugin +# chinmina-git-credentials-buildkite-plugin Combines a Git credential helper with a [`chinmina-bridge` helper agent][chinmina-bridge] to allow Buildkite agents securely authorize Github @@ -11,13 +11,14 @@ The credential helper calls `chinmina-bridge` when credentials for a GitHub repository are requested, supplying the result to Git in its expected format. > [!IMPORTANT] +> Refer to the [Chinmina documentation][chinmina-integration] for detailed +> information about configuring and using this plugin effectively. > -> In order for this plugin to work for a whole pipeline, it must be enabled on -> every step. **This includes any steps configured in the [pipeline -> configuration](https://buildkite.com/docs/pipelines/defining-steps).** -> -> Alternatively, the plugin may be enabled globally by the agent: see -> instructions below. +> While this plugin can be used as a regular Buildkite plugin, it must be +> enabled on every step. **This includes any steps configured in the [pipeline +> configuration](https://buildkite.com/docs/pipelines/defining-steps).** This is +> difficult to implement and maintain; hence the [strategy +> suggested][chinmina-integration]. ## Example @@ -27,14 +28,14 @@ Add the following to your `pipeline.yml`: steps: - command: ls plugins: - - jamestelfer/github-app-auth#v1.0.2: - vendor-url: "https://chinmina-bridge-url" - audience: "github-app-auth:your-github-organization" + - chinmina/chinmina-git-credentials#v1.1.0: + chinmina-url: "https://chinmina-bridge-url" + audience: "chinmina:your-github-organization" ``` ## Configuration -### `vendor-url` (Required, string) +### `chinmina-url` (Required, string) The URL of the [`chinmina-bridge`][chinmina-bridge] helper agent that vends a token for a pipeline. This is a separate HTTP service that must accessible to @@ -42,84 +43,39 @@ your Buildkite agents. ### `audience` (string) -**Default:** `github-app-auth:default` +**Default:** `chinmina:default` The value of the `aud` claim of the OIDC JWT that will be sent to [`chinmina-bridge`][chinmina-bridge]. This must correlate with the value configured in the `chinmina-bridge` settings. -A recommendation: `github-app-auth:your-github-organization`. This is specific +A recommendation: `chinmina:your-github-organization`. This is specific to the purpose of the token, and also scoped to the GitHub organization that tokens will be vended for. `chinmina-bridge`'s GitHub app is configured for a particular GitHub organization/user, so if you have multiple organizations, multiple agents will need to be running. -## Global agent configuration - -In order to enable the plugin automatically, consider changing the Buildkite -agent configuration such that the plugin is installed and enabled by default. - -> [!NOTE] -> -> Credential helpers are only used by Git for HTTP, not for SSH. This -> configuration does not change behaviour for SSH connections. - -One way to do this is to clone the plugin when the agent is bootstrapped, then -call the plugin's environment hook directly from the agent's environment hook. - -The two scripts below accomplish this: - -### Agent `bootstrap` hook additions - -```bash -#!/usr/bin/env bash - -echo "installing Github credential plugin" - -plugin_repo="https://github.com/jamestelfer/github-app-auth-buildkite-plugin.git" -plugin_version="v1.0.1" -plugin_dir="/buildkite/plugins/github-app-auth-buildkite-plugin" - -[[ -d "${plugin_dir}" ]] && rm -rf "${plugin_dir}" - -GIT_CONFIG_COUNT=1 \ -GIT_CONFIG_KEY_0=advice.detachedHead \ -GIT_CONFIG_VALUE_0=false \ - git clone --depth 1 --single-branch --no-tags \ - --branch "${plugin_version}" -- \ - "${plugin_repo}" "${plugin_dir}" -``` - -### Agent `environment` hook additions - -```bash -# -# executing this script from your infrastructure's environment agent hook will -# configure Github App Auth for every build -# -# Changing the parameters supplied will be necessary to ensure that agents can -# connect to the service and include the correct audience. -# -BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL="https://chinmina-bridge-url" \ -BUILDKITE_PLUGIN_GITHUB_APP_AUTH_AUDIENCE="github-app-auth:your-github-org" \ - source /buildkite/plugins/github-app-auth-buildkite-plugin/hooks/environment -``` - ## Developing -To run the tests: +Run tests and plugin linting locally using `docker compose`: ```shell +# Buildkite plugin linter +docker-compose run --rm lint + +# Bash tests docker-compose run --rm tests ``` ## Contributing +Contributions are welcome! Raise a PR, and include tests with your changes. + 1. Fork the repo 2. Make the changes -3. Run the tests +3. Run the tests and linter 4. Commit and push your changes 5. Send a pull request - -[chinmina-bridge]: https://github.com/jamestelfer/chinmina-bridge +[chinmina-bridge]: https://chinmina.github.io/introduction/ +[chinmina-integration]: https://chinmina.github.io/guides/buildkite-integration/ diff --git a/docker-compose.yml b/docker-compose.yml index 18aa02a..2389d33 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,7 +1,7 @@ services: lint: image: buildkite/plugin-linter - command: ['--id', 'jamestelfer/github-app-auth'] + command: ['--id', 'chinmina/chinmina-git-credentials'] volumes: - ".:/plugin:ro" diff --git a/hooks/environment b/hooks/environment index 6aad1bb..88ca01a 100755 --- a/hooks/environment +++ b/hooks/environment @@ -1,10 +1,38 @@ #!/bin/bash set -euo pipefail -vendor_url="${BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL:?vendor-url property required}" -audience="${BUILDKITE_PLUGIN_GITHUB_APP_AUTH_AUDIENCE:-github-app-auth:default}" +original_prefix="BUILDKITE_PLUGIN_GITHUB_APP_AUTH_" +prefix="BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_" + +get_parameter() { + local key="$1" + local name="${prefix}${key}" + local value="${!name:-}" + + if [ -z "$value" ]; then + name="${original_prefix}${key}" + value="${!name:-}" + fi + echo "${value}" +} + +chinmina_url="$(get_parameter "CHINMINA_URL")" +vendor_url_compat="$(get_parameter "VENDOR_URL")" +audience="$(get_parameter "AUDIENCE")" + +# allow the old name of the parameter to be used +chinmina_url="${chinmina_url:-$vendor_url_compat}" + +if [ -z "$chinmina_url" ]; then + echo "~~~ :error: Missing required parameter chinmina-url" + exit 1 +fi + +if [ -z "$audience" ]; then + audience="chinmina:default" +fi -echo "~~~ :git: :github: Configuring git to authenticate via the vendor agent" +echo "~~~ :git: :github: Configuring Git to authenticate via Chinmina" plugin_root="$(cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd)" @@ -28,4 +56,4 @@ git_config_add() { } git_config_add "credential.https://github.com.usehttppath" "true" -git_config_add "credential.https://github.com.helper" "${plugin_root}/credential-helper/buildkite-connector-credential-helper ${vendor_url} ${audience}" +git_config_add "credential.https://github.com.helper" "${plugin_root}/credential-helper/buildkite-connector-credential-helper ${chinmina_url} ${audience}" diff --git a/plugin.yml b/plugin.yml index 0528302..a736fc5 100644 --- a/plugin.yml +++ b/plugin.yml @@ -5,14 +5,17 @@ description: | The helper agent (separate) is accessed via HTTP, using the Buildkite Agent OIDC token as its authorization. -author: https://github.com/jamestelfer +author: https://github.com/chinmina requirements: [] configuration: properties: - vendor-url: + chinmina-url: type: string - description: The URL of the helper agent that vends a token for a pipeline. + description: The URL of the Chinmina Bridge agent that creates a token for a pipeline. audience: type: string - description: (Default `github-app-auth:default`.) The audience to use for the Buildkite OIDC JWT that is sent to the vendor agent. Must match the setting in the vendor agent. + description: | + (Default `chinmina:default`.) The audience to use for the Buildkite OIDC + JWT that is sent to the vendor agent. Must match the setting in the + vendor agent. additionalProperties: false diff --git a/tests/environment.bats b/tests/environment.bats index 601d693..9f2edc1 100755 --- a/tests/environment.bats +++ b/tests/environment.bats @@ -26,8 +26,8 @@ setup() { } teardown() { - unset BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL - unset BUILDKITE_PLUGIN_GITHUB_APP_AUTH_AUDIENCE + unset BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_CHINMINA_URL + unset BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_AUDIENCE clear_git_config } @@ -40,11 +40,11 @@ run_environment() { run "$PWD/hooks/environment" assert_failure - assert_line --partial "vendor-url property required" + assert_line --partial "Missing required parameter chinmina-url" } @test "Adds config for default audience" { - export BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL=http://test-location + export BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_CHINMINA_URL=http://test-location run_environment "${PWD}/hooks/environment" @@ -53,10 +53,24 @@ run_environment() { assert_line "GIT_CONFIG_KEY_0=credential.https://github.com.usehttppath" assert_line "GIT_CONFIG_VALUE_0=true" assert_line "GIT_CONFIG_KEY_1=credential.https://github.com.helper" - assert_line --regexp "GIT_CONFIG_VALUE_1=/.*/credential-helper/buildkite-connector-credential-helper http://test-location github-app-auth:default" + assert_line --regexp "GIT_CONFIG_VALUE_1=/.*/credential-helper/buildkite-connector-credential-helper http://test-location chinmina:default" } @test "Adds config for non-default audience" { + export BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_CHINMINA_URL=http://test-location + export BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_AUDIENCE=test-audience + + run_environment "${PWD}/hooks/environment" + + assert_success + assert_line "GIT_CONFIG_COUNT=2" + assert_line "GIT_CONFIG_KEY_0=credential.https://github.com.usehttppath" + assert_line "GIT_CONFIG_VALUE_0=true" + assert_line "GIT_CONFIG_KEY_1=credential.https://github.com.helper" + assert_line --regexp "GIT_CONFIG_VALUE_1=/.*/credential-helper/buildkite-connector-credential-helper http://test-location test-audience" +} + +@test "Backwards compatible with old name" { export BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL=http://test-location export BUILDKITE_PLUGIN_GITHUB_APP_AUTH_AUDIENCE=test-audience @@ -71,7 +85,7 @@ run_environment() { } @test "Adds to existing configuration if present" { - export BUILDKITE_PLUGIN_GITHUB_APP_AUTH_VENDOR_URL=http://test-location + export BUILDKITE_PLUGIN_CHINMINA_GIT_CREDENTIALS_CHINMINA_URL=http://test-location # Setup existing config items. These must exist or Git will fail. export GIT_CONFIG_COUNT="3" @@ -91,5 +105,5 @@ run_environment() { assert_line "GIT_CONFIG_KEY_3=credential.https://github.com.usehttppath" assert_line "GIT_CONFIG_VALUE_3=true" assert_line "GIT_CONFIG_KEY_4=credential.https://github.com.helper" - assert_line --regexp "GIT_CONFIG_VALUE_4=/.*/credential-helper/buildkite-connector-credential-helper http://test-location github-app-auth:default" + assert_line --regexp "GIT_CONFIG_VALUE_4=/.*/credential-helper/buildkite-connector-credential-helper http://test-location chinmina:default" }