googleauth 0.8.1 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.kokoro/build.bat +9 -1
  3. data/.kokoro/continuous/linux.cfg +12 -2
  4. data/.kokoro/continuous/osx.cfg +5 -0
  5. data/.kokoro/continuous/post.cfg +30 -0
  6. data/.kokoro/continuous/windows.cfg +27 -1
  7. data/.kokoro/presubmit/linux.cfg +11 -1
  8. data/.kokoro/presubmit/osx.cfg +5 -0
  9. data/.kokoro/presubmit/windows.cfg +27 -1
  10. data/.kokoro/release.cfg +42 -1
  11. data/.kokoro/trampoline.bat +10 -0
  12. data/.repo-metadata.json +5 -0
  13. data/.rubocop.yml +10 -2
  14. data/CHANGELOG.md +34 -0
  15. data/Gemfile +8 -3
  16. data/README.md +7 -12
  17. data/Rakefile +48 -5
  18. data/googleauth.gemspec +6 -3
  19. data/integration/helper.rb +31 -0
  20. data/integration/id_tokens/key_source_test.rb +74 -0
  21. data/lib/googleauth.rb +1 -0
  22. data/lib/googleauth/application_default.rb +1 -1
  23. data/lib/googleauth/compute_engine.rb +19 -17
  24. data/lib/googleauth/credentials.rb +318 -63
  25. data/lib/googleauth/credentials_loader.rb +10 -8
  26. data/lib/googleauth/id_tokens.rb +233 -0
  27. data/lib/googleauth/id_tokens/errors.rb +71 -0
  28. data/lib/googleauth/id_tokens/key_sources.rb +394 -0
  29. data/lib/googleauth/id_tokens/verifier.rb +144 -0
  30. data/lib/googleauth/json_key_reader.rb +6 -2
  31. data/lib/googleauth/service_account.rb +16 -7
  32. data/lib/googleauth/signet.rb +8 -5
  33. data/lib/googleauth/user_authorizer.rb +6 -1
  34. data/lib/googleauth/user_refresh.rb +2 -2
  35. data/lib/googleauth/version.rb +1 -1
  36. data/lib/googleauth/web_user_authorizer.rb +13 -8
  37. data/rakelib/devsite_builder.rb +45 -0
  38. data/rakelib/link_checker.rb +64 -0
  39. data/rakelib/repo_metadata.rb +59 -0
  40. data/spec/googleauth/apply_auth_examples.rb +28 -5
  41. data/spec/googleauth/compute_engine_spec.rb +25 -13
  42. data/spec/googleauth/credentials_spec.rb +366 -161
  43. data/spec/googleauth/service_account_spec.rb +23 -16
  44. data/spec/googleauth/signet_spec.rb +46 -7
  45. data/spec/googleauth/user_authorizer_spec.rb +21 -1
  46. data/spec/googleauth/user_refresh_spec.rb +1 -1
  47. data/spec/googleauth/web_user_authorizer_spec.rb +6 -0
  48. data/test/helper.rb +33 -0
  49. data/test/id_tokens/key_sources_test.rb +240 -0
  50. data/test/id_tokens/verifier_test.rb +269 -0
  51. metadata +46 -12
  52. data/.kokoro/windows.sh +0 -4
