diff --git a/test/factories/oidc/provider.rb b/test/factories/oidc/provider.rb index f745ff2cc63..6f839c97e9a 100644 --- a/test/factories/oidc/provider.rb +++ b/test/factories/oidc/provider.rb @@ -63,5 +63,56 @@ transient do pkey { OpenSSL::PKey::RSA.generate(2048) } end + + trait :buildkite do + issuer { "https://agent.buildkite.com" } + configuration do + { + issuer: issuer, + jwks_uri: "#{issuer}/.well-known/jwks", + id_token_signing_alg_values_supported: [ + "RS256" + ], + response_types_supported: [ + "id_token" + ], + scopes_supported: [ + "openid" + ], + subject_types_supported: %w[ + public + pairwise + ], + claims_supported: %w[ + sub + aud + exp + iat + iss + nbf + jti + organization_id + organization_slug + pipeline_id + pipeline_slug + build_number + build_branch + build_tag + build_commit + build_source + step_key + job_id + agent_id + cluster_id + cluster_name + queue_id + queue_key + runner_environment + ] + } + end + end + + factory :oidc_provider_buildkite, traits: [:buildkite] end end diff --git a/test/integration/api/v1/oidc/api_key_roles_test.rb b/test/integration/api/v1/oidc/api_key_roles_test.rb index b2f9a08e2b5..861477c16ab 100644 --- a/test/integration/api/v1/oidc/api_key_roles_test.rb +++ b/test/integration/api/v1/oidc/api_key_roles_test.rb @@ -383,5 +383,70 @@ def jwt(claims = @claims, key: @pkey) ) end end + + context "with a Buildkite OIDC token" do + setup do + @role = create(:oidc_api_key_role, provider: build(:oidc_provider_buildkite, pkey: @pkey)) + @user = @role.user + + @claims = { + "aud" => "rubygems.org", + "exp" => 1_680_020_837, + "iat" => 1_680_020_537, + "iss" => "https://agent.buildkite.com", + "jti" => "0194b014-8517-7cef-b232-76a827315f08", + "nbf" => 1_680_019_937, + "sub" => "organization:example-org:pipeline:example-pipeline:ref:refs/heads/main:commit:b5ffe3aeea51cec6c41aef16e45ee6bce47d8810:step:", + "organization_slug" => "example-org", + "pipeline_slug" => "example-pipeline", + "build_number" => 5, + "build_branch" => "main", + "build_tag" => nil, + "build_commit" => "b5ffe3aeea51cec6c41aef16e45ee6bce47d8810", + "step_key" => nil, + "job_id" => "01945ecf-80f0-41e8-9b83-a2970a9305a1", + "agent_id" => "01945ecf-8bcf-40a6-9d70-a765db9a0928", + "build_source" => "ui", + "runner_environment" => "buildkite-hosted" + } + + travel_to Time.zone.at(1_680_020_830) # after the JWT iat, before the exp + end + + context "with matching conditions" do + should "return API key" do + # remove the Github Actions shaped condition in the default fixture + @role.access_policy.statements.first.conditions.clear + @role.access_policy.statements.first.conditions << OIDC::AccessPolicy::Statement::Condition.new( + operator: "string_equals", + claim: "organization_slug", + value: "example-org" + ) + @role.save! + + post assume_role_api_v1_oidc_api_key_role_path(@role.token), + params: { + jwt: jwt.to_s + }, + headers: {} + + assert_response :created + + resp = response.parsed_body + + assert_match(/^rubygems_/, resp["rubygems_api_key"]) + assert_equal_hash( + { "rubygems_api_key" => resp["rubygems_api_key"], + "name" => "#{@role.name}-0194b014-8517-7cef-b232-76a827315f08", + "scopes" => ["push_rubygem"], + "expires_at" => 30.minutes.from_now }, + resp + ) + hashed_key = @user.api_keys.sole.hashed_key + + assert_equal hashed_key, Digest::SHA256.hexdigest(resp["rubygems_api_key"]) + end + end + end end end