diff --git a/lib/googleauth/external_account/pluggable_credentials.rb b/lib/googleauth/external_account/pluggable_credentials.rb index 82db663a..545ecc0f 100644 --- a/lib/googleauth/external_account/pluggable_credentials.rb +++ b/lib/googleauth/external_account/pluggable_credentials.rb @@ -13,6 +13,7 @@ # limitations under the License. require "open3" +require "timeout" require "time" require "json" require "googleauth/errors" @@ -88,7 +89,7 @@ def retrieve_subject_token! # environment variable injection env = inject_environment_variables output = subprocess_with_timeout env, @credential_source_executable_command, - @credential_source_executable_timeout_millis + (@credential_source_executable_timeout_millis / 1000.0) response = JSON.parse output, symbolize_names: true parse_subject_token response end diff --git a/spec/googleauth/external_account/pluggable_credentials_spec.rb b/spec/googleauth/external_account/pluggable_credentials_spec.rb index 3c242558..1107df2c 100644 --- a/spec/googleauth/external_account/pluggable_credentials_spec.rb +++ b/spec/googleauth/external_account/pluggable_credentials_spec.rb @@ -531,4 +531,46 @@ end end end + + describe "test retrieve subject token executable timeout" do + let(:command) { "fake_cmd" } + let(:options) do + { + audience: AUDIENCE, + subject_token_type: SUBJECT_TOKEN_TYPE, + token_url: TOKEN_URL, + credential_source: { + executable: { + command: command, + timeout_millis: 12_000 + } + } + } + end + + before :example do + ENV[Google::Auth::ExternalAccount::PluggableAuthCredentials::ENABLE_PLUGGABLE_ENV] = "1" + end + + it "converts configured timeout_millis to seconds for Timeout.timeout" do + expect(Timeout).to receive(:timeout).with(12.0).and_yield + allow(Open3).to receive(:capture3).and_return( + [JSON.generate(EXECUTABLE_SUCCESSFUL_OIDC_RESPONSE_ID_TOKEN), "", double("Process::Status", exitstatus: 0, success?: true)] + ) + + credentials = PluggableAuthCredentials.new options + expect(credentials.retrieve_subject_token!).to eq(EXECUTABLE_OIDC_TOKEN) + end + + it "converts default timeout_millis to seconds for Timeout.timeout when unspecified" do + options[:credential_source][:executable].delete :timeout_millis + expect(Timeout).to receive(:timeout).with(30.0).and_yield + allow(Open3).to receive(:capture3).and_return( + [JSON.generate(EXECUTABLE_SUCCESSFUL_OIDC_RESPONSE_ID_TOKEN), "", double("Process::Status", exitstatus: 0, success?: true)] + ) + + credentials = PluggableAuthCredentials.new options + expect(credentials.retrieve_subject_token!).to eq(EXECUTABLE_OIDC_TOKEN) + end + end end