@@ -0,0 +1,59 @@
1
+ require "json"
2
+
3
+ class RepoMetadata
4
+ attr_reader :data
5
+
6
+ def initialize data
7
+ @data = data
8
+ normalize_data!
9
+ end
10
+
11
+ def allowed_fields
12
+ [
13
+ "name", "version", "language", "distribution-name",
14
+ "product-page", "github-repository", "issue-tracker"
15
+ ]
16
+ end
17
+
18
+ def build output_directory
19
+ fields = @data.to_a.map { |kv| "--#{kv[0]} #{kv[1]}" }
20
+ Dir.chdir output_directory do
21
+ cmd "python3 -m docuploader create-metadata #{fields.join ' '}"
22
+ end
23
+ end
24
+
25
+ def normalize_data!
26
+ require_relative "../lib/googleauth/version.rb"
27
+
28
+ @data.delete_if { |k, _| !allowed_fields.include?(k) }
29
+ @data["version"] = "v#{Google::Auth::VERSION}"
30
+ end
31
+
32
+ def [] key
33
+ data[key]
34
+ end
35
+
36
+ def []= key, value
37
+ @data[key] = value
38
+ end
39
+
40
+ def cmd line
41
+ puts line
42
+ output = `#{line}`
43
+ puts output
44
+ output
45
+ end
46
+
47
+ def self.from_source source
48
+ if source.is_a? RepoMetadata
49
+ data = source.data
50
+ elsif source.is_a? Hash
51
+ data = source
52
+ elsif File.file? source
53
+ data = JSON.parse File.read(source)
54
+ else
55
+ raise "Source must be a path, hash, or RepoMetadata instance"
56
+ end
57
+ RepoMetadata.new data
58
+ end
59
+ end
@@ -45,26 +45,37 @@ shared_examples "apply/apply! are OK" do
45
45
  # auth client
46
46
  describe "#fetch_access_token" do
47
47
  let(:token) { "1/abcdef1234567890" }
48
- let :stub do
48
+ let :access_stub do
49
49
  make_auth_stubs access_token: token
50
50
  end
51
+ let :id_stub do
52
+ make_auth_stubs id_token: token
53
+ end
51
54
 
52
55
  it "should set access_token to the fetched value" do
53
- stub
56
+ access_stub
54
57
  @client.fetch_access_token!
55
58
  expect(@client.access_token).to eq(token)
56
- expect(stub).to have_been_requested
59
+ expect(access_stub).to have_been_requested
60
+ end
61
+
62
+ it "should set id_token to the fetched value" do
63
+ skip unless @id_client
64
+ id_stub
65
+ @id_client.fetch_access_token!
66
+ expect(@id_client.id_token).to eq(token)
67
+ expect(id_stub).to have_been_requested
57
68
  end
58
69
 
59
70
  it "should notify refresh listeners after updating" do
60
- stub
71
+ access_stub
61
72
  expect do |b|
62
73
  @client.on_refresh(&b)
63
74
  @client.fetch_access_token!
64
75
  end.to yield_with_args(have_attributes(
65
76
  access_token: "1/abcdef1234567890"
66
77
  ))
67
- expect(stub).to have_been_requested
78
+ expect(access_stub).to have_been_requested
68
79
  end
69
80
  end
70
81
 
@@ -79,6 +90,18 @@ shared_examples "apply/apply! are OK" do
79
90
  expect(md).to eq(want)
80
91
  expect(stub).to have_been_requested
81
92
  end
93
+
94
+ it "should update the target hash with fetched ID token" do
95
+ skip unless @id_client
96
+ token = "1/abcdef1234567890"
97
+ stub = make_auth_stubs id_token: token
98
+
99
+ md = { foo: "bar" }
100
+ @id_client.apply! md
101
+ want = { :foo => "bar", auth_key => "Bearer #{token}" }
102
+ expect(md).to eq(want)
103
+ expect(stub).to have_been_requested
104
+ end
82
105
  end
83
106
 
84
107
  describe "updater_proc" do
@@ -37,23 +37,32 @@ require "googleauth/compute_engine"
37
37
  require "spec_helper"
38
38
 
39
39
  describe Google::Auth::GCECredentials do
40
- MD_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
40
+ MD_ACCESS_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token".freeze
41
+ MD_ID_URI = "http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://pubsub.googleapis.com/&format=full".freeze
41
42
  GCECredentials = Google::Auth::GCECredentials
42
43
 
43
44
  before :example do
44
45
  @client = GCECredentials.new
46
+ @id_client = GCECredentials.new target_audience: "https://pubsub.googleapis.com/"
45
47
  end
46
48
 
47
- def make_auth_stubs opts = {}
48
- access_token = opts[:access_token] || ""
49
- body = MultiJson.dump("access_token" => access_token,
50
- "token_type" => "Bearer",
51
- "expires_in" => 3600)
52
- stub_request(:get, MD_URI)
53
- .with(headers: { "Metadata-Flavor" => "Google" })
54
- .to_return(body: body,
55
- status: 200,
56
- headers: { "Content-Type" => "application/json" })
49
+ def make_auth_stubs opts
50
+ if opts[:access_token]
51
+ body = MultiJson.dump("access_token" => opts[:access_token],
52
+ "token_type" => "Bearer",
53
+ "expires_in" => 3600)
54
+ stub_request(:get, MD_ACCESS_URI)
55
+ .with(headers: { "Metadata-Flavor" => "Google" })
56
+ .to_return(body: body,
57
+ status: 200,
58
+ headers: { "Content-Type" => "application/json" })
59
+ elsif opts[:id_token]
60
+ stub_request(:get, MD_ID_URI)
61
+ .with(headers: { "Metadata-Flavor" => "Google" })
62
+ .to_return(body: opts[:id_token],
63
+ status: 200,
64
+ headers: { "Content-Type" => "text/html" })
65
+ end
57
66
  end
58
67
 
59
68
  it_behaves_like "apply/apply! are OK"
@@ -61,7 +70,7 @@ describe Google::Auth::GCECredentials do
61
70
  context "metadata is unavailable" do
62
71
  describe "#fetch_access_token" do
63
72
  it "should fail if the metadata request returns a 404" do
64
- stub = stub_request(:get, MD_URI)
73
+ stub = stub_request(:get, MD_ACCESS_URI)
65
74
  .to_return(status: 404,
66
75
  headers: { "Metadata-Flavor" => "Google" })
67
76
  expect { @client.fetch_access_token! }
@@ -70,7 +79,7 @@ describe Google::Auth::GCECredentials do
70
79
  end
71
80
 
72
81
  it "should fail if the metadata request returns an unexpected code" do
73
- stub = stub_request(:get, MD_URI)
82
+ stub = stub_request(:get, MD_ACCESS_URI)
74
83
  .to_return(status: 503,
75
84
  headers: { "Metadata-Flavor" => "Google" })
76
85
  expect { @client.fetch_access_token! }
@@ -97,6 +106,7 @@ describe Google::Auth::GCECredentials do
97
106
  describe "#on_gce?" do
98
107
  it "should be true when Metadata-Flavor is Google" do
99
108
  stub = stub_request(:get, "http://169.254.169.254")
109
+ .with(headers: { "Metadata-Flavor" => "Google" })
100
110
  .to_return(status: 200,
101
111
  headers: { "Metadata-Flavor" => "Google" })
102
112
  expect(GCECredentials.on_gce?({}, true)).to eq(true)
@@ -105,6 +115,7 @@ describe Google::Auth::GCECredentials do
105
115
 
106
116
  it "should be false when Metadata-Flavor is not Google" do
107
117
  stub = stub_request(:get, "http://169.254.169.254")
118
+ .with(headers: { "Metadata-Flavor" => "Google" })
108
119
  .to_return(status: 200,
109
120
  headers: { "Metadata-Flavor" => "NotGoogle" })
110
121
  expect(GCECredentials.on_gce?({}, true)).to eq(false)
@@ -113,6 +124,7 @@ describe Google::Auth::GCECredentials do
113
124
 
114
125
  it "should be false if the response is not 200" do
115
126
  stub = stub_request(:get, "http://169.254.169.254")
127
+ .with(headers: { "Metadata-Flavor" => "Google" })
116
128
  .to_return(status: 404,
117
129
  headers: { "Metadata-Flavor" => "NotGoogle" })
118
130
  expect(GCECredentials.on_gce?({}, true)).to eq(false)
@@ -36,12 +36,13 @@ require "googleauth"
36
36
  describe Google::Auth::Credentials, :private do
37
37
  let :default_keyfile_hash do
38
38
  {
39
- "private_key_id" => "testabc1234567890xyz",
40
- "private_key" => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
41
- "client_email" => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
42
- "client_id" => "credz-testabc1234567890xyz.apps.googleusercontent.com",
43
- "type" => "service_account",
44
- "project_id" => "a_project_id"
39
+ "private_key_id" => "testabc1234567890xyz",
40
+ "private_key" => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
41
+ "client_email" => "credz-testabc1234567890xyz@developer.gserviceaccount.com",
42
+ "client_id" => "credz-testabc1234567890xyz.apps.googleusercontent.com",
43
+ "type" => "service_account",
44
+ "project_id" => "a_project_id",
45
+ "quota_project_id" => "b_project_id"
45
46
  }
46
47
  end
47
48
 
@@ -81,181 +82,385 @@ describe Google::Auth::Credentials, :private do
81
82
  Google::Auth::Credentials.new default_keyfile_hash, scope: "http://example.com/scope"
82
83
  end
83
84
 
84
- it "can be subclassed to pass in other env paths" do
85
- TEST_PATH_ENV_VAR = "TEST_PATH".freeze
86
- TEST_PATH_ENV_VAL = "/unknown/path/to/file.txt".freeze
87
- TEST_JSON_ENV_VAR = "TEST_JSON_VARS".freeze
88
-
89
- ENV[TEST_PATH_ENV_VAR] = TEST_PATH_ENV_VAL
90
- ENV[TEST_JSON_ENV_VAR] = JSON.generate default_keyfile_hash
91
-
92
- class TestCredentials < Google::Auth::Credentials
93
- SCOPE = "http://example.com/scope".freeze
94
- PATH_ENV_VARS = [TEST_PATH_ENV_VAR].freeze
95
- JSON_ENV_VARS = [TEST_JSON_ENV_VAR].freeze
85
+ describe "using CONSTANTS" do
86
+ it "can be subclassed to pass in other env paths" do
87
+ test_path_env_val = "/unknown/path/to/file.txt".freeze
88
+ test_json_env_val = JSON.generate default_keyfile_hash
89
+
90
+ ENV["TEST_PATH"] = test_path_env_val
91
+ ENV["TEST_JSON_VARS"] = test_json_env_val
92
+
93
+ class TestCredentials1 < Google::Auth::Credentials
94
+ TOKEN_CREDENTIAL_URI = "https://example.com/token".freeze
95
+ AUDIENCE = "https://example.com/audience".freeze
96
+ SCOPE = "http://example.com/scope".freeze
97
+ PATH_ENV_VARS = ["TEST_PATH"].freeze
98
+ JSON_ENV_VARS = ["TEST_JSON_VARS"].freeze
99
+ end
100
+
101
+ allow(::File).to receive(:file?).with(test_path_env_val) { false }
102
+ allow(::File).to receive(:file?).with(test_json_env_val) { false }
103
+
104
+ mocked_signet = double "Signet::OAuth2::Client"
105
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
106
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
107
+ allow(mocked_signet).to receive(:client_id)
108
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
109
+ expect(options[:token_credential_uri]).to eq("https://example.com/token")
110
+ expect(options[:audience]).to eq("https://example.com/audience")
111
+ expect(options[:scope]).to eq(["http://example.com/scope"])
112
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
113
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
114
+
115
+ mocked_signet
116
+ end
117
+
118
+ creds = TestCredentials1.default
119
+ expect(creds).to be_a_kind_of(TestCredentials1)
120
+ expect(creds.client).to eq(mocked_signet)
121
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
122
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
96
123
  end
97
124
 
98
- allow(::File).to receive(:file?).with(TEST_PATH_ENV_VAL) { false }
99
-
100
- mocked_signet = double "Signet::OAuth2::Client"
101
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
102
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
103
- allow(mocked_signet).to receive(:client_id)
104
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
105
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
106
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
107
- expect(options[:scope]).to eq(["http://example.com/scope"])
108
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
109
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
110
-
111
- mocked_signet
125
+ it "subclasses can use PATH_ENV_VARS to get keyfile path" do
126
+ class TestCredentials2 < Google::Auth::Credentials
127
+ SCOPE = "http://example.com/scope".freeze
128
+ PATH_ENV_VARS = %w[PATH_ENV_DUMMY PATH_ENV_TEST].freeze
129
+ JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
130
+ DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
131
+ end
132
+
133
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
134
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
135
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
136
+ allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
137
+ allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
138
+ allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
139
+
140
+ mocked_signet = double "Signet::OAuth2::Client"
141
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
142
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
143
+ allow(mocked_signet).to receive(:client_id)
144
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
145
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
146
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
147
+ expect(options[:scope]).to eq(["http://example.com/scope"])
148
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
149
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
150
+
151
+ mocked_signet
152
+ end
153
+
154
+ creds = TestCredentials2.default
155
+ expect(creds).to be_a_kind_of(TestCredentials2)
156
+ expect(creds.client).to eq(mocked_signet)
157
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
158
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
112
159
  end
113
160
 
114
- creds = TestCredentials.default
115
- expect(creds).to be_a_kind_of(TestCredentials)
116
- expect(creds.client).to eq(mocked_signet)
117
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
118
- end
119
-
120
- it "subclasses can use PATH_ENV_VARS to get keyfile path" do
121
- class TestCredentials < Google::Auth::Credentials
122
- SCOPE = "http://example.com/scope".freeze
123
- PATH_ENV_VARS = %w[PATH_ENV_DUMMY PATH_ENV_TEST].freeze
124
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
125
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
161
+ it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
162
+ test_json_env_val = JSON.generate default_keyfile_hash
163
+
164
+ class TestCredentials3 < Google::Auth::Credentials
165
+ SCOPE = "http://example.com/scope".freeze
166
+ PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
167
+ JSON_ENV_VARS = %w[JSON_ENV_DUMMY JSON_ENV_TEST].freeze
168
+ DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
169
+ end
170
+
171
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
172
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
173
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
174
+ allow(::File).to receive(:file?).with(test_json_env_val) { false }
175
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
176
+ allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
177
+
178
+ mocked_signet = double "Signet::OAuth2::Client"
179
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
180
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
181
+ allow(mocked_signet).to receive(:client_id)
182
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
183
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
184
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
185
+ expect(options[:scope]).to eq(["http://example.com/scope"])
186
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
187
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
188
+
189
+ mocked_signet
190
+ end
191
+
192
+ creds = TestCredentials3.default
193
+ expect(creds).to be_a_kind_of(TestCredentials3)
194
+ expect(creds.client).to eq(mocked_signet)
195
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
196
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
126
197
  end
127
198
 
128
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
129
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
130
- allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
131
- allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
132
- allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
133
-
134
- mocked_signet = double "Signet::OAuth2::Client"
135
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
136
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
137
- allow(mocked_signet).to receive(:client_id)
138
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
139
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
140
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
141
- expect(options[:scope]).to eq(["http://example.com/scope"])
142
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
143
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
144
-
145
- mocked_signet
199
+ it "subclasses can use DEFAULT_PATHS to get keyfile path" do
200
+ class TestCredentials4 < Google::Auth::Credentials
201
+ SCOPE = "http://example.com/scope".freeze
202
+ PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
203
+ JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
204
+ DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
205
+ end
206
+
207
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
208
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
209
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
210
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
211
+ allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
212
+ allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
213
+
214
+ mocked_signet = double "Signet::OAuth2::Client"
215
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
216
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
217
+ allow(mocked_signet).to receive(:client_id)
218
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
219
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
220
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
221
+ expect(options[:scope]).to eq(["http://example.com/scope"])
222
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
223
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
224
+
225
+ mocked_signet
226
+ end
227
+
228
+ creds = TestCredentials4.default
229
+ expect(creds).to be_a_kind_of(TestCredentials4)
230
+ expect(creds.client).to eq(mocked_signet)
231
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
232
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
146
233
  end
147
234
 
148
- creds = TestCredentials.default
149
- expect(creds).to be_a_kind_of(TestCredentials)
150
- expect(creds.client).to eq(mocked_signet)
151
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
152
- end
153
-
154
- it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
155
- class TestCredentials < Google::Auth::Credentials
156
- SCOPE = "http://example.com/scope".freeze
157
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
158
- JSON_ENV_VARS = %w[JSON_ENV_DUMMY JSON_ENV_TEST].freeze
159
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
235
+ it "subclasses that find no matches default to Google::Auth.get_application_default" do
236
+ class TestCredentials5 < Google::Auth::Credentials
237
+ SCOPE = "http://example.com/scope".freeze
238
+ PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
239
+ JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
240
+ DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
241
+ end
242
+
243
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
244
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
245
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
246
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
247
+ allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
248
+
249
+ mocked_signet = double "Signet::OAuth2::Client"
250
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
251
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
252
+ allow(mocked_signet).to receive(:client_id)
253
+ allow(Google::Auth).to receive(:get_application_default) do |scope|
254
+ expect(scope).to eq([TestCredentials5::SCOPE])
255
+
256
+ # This should really be a Signet::OAuth2::Client object,
257
+ # but mocking is making that difficult, so return a valid hash instead.
258
+ default_keyfile_hash
259
+ end
260
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
261
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
262
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
263
+ expect(options[:scope]).to eq(["http://example.com/scope"])
264
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
265
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
266
+
267
+ mocked_signet
268
+ end
269
+
270
+ creds = TestCredentials5.default
271
+ expect(creds).to be_a_kind_of(TestCredentials5)
272
+ expect(creds.client).to eq(mocked_signet)
273
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
274
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
160
275
  end
161
-
162
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
163
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
164
- allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
165
- allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { JSON.generate default_keyfile_hash }
166
-
167
- mocked_signet = double "Signet::OAuth2::Client"
168
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
169
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
170
- allow(mocked_signet).to receive(:client_id)
171
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
172
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
173
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
174
- expect(options[:scope]).to eq(["http://example.com/scope"])
175
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
176
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
177
-
178
- mocked_signet
179
- end
180
-
181
- creds = TestCredentials.default
182
- expect(creds).to be_a_kind_of(TestCredentials)
183
- expect(creds.client).to eq(mocked_signet)
184
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
185
276
  end
186
277
 
187
- it "subclasses can use DEFAULT_PATHS to get keyfile path" do
188
- class TestCredentials < Google::Auth::Credentials
189
- SCOPE = "http://example.com/scope".freeze
190
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
191
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
192
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
278
+ describe "using class methods" do
279
+ it "can be subclassed to pass in other env paths" do
280
+ test_path_env_val = "/unknown/path/to/file.txt".freeze
281
+ test_json_env_val = JSON.generate default_keyfile_hash
282
+
283
+ ENV["TEST_PATH"] = test_path_env_val
284
+ ENV["TEST_JSON_VARS"] = test_json_env_val
285
+
286
+ class TestCredentials11 < Google::Auth::Credentials
287
+ self.token_credential_uri = "https://example.com/token"
288
+ self.audience = "https://example.com/audience"
289
+ self.scope = "http://example.com/scope"
290
+ self.env_vars = ["TEST_PATH", "TEST_JSON_VARS"]
291
+ end
292
+
293
+ allow(::File).to receive(:file?).with(test_path_env_val) { false }
294
+ allow(::File).to receive(:file?).with(test_json_env_val) { false }
295
+
296
+ mocked_signet = double "Signet::OAuth2::Client"
297
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
298
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
299
+ allow(mocked_signet).to receive(:client_id)
300
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
301
+ expect(options[:token_credential_uri]).to eq("https://example.com/token")
302
+ expect(options[:audience]).to eq("https://example.com/audience")
303
+ expect(options[:scope]).to eq(["http://example.com/scope"])
304
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
305
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
306
+
307
+ mocked_signet
308
+ end
309
+
310
+ creds = TestCredentials11.default
311
+ expect(creds).to be_a_kind_of(TestCredentials11)
312
+ expect(creds.client).to eq(mocked_signet)
313
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
314
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
193
315
  end
194
316
 
195
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
196
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
197
- allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
198
- allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
199
- allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
200
-
201
- mocked_signet = double "Signet::OAuth2::Client"
202
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
203
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
204
- allow(mocked_signet).to receive(:client_id)
205
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
206
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
207
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
208
- expect(options[:scope]).to eq(["http://example.com/scope"])
209
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
210
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
211
-
212
- mocked_signet
317
+ it "subclasses can use PATH_ENV_VARS to get keyfile path" do
318
+ class TestCredentials12 < Google::Auth::Credentials
319
+ self.scope = "http://example.com/scope"
320
+ self.env_vars = %w[PATH_ENV_DUMMY PATH_ENV_TEST JSON_ENV_DUMMY]
321
+ self.paths = ["~/default/path/to/file.txt"]
322
+ end
323
+
324
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
325
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
326
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
327
+ allow(::ENV).to receive(:[]).with("PATH_ENV_TEST") { "/unknown/path/to/file.txt" }
328
+ allow(::File).to receive(:file?).with("/unknown/path/to/file.txt") { true }
329
+ allow(::File).to receive(:read).with("/unknown/path/to/file.txt") { JSON.generate default_keyfile_hash }
330
+
331
+ mocked_signet = double "Signet::OAuth2::Client"
332
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
333
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
334
+ allow(mocked_signet).to receive(:client_id)
335
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
336
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
337
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
338
+ expect(options[:scope]).to eq(["http://example.com/scope"])
339
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
340
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
341
+
342
+ mocked_signet
343
+ end
344
+
345
+ creds = TestCredentials12.default
346
+ expect(creds).to be_a_kind_of(TestCredentials12)
347
+ expect(creds.client).to eq(mocked_signet)
348
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
349
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
213
350
  end
214
351
 
215
- creds = TestCredentials.default
216
- expect(creds).to be_a_kind_of(TestCredentials)
217
- expect(creds.client).to eq(mocked_signet)
218
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
219
- end
220
-
221
- it "subclasses that find no matches default to Google::Auth.get_application_default" do
222
- class TestCredentials < Google::Auth::Credentials
223
- SCOPE = "http://example.com/scope".freeze
224
- PATH_ENV_VARS = ["PATH_ENV_DUMMY"].freeze
225
- JSON_ENV_VARS = ["JSON_ENV_DUMMY"].freeze
226
- DEFAULT_PATHS = ["~/default/path/to/file.txt"].freeze
352
+ it "subclasses can use JSON_ENV_VARS to get keyfile contents" do
353
+ test_json_env_val = JSON.generate default_keyfile_hash
354
+
355
+ class TestCredentials13 < Google::Auth::Credentials
356
+ self.scope = "http://example.com/scope"
357
+ self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY JSON_ENV_TEST]
358
+ self.paths = ["~/default/path/to/file.txt"]
359
+ end
360
+
361
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
362
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
363
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
364
+ allow(::File).to receive(:file?).with(test_json_env_val) { false }
365
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
366
+ allow(::ENV).to receive(:[]).with("JSON_ENV_TEST") { test_json_env_val }
367
+
368
+ mocked_signet = double "Signet::OAuth2::Client"
369
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
370
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
371
+ allow(mocked_signet).to receive(:client_id)
372
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
373
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
374
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
375
+ expect(options[:scope]).to eq(["http://example.com/scope"])
376
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
377
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
378
+
379
+ mocked_signet
380
+ end
381
+
382
+ creds = TestCredentials13.default
383
+ expect(creds).to be_a_kind_of(TestCredentials13)
384
+ expect(creds.client).to eq(mocked_signet)
385
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
386
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
227
387
  end
228
388
 
229
- allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
230
- allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
231
- allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
232
- allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
233
-
234
- mocked_signet = double "Signet::OAuth2::Client"
235
- allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
236
- allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
237
- allow(mocked_signet).to receive(:client_id)
238
- allow(Google::Auth).to receive(:get_application_default) do |scope|
239
- expect(scope).to eq(TestCredentials::SCOPE)
240
-
241
- # This should really be a Signet::OAuth2::Client object,
242
- # but mocking is making that difficult, so return a valid hash instead.
243
- default_keyfile_hash
389
+ it "subclasses can use DEFAULT_PATHS to get keyfile path" do
390
+ class TestCredentials14 < Google::Auth::Credentials
391
+ self.scope = "http://example.com/scope"
392
+ self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
393
+ self.paths = ["~/default/path/to/file.txt"]
394
+ end
395
+
396
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
397
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
398
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
399
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
400
+ allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { true }
401
+ allow(::File).to receive(:read).with("~/default/path/to/file.txt") { JSON.generate default_keyfile_hash }
402
+
403
+ mocked_signet = double "Signet::OAuth2::Client"
404
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
405
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
406
+ allow(mocked_signet).to receive(:client_id)
407
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
408
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
409
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
410
+ expect(options[:scope]).to eq(["http://example.com/scope"])
411
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
412
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
413
+
414
+ mocked_signet
415
+ end
416
+
417
+ creds = TestCredentials14.default
418
+ expect(creds).to be_a_kind_of(TestCredentials14)
419
+ expect(creds.client).to eq(mocked_signet)
420
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
421
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
244
422
  end
245
- allow(Signet::OAuth2::Client).to receive(:new) do |options|
246
- expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
247
- expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
248
- expect(options[:scope]).to eq(["http://example.com/scope"])
249
- expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
250
- expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
251
423
 
252
- mocked_signet
424
+ it "subclasses that find no matches default to Google::Auth.get_application_default" do
425
+ class TestCredentials15 < Google::Auth::Credentials
426
+ self.scope = "http://example.com/scope"
427
+ self.env_vars = %w[PATH_ENV_DUMMY JSON_ENV_DUMMY]
428
+ self.paths = ["~/default/path/to/file.txt"]
429
+ end
430
+
431
+ allow(::ENV).to receive(:[]).with("GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS") { "true" }
432
+ allow(::ENV).to receive(:[]).with("PATH_ENV_DUMMY") { "/fake/path/to/file.txt" }
433
+ allow(::File).to receive(:file?).with("/fake/path/to/file.txt") { false }
434
+ allow(::ENV).to receive(:[]).with("JSON_ENV_DUMMY") { nil }
435
+ allow(::File).to receive(:file?).with("~/default/path/to/file.txt") { false }
436
+
437
+ mocked_signet = double "Signet::OAuth2::Client"
438
+ allow(mocked_signet).to receive(:configure_connection).and_return(mocked_signet)
439
+ allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
440
+ allow(mocked_signet).to receive(:client_id)
441
+ allow(Google::Auth).to receive(:get_application_default) do |scope|
442
+ expect(scope).to eq(TestCredentials15.scope)
443
+
444
+ # This should really be a Signet::OAuth2::Client object,
445
+ # but mocking is making that difficult, so return a valid hash instead.
446
+ default_keyfile_hash
447
+ end
448
+ allow(Signet::OAuth2::Client).to receive(:new) do |options|
449
+ expect(options[:token_credential_uri]).to eq("https://oauth2.googleapis.com/token")
450
+ expect(options[:audience]).to eq("https://oauth2.googleapis.com/token")
451
+ expect(options[:scope]).to eq(["http://example.com/scope"])
452
+ expect(options[:issuer]).to eq(default_keyfile_hash["client_email"])
453
+ expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
454
+
455
+ mocked_signet
456
+ end
457
+
458
+ creds = TestCredentials15.default
459
+ expect(creds).to be_a_kind_of(TestCredentials15)
460
+ expect(creds.client).to eq(mocked_signet)
461
+ expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
462
+ expect(creds.quota_project_id).to eq(default_keyfile_hash["quota_project_id"])
253
463
  end
254
-
255
- creds = TestCredentials.default
256
- expect(creds).to be_a_kind_of(TestCredentials)
257
- expect(creds.client).to eq(mocked_signet)
258
- expect(creds.project_id).to eq(default_keyfile_hash["project_id"])
259
464
  end
260
465
 
261
466
  it "warns when cloud sdk credentials are used" do