1 package config
2
3 import (
4 "bytes"
5 "context"
6 "fmt"
7 "path/filepath"
8 "reflect"
9 "strconv"
10 "strings"
11 "testing"
12 "time"
13
14 "github.com/aws/aws-sdk-go-v2/aws"
15 "github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
16 "github.com/aws/aws-sdk-go-v2/internal/ini"
17 "github.com/aws/smithy-go/logging"
18 "github.com/aws/smithy-go/ptr"
19 )
20
21 var _ regionProvider = (*SharedConfig)(nil)
22
23 var (
24 testConfigFilename = filepath.Join("testdata", "shared_config")
25 testConfigOtherFilename = filepath.Join("testdata", "shared_config_other")
26 testCredentialsFilename = filepath.Join("testdata", "shared_credentials")
27 )
28
29 func TestNewSharedConfig(t *testing.T) {
30 cases := map[string]struct {
31 ConfigFilenames []string
32 CredentialsFilenames []string
33 Profile string
34 Expected SharedConfig
35 Err error
36 }{
37 "file not exist": {
38 ConfigFilenames: []string{"file_not_exist"},
39 Profile: "default",
40 Err: fmt.Errorf("failed to get shared config profile"),
41 },
42 "default profile": {
43 ConfigFilenames: []string{testConfigFilename},
44 Profile: "default",
45 Expected: SharedConfig{
46 Profile: "default",
47 Region: "default_region",
48 },
49 },
50 "multiple config files": {
51 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
52 Profile: "config_file_load_order",
53 Expected: SharedConfig{
54 Profile: "config_file_load_order",
55 Region: "shared_config_region",
56 Credentials: aws.Credentials{
57 AccessKeyID: "shared_config_akid",
58 SecretAccessKey: "shared_config_secret",
59 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
60 },
61 },
62 },
63 "mutliple config files reverse order": {
64 ConfigFilenames: []string{testConfigFilename, testConfigOtherFilename},
65 Profile: "config_file_load_order",
66 Expected: SharedConfig{
67 Profile: "config_file_load_order",
68 Region: "shared_config_other_region",
69 Credentials: aws.Credentials{
70 AccessKeyID: "shared_config_other_akid",
71 SecretAccessKey: "shared_config_other_secret",
72 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigOtherFilename),
73 },
74 },
75 },
76 "Assume role": {
77 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
78 Profile: "assume_role",
79 Expected: SharedConfig{
80 Profile: "assume_role",
81 RoleARN: "assume_role_role_arn",
82 SourceProfileName: "complete_creds",
83 Source: &SharedConfig{
84 Profile: "complete_creds",
85 Credentials: aws.Credentials{
86 AccessKeyID: "complete_creds_akid",
87 SecretAccessKey: "complete_creds_secret",
88 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
89 },
90 },
91 },
92 },
93 "Assume role with invalid source profile": {
94 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
95 Profile: "assume_role_invalid_source_profile",
96 Err: SharedConfigAssumeRoleError{
97 Profile: "profile_not_exists",
98 RoleARN: "assume_role_invalid_source_profile_role_arn",
99 Err: SharedConfigProfileNotExistError{
100 Profile: "profile_not_exists",
101 Err: nil,
102 },
103 },
104 },
105 "Assume role with creds": {
106 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
107 Profile: "assume_role_w_creds",
108 Expected: SharedConfig{
109 Profile: "assume_role_w_creds",
110 RoleARN: "assume_role_w_creds_role_arn",
111 ExternalID: "1234",
112 RoleSessionName: "assume_role_w_creds_session_name",
113 SourceProfileName: "assume_role_w_creds",
114 Source: &SharedConfig{
115 Profile: "assume_role_w_creds",
116 Credentials: aws.Credentials{
117 AccessKeyID: "assume_role_w_creds_akid",
118 SecretAccessKey: "assume_role_w_creds_secret",
119 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
120 },
121 },
122 },
123 },
124 "Assume role without creds": {
125 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
126 Profile: "assume_role_wo_creds",
127 Expected: SharedConfig{
128 Profile: "assume_role_wo_creds",
129 RoleARN: "assume_role_wo_creds_role_arn",
130 SourceProfileName: "assume_role_wo_creds",
131 },
132 Err: SharedConfigAssumeRoleError{
133 Profile: "assume_role_wo_creds",
134 RoleARN: "assume_role_wo_creds_role_arn",
135 },
136 },
137 "Invalid INI file": {
138 ConfigFilenames: []string{filepath.Join("testdata", "shared_config_invalid_ini")},
139 Profile: "profile_name",
140 Err: SharedConfigProfileNotExistError{
141 Filename: []string{filepath.Join("testdata", "shared_config_invalid_ini")},
142 Profile: "profile_name",
143 Err: nil,
144 },
145 },
146 "S3UseARNRegion property on profile": {
147 Profile: "valid_arn_region",
148 ConfigFilenames: []string{testConfigFilename},
149 Expected: SharedConfig{
150 Profile: "valid_arn_region",
151 S3UseARNRegion: ptr.Bool(true),
152 },
153 },
154 "S3DisableMultiRegionAccessPoints property on profile": {
155 Profile: "disable_mrap",
156 ConfigFilenames: []string{testConfigFilename},
157 Expected: SharedConfig{
158 Profile: "disable_mrap",
159 S3DisableMultiRegionAccessPoints: ptr.Bool(true),
160 },
161 },
162 "EndpointDiscovery property enabled on profile": {
163 Profile: "endpoint_discovery_enabled",
164 ConfigFilenames: []string{testConfigFilename},
165 Expected: SharedConfig{
166 Profile: "endpoint_discovery_enabled",
167 EnableEndpointDiscovery: aws.EndpointDiscoveryEnabled,
168 },
169 },
170 "EndpointDiscovery property disabled on profile": {
171 Profile: "endpoint_discovery_disabled",
172 ConfigFilenames: []string{testConfigFilename},
173 Expected: SharedConfig{
174 Profile: "endpoint_discovery_disabled",
175 EnableEndpointDiscovery: aws.EndpointDiscoveryDisabled,
176 },
177 },
178 "EndpointDiscovery property set as auto on profile": {
179 Profile: "endpoint_discovery_auto",
180 ConfigFilenames: []string{testConfigFilename},
181 Expected: SharedConfig{
182 Profile: "endpoint_discovery_auto",
183 EnableEndpointDiscovery: aws.EndpointDiscoveryAuto,
184 },
185 },
186 "EndpointDiscovery property set as unknown on profile": {
187 Profile: "endpoint_discovery_unknown",
188 ConfigFilenames: []string{testConfigFilename},
189 Expected: SharedConfig{
190 Profile: "endpoint_discovery_unknown",
191 EnableEndpointDiscovery: aws.EndpointDiscoveryUnset,
192 },
193 },
194 "Assume role with credential source Ec2Metadata": {
195 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
196 Profile: "assume_role_with_credential_source",
197 Expected: SharedConfig{
198 Profile: "assume_role_with_credential_source",
199 RoleARN: "assume_role_with_credential_source_role_arn",
200 CredentialSource: credSourceEc2Metadata,
201 },
202 },
203 "Assume role chained with creds": {
204 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
205 Profile: "multiple_assume_role",
206 Expected: SharedConfig{
207 Profile: "multiple_assume_role",
208 RoleARN: "multiple_assume_role_role_arn",
209 SourceProfileName: "assume_role",
210 Source: &SharedConfig{
211 Profile: "assume_role",
212 RoleARN: "assume_role_role_arn",
213 SourceProfileName: "complete_creds",
214 Source: &SharedConfig{
215 Profile: "complete_creds",
216 Credentials: aws.Credentials{
217 AccessKeyID: "complete_creds_akid",
218 SecretAccessKey: "complete_creds_secret",
219 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
220 },
221 },
222 },
223 },
224 },
225 "Assume role chained with credential source": {
226 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
227 Profile: "multiple_assume_role_with_credential_source",
228 Expected: SharedConfig{
229 Profile: "multiple_assume_role_with_credential_source",
230 RoleARN: "multiple_assume_role_with_credential_source_role_arn",
231 SourceProfileName: "assume_role_with_credential_source",
232 Source: &SharedConfig{
233 Profile: "assume_role_with_credential_source",
234 RoleARN: "assume_role_with_credential_source_role_arn",
235 CredentialSource: credSourceEc2Metadata,
236 },
237 },
238 },
239 "Assume role chained with credential source reversed order": {
240 ConfigFilenames: []string{testConfigOtherFilename, testConfigFilename},
241 Profile: "multiple_assume_role_with_credential_source2",
242 Expected: SharedConfig{
243 Profile: "multiple_assume_role_with_credential_source2",
244 RoleARN: "multiple_assume_role_with_credential_source2_role_arn",
245 SourceProfileName: "multiple_assume_role_with_credential_source",
246 Source: &SharedConfig{
247 Profile: "multiple_assume_role_with_credential_source",
248 RoleARN: "multiple_assume_role_with_credential_source_role_arn",
249 SourceProfileName: "assume_role_with_credential_source",
250 Source: &SharedConfig{
251 Profile: "assume_role_with_credential_source",
252 RoleARN: "assume_role_with_credential_source_role_arn",
253 CredentialSource: credSourceEc2Metadata,
254 },
255 },
256 },
257 },
258 "AWS SSO Profile": {
259 ConfigFilenames: []string{testConfigFilename},
260 Profile: "sso_creds",
261 Expected: SharedConfig{
262 Profile: "sso_creds",
263 SSOAccountID: "012345678901",
264 SSORegion: "us-west-2",
265 SSORoleName: "TestRole",
266 SSOStartURL: "https://127.0.0.1/start",
267 },
268 },
269 "Assume Role with AWS SSO Credentials": {
270 ConfigFilenames: []string{testConfigFilename},
271 Profile: "source_sso_creds",
272 Expected: SharedConfig{
273 Profile: "source_sso_creds",
274 RoleARN: "source_sso_creds_arn",
275 SourceProfileName: "sso_creds",
276 Source: &SharedConfig{
277 Profile: "sso_creds",
278 SSOAccountID: "012345678901",
279 SSORegion: "us-west-2",
280 SSORoleName: "TestRole",
281 SSOStartURL: "https://127.0.0.1/start",
282 },
283 },
284 },
285 "AWS SSO Profile and Static Credentials": {
286 ConfigFilenames: []string{testConfigFilename},
287 Profile: "sso_and_static",
288 Expected: SharedConfig{
289 Profile: "sso_and_static",
290 Credentials: aws.Credentials{
291 AccessKeyID: "sso_and_static_akid",
292 SecretAccessKey: "sso_and_static_secret",
293 SessionToken: "sso_and_static_token",
294 Source: fmt.Sprintf("SharedConfigCredentials: %s", testConfigFilename),
295 },
296 SSOAccountID: "012345678901",
297 SSORegion: "us-west-2",
298 SSORoleName: "TestRole",
299 SSOStartURL: "https://THIS_SHOULD_NOT_BE_IN_TESTDATA_CACHE/start",
300 },
301 },
302 "Assume Role with AWS SSO Configuration and Source Profile": {
303 ConfigFilenames: []string{testConfigFilename},
304 Profile: "source_sso_and_assume",
305 Expected: SharedConfig{
306 Profile: "source_sso_and_assume",
307 RoleARN: "source_sso_and_assume_arn",
308 SourceProfileName: "sso_and_assume",
309 Source: &SharedConfig{
310 Profile: "sso_and_assume",
311 RoleARN: "sso_with_assume_role_arn",
312 SourceProfileName: "multiple_assume_role_with_credential_source",
313 Source: &SharedConfig{
314 Profile: "multiple_assume_role_with_credential_source",
315 RoleARN: "multiple_assume_role_with_credential_source_role_arn",
316 SourceProfileName: "assume_role_with_credential_source",
317 Source: &SharedConfig{
318 Profile: "assume_role_with_credential_source",
319 RoleARN: "assume_role_with_credential_source_role_arn",
320 CredentialSource: credSourceEc2Metadata,
321 },
322 },
323 },
324 },
325 },
326 "SSO Mixed with Additional Credential Providrer": {
327 ConfigFilenames: []string{testConfigFilename},
328 Profile: "sso_mixed_credproc",
329 Expected: SharedConfig{
330 Profile: "sso_mixed_credproc",
331 SSOAccountID: "012345678901",
332 SSORegion: "us-west-2",
333 SSORoleName: "TestRole",
334 SSOStartURL: "https://127.0.0.1/start",
335 CredentialProcess: "/path/to/process",
336 },
337 },
338 "SSO Session success": {
339 ConfigFilenames: []string{testConfigFilename},
340 Profile: "sso-session-success",
341 Expected: SharedConfig{
342 Profile: "sso-session-success",
343 Region: "us-east-1",
344 SSOAccountID: "123456789012",
345 SSORoleName: "testRole",
346 SSOSessionName: "sso-session-success-dev",
347 SSOSession: &SSOSession{
348 Name: "sso-session-success-dev",
349 SSORegion: "us-east-1",
350 SSOStartURL: "https://d-123456789a.awsapps.com/start",
351 },
352 },
353 },
354 "profile names are case-sensitive (Mixed)": {
355 ConfigFilenames: []string{testConfigFilename},
356 CredentialsFilenames: []string{testCredentialsFilename},
357 Profile: "DoNotNormalize",
358 Expected: SharedConfig{
359 Profile: "DoNotNormalize",
360 Credentials: aws.Credentials{
361 AccessKeyID: "DoNotNormalize_credentials_akid",
362 SecretAccessKey: "DoNotNormalize_credentials_secret",
363 SessionToken: "DoNotNormalize_config_session_token",
364 Source: fmt.Sprintf("SharedConfigCredentials: %s", testCredentialsFilename),
365 },
366 RoleDurationSeconds: func() *time.Duration { d := time.Minute * 20; return &d }(),
367 Region: "eu-west-1",
368 },
369 },
370 "profile names are case-sensitive (lower)": {
371 ConfigFilenames: []string{testConfigFilename},
372 CredentialsFilenames: []string{testCredentialsFilename},
373 Profile: "donotnormalize",
374 Expected: SharedConfig{
375 Profile: "donotnormalize",
376 Credentials: aws.Credentials{
377 AccessKeyID: "donotnormalize_credentials_akid",
378 SecretAccessKey: "donotnormalize_credentials_secret",
379 SessionToken: "donotnormalize_config_session_token",
380 Source: fmt.Sprintf("SharedConfigCredentials: %s", testCredentialsFilename),
381 },
382 RoleDurationSeconds: func() *time.Duration { d := time.Minute * 25; return &d }(),
383 Region: "eu-west-2",
384 },
385 },
386 "profile names are case-sensitive (upper)": {
387 ConfigFilenames: []string{testConfigFilename},
388 CredentialsFilenames: []string{testCredentialsFilename},
389 Profile: "DONOTNORMALIZE",
390 Expected: SharedConfig{
391 Profile: "DONOTNORMALIZE",
392 Credentials: aws.Credentials{
393 AccessKeyID: "DONOTNORMALIZE_credentials_akid",
394 SecretAccessKey: "DONOTNORMALIZE_credentials_secret",
395 SessionToken: "DONOTNORMALIZE_config_session_token",
396 Source: fmt.Sprintf("SharedConfigCredentials: %s", testCredentialsFilename),
397 },
398 RoleDurationSeconds: func() *time.Duration { d := time.Minute * 30; return &d }(),
399 Region: "eu-west-3",
400 },
401 },
402 "source profile name is case-sensitive": {
403 ConfigFilenames: []string{testConfigFilename},
404 CredentialsFilenames: []string{testCredentialsFilename},
405 Profile: "AssumeWithDoNotNormalize",
406 Expected: SharedConfig{
407 Profile: "AssumeWithDoNotNormalize",
408 RoleARN: "AssumeWithDoNotNormalize_role_arn",
409 SourceProfileName: "DoNotNormalize",
410 Source: &SharedConfig{
411 Profile: "DoNotNormalize",
412 Credentials: aws.Credentials{
413 AccessKeyID: "DoNotNormalize_credentials_akid",
414 SecretAccessKey: "DoNotNormalize_credentials_secret",
415 SessionToken: "DoNotNormalize_config_session_token",
416 Source: fmt.Sprintf("SharedConfigCredentials: %s", testCredentialsFilename),
417 },
418 RoleDurationSeconds: func() *time.Duration { d := time.Minute * 20; return &d }(),
419 Region: "eu-west-1",
420 },
421 },
422 },
423 "profile with ec2_metadata_service_endpoint": {
424 ConfigFilenames: []string{testConfigFilename},
425 CredentialsFilenames: []string{testCredentialsFilename},
426 Profile: "EC2MetadataServiceEndpoint",
427 Expected: SharedConfig{
428 Profile: "EC2MetadataServiceEndpoint",
429 EC2IMDSEndpoint: "http://endpoint.localhost",
430 },
431 },
432 "profile with ec2_metadata_service_endpoint_mode as IPv6": {
433 ConfigFilenames: []string{testConfigFilename},
434 CredentialsFilenames: []string{testCredentialsFilename},
435 Profile: "EC2MetadataServiceEndpointModeIPv6",
436 Expected: SharedConfig{
437 Profile: "EC2MetadataServiceEndpointModeIPv6",
438 EC2IMDSEndpointMode: imds.EndpointModeStateIPv6,
439 },
440 },
441 "profile with ec2_metadata_service_endpoint_mode as IPv4": {
442 ConfigFilenames: []string{testConfigFilename},
443 CredentialsFilenames: []string{testCredentialsFilename},
444 Profile: "EC2MetadataServiceEndpointModeIPv4",
445 Expected: SharedConfig{
446 Profile: "EC2MetadataServiceEndpointModeIPv4",
447 EC2IMDSEndpointMode: imds.EndpointModeStateIPv4,
448 },
449 },
450 "profile with ec2_metadata_service_endpoint_mode is unknown": {
451 ConfigFilenames: []string{testConfigFilename},
452 CredentialsFilenames: []string{testCredentialsFilename},
453 Profile: "EC2MetadataServiceEndpointModeUnknown",
454 Expected: SharedConfig{
455 Profile: "EC2MetadataServiceEndpointModeUnknown",
456 },
457 Err: fmt.Errorf("unknown EC2 IMDS endpoint mode"),
458 },
459 "profile with ec2_metadata_service_endpoint and ec2_metadata_service_endpoint_mode": {
460 ConfigFilenames: []string{testConfigFilename},
461 CredentialsFilenames: []string{testCredentialsFilename},
462 Profile: "EC2MetadataServiceEndpointAndModeMixed",
463 Expected: SharedConfig{
464 Profile: "EC2MetadataServiceEndpointAndModeMixed",
465 EC2IMDSEndpoint: "http://endpoint.localhost",
466 EC2IMDSEndpointMode: imds.EndpointModeStateIPv6,
467 },
468 },
469 "dual-stack endpoint enabled": {
470 ConfigFilenames: []string{testConfigFilename},
471 CredentialsFilenames: []string{testCredentialsFilename},
472 Profile: "UseDualStackEndpointEnabled",
473 Expected: SharedConfig{
474 Profile: "UseDualStackEndpointEnabled",
475 Region: "us-west-2",
476 UseDualStackEndpoint: aws.DualStackEndpointStateEnabled,
477 },
478 },
479 "dual-stack endpoint disabled": {
480 ConfigFilenames: []string{testConfigFilename},
481 CredentialsFilenames: []string{testCredentialsFilename},
482 Profile: "UseDualStackEndpointDisabled",
483 Expected: SharedConfig{
484 Profile: "UseDualStackEndpointDisabled",
485 Region: "us-west-2",
486 UseDualStackEndpoint: aws.DualStackEndpointStateDisabled,
487 },
488 },
489 "dual-stack endpoint invalid": {
490 ConfigFilenames: []string{testConfigFilename},
491 CredentialsFilenames: []string{testCredentialsFilename},
492 Profile: "UseDualStackEndpointInvalid",
493 Expected: SharedConfig{
494 Profile: "UseDualStackEndpointInvalid",
495 Region: "us-west-2",
496 UseDualStackEndpoint: aws.DualStackEndpointStateDisabled,
497 },
498 },
499 "fips endpoint enabled": {
500 ConfigFilenames: []string{testConfigFilename},
501 CredentialsFilenames: []string{testCredentialsFilename},
502 Profile: "UseFIPSEndpointEnabled",
503 Expected: SharedConfig{
504 Profile: "UseFIPSEndpointEnabled",
505 Region: "us-west-2",
506 UseFIPSEndpoint: aws.FIPSEndpointStateEnabled,
507 },
508 },
509 "fips endpoint disabled": {
510 ConfigFilenames: []string{testConfigFilename},
511 CredentialsFilenames: []string{testCredentialsFilename},
512 Profile: "UseFIPSEndpointDisabled",
513 Expected: SharedConfig{
514 Profile: "UseFIPSEndpointDisabled",
515 Region: "us-west-2",
516 UseFIPSEndpoint: aws.FIPSEndpointStateDisabled,
517 },
518 },
519 "fips endpoint unknown": {
520 ConfigFilenames: []string{testConfigFilename},
521 CredentialsFilenames: []string{testCredentialsFilename},
522 Profile: "UseFIPSEndpointInvalid",
523 Expected: SharedConfig{
524 Profile: "UseFIPSEndpointInvalid",
525 Region: "us-west-2",
526 UseFIPSEndpoint: aws.FIPSEndpointStateDisabled,
527 },
528 },
529 "defaults mode auto": {
530 ConfigFilenames: []string{testConfigFilename},
531 CredentialsFilenames: []string{testCredentialsFilename},
532 Profile: "autodefaultsmode",
533 Expected: SharedConfig{
534 Profile: "autodefaultsmode",
535 DefaultsMode: aws.DefaultsModeAuto,
536 },
537 },
538 "defaults mode standard": {
539 ConfigFilenames: []string{testConfigFilename},
540 CredentialsFilenames: []string{testCredentialsFilename},
541 Profile: "standarddefaultsmode",
542 Expected: SharedConfig{
543 Profile: "standarddefaultsmode",
544 DefaultsMode: aws.DefaultsModeStandard,
545 },
546 },
547 "defaults mode invalid": {
548 ConfigFilenames: []string{testConfigFilename},
549 CredentialsFilenames: []string{testCredentialsFilename},
550 Profile: "invaliddefaultsmode",
551 Err: fmt.Errorf("failed to load defaults_mode from shared config, invalid value: invalid"),
552 },
553 "retry options auto": {
554 ConfigFilenames: []string{testConfigFilename},
555 CredentialsFilenames: []string{testCredentialsFilename},
556 Profile: "retryunset",
557 Expected: SharedConfig{
558 Profile: "retryunset",
559 },
560 },
561 "retry options standard": {
562 ConfigFilenames: []string{testConfigFilename},
563 CredentialsFilenames: []string{testCredentialsFilename},
564 Profile: "retrywithstandard",
565 Expected: SharedConfig{
566 Profile: "retrywithstandard",
567 RetryMode: aws.RetryModeStandard,
568 RetryMaxAttempts: 5,
569 },
570 },
571 "retry options adaptive": {
572 ConfigFilenames: []string{testConfigFilename},
573 CredentialsFilenames: []string{testCredentialsFilename},
574 Profile: "retrywithadaptive",
575 Expected: SharedConfig{
576 Profile: "retrywithadaptive",
577 RetryMode: aws.RetryModeAdaptive,
578 RetryMaxAttempts: 4,
579 },
580 },
581 "retry options invalid": {
582 ConfigFilenames: []string{testConfigFilename},
583 CredentialsFilenames: []string{testCredentialsFilename},
584 Profile: "retrywithinvalidmode",
585 Err: fmt.Errorf("failed to load retry_mode from shared config, unknown RetryMode, invalid"),
586 },
587 "retry options invalid retry attempts": {
588 ConfigFilenames: []string{testConfigFilename},
589 CredentialsFilenames: []string{testCredentialsFilename},
590 Profile: "retrywithinvalidattempts",
591 Err: fmt.Errorf("failed to load max_attempts from shared config, invalid value max_attempts=invalid, expect integer"),
592 },
593 "ca bundle options": {
594 ConfigFilenames: []string{testConfigFilename},
595 CredentialsFilenames: []string{testCredentialsFilename},
596 Profile: "with_ca_bundle",
597 Expected: SharedConfig{
598 Profile: "with_ca_bundle",
599 CustomCABundle: "custom_ca_bundle_file.pem",
600 },
601 },
602 "merged profiles across files": {
603 ConfigFilenames: []string{testConfigFilename},
604 CredentialsFilenames: []string{testCredentialsFilename},
605 Profile: "merged_profiles",
606 Expected: SharedConfig{
607 Profile: "merged_profiles",
608 RoleARN: "creds_profile_arn",
609 RoleDurationSeconds: aws.Duration(1023 * time.Second),
610 SSOAccountID: "0123456789",
611 SSORegion: "us-west-2",
612 SSORoleName: "CredProfileRole",
613 SSOStartURL: "https://my-sso-cred-profile-role.awsapps.com/start",
614 CustomCABundle: "/path/to/bundle.b",
615 },
616 },
617 "merged profiles across config files": {
618 ConfigFilenames: []string{testConfigFilename, testConfigFilename},
619 CredentialsFilenames: []string{},
620 Profile: "merged_profiles",
621 Expected: SharedConfig{
622 Profile: "merged_profiles",
623 RoleARN: "config_profile_arn",
624 RoleDurationSeconds: aws.Duration(3601 * time.Second),
625 SSOAccountID: "1234567890",
626 SSORegion: "us-east-1",
627 SSORoleName: "ConfigProfileRole",
628 SSOStartURL: "https://my-sso-config-profile-role.awsapps.com/start",
629 CustomCABundle: "/path/to/bundle.a",
630 },
631 },
632 "merged profiles across credentials files": {
633 ConfigFilenames: []string{},
634 CredentialsFilenames: []string{testCredentialsFilename, testCredentialsFilename},
635 Profile: "merged_profiles",
636 Expected: SharedConfig{
637 Profile: "merged_profiles",
638 RoleARN: "creds_profile_arn",
639 RoleDurationSeconds: aws.Duration(1023 * time.Second),
640 SSOAccountID: "0123456789",
641 SSORegion: "us-west-2",
642 SSORoleName: "CredProfileRole",
643 SSOStartURL: "https://my-sso-cred-profile-role.awsapps.com/start",
644 CustomCABundle: "/path/to/bundle.b",
645 },
646 },
647 "Profile with app ID": {
648 ConfigFilenames: []string{testConfigFilename},
649 Profile: "sdk_app_id",
650 Expected: SharedConfig{
651 Profile: "sdk_app_id",
652 AppID: "12345",
653 },
654 },
655 "endpoint config test": {
656 ConfigFilenames: []string{testConfigFilename},
657 Profile: "endpoint_config",
658 Expected: SharedConfig{
659 Profile: "endpoint_config",
660 BaseEndpoint: "https://example.com",
661 IgnoreConfiguredEndpoints: ptr.Bool(true),
662 },
663 },
664 "imdsv1 disabled = false": {
665 ConfigFilenames: []string{testConfigFilename},
666 Profile: "ec2-metadata-v1-disabled-false",
667 Expected: SharedConfig{
668 Profile: "ec2-metadata-v1-disabled-false",
669 EC2IMDSv1Disabled: aws.Bool(false),
670 },
671 },
672 "imdsv1 disabled = true": {
673 ConfigFilenames: []string{testConfigFilename},
674 Profile: "ec2-metadata-v1-disabled-true",
675 Expected: SharedConfig{
676 Profile: "ec2-metadata-v1-disabled-true",
677 EC2IMDSv1Disabled: aws.Bool(true),
678 },
679 },
680 "imdsv1 disabled = invalid": {
681 ConfigFilenames: []string{testConfigFilename},
682 Profile: "ec2-metadata-v1-disabled-invalid",
683 Expected: SharedConfig{
684 Profile: "ec2-metadata-v1-disabled-invalid",
685 EC2IMDSv1Disabled: aws.Bool(false),
686 },
687 },
688 "profile configuring request compression": {
689 ConfigFilenames: []string{testConfigFilename},
690 Profile: "request_compression",
691 Expected: SharedConfig{
692 Profile: "request_compression",
693 DisableRequestCompression: aws.Bool(true),
694 RequestMinCompressSizeBytes: aws.Int64(12345),
695 },
696 },
697 "profile with invalid disableRequestCompression": {
698 ConfigFilenames: []string{testConfigFilename},
699 Profile: "request_compression_invalid_disable",
700 Err: fmt.Errorf("invalid value for shared config profile field, %s=%s, need true or false",
701 disableRequestCompression, "blabla"),
702 },
703 "profile with non-int requestMinCompressSizeBytes": {
704 ConfigFilenames: []string{testConfigFilename},
705 Profile: "request_compression_non_int_min_request",
706 Err: fmt.Errorf("invalid value for min request compression size bytes hahaha, need int64"),
707 },
708 "profile with requestMinCompressSizeBytes out of bounds": {
709 ConfigFilenames: []string{testConfigFilename},
710 Profile: "request_compression_min_request_out_of_bounds",
711 Err: fmt.Errorf("invalid range for min request compression size bytes 10485761, must be within 0 and 10485760 inclusively"),
712 },
713 "services section": {
714 ConfigFilenames: []string{testConfigFilename},
715 Profile: "service_endpoint_url",
716 Expected: SharedConfig{
717 Profile: "service_endpoint_url",
718 ServicesSectionName: "service_endpoint_url_services",
719 Services: Services{
720 ServiceValues: map[string]map[string]string{
721 "s3": {
722 "endpoint_url": "http://127.0.0.1",
723 "other": "foo",
724 },
725 "ec2": {
726 "endpoint_url": "http://127.0.0.1:81",
727 },
728 },
729 },
730 },
731 },
732 }
733
734 for name, c := range cases {
735 t.Run(name, func(t *testing.T) {
736 cfg, err := LoadSharedConfigProfile(context.TODO(), c.Profile, func(o *LoadSharedConfigOptions) {
737 o.ConfigFiles = c.ConfigFilenames
738 if c.CredentialsFilenames != nil {
739 o.CredentialsFiles = c.CredentialsFilenames
740 } else {
741 o.CredentialsFiles = []string{filepath.Join("testdata", "empty_creds_config")}
742 }
743 })
744 if c.Err != nil && err != nil {
745 if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
746 t.Errorf("expect %q to be in %q", e, a)
747 }
748 return
749 }
750 if err != nil {
751 t.Fatalf("expect no error, got %v", err)
752 }
753 if c.Err != nil {
754 t.Errorf("expect error: %v, got none", c.Err)
755 }
756 if diff := cmpDiff(c.Expected, cfg); len(diff) > 0 {
757 t.Error(diff)
758 }
759 })
760 }
761 }
762
763 func TestLoadSharedConfigFromSection(t *testing.T) {
764 filename := testConfigFilename
765 sections, err := ini.OpenFile(filename)
766
767 if err != nil {
768 t.Fatalf("failed to load test config file, %s, %v", filename, err)
769 }
770 cases := map[string]struct {
771 Profile string
772 Expected SharedConfig
773 Err error
774 }{
775 "Default as profile": {
776 Profile: "default",
777 Expected: SharedConfig{Region: "default_region"},
778 },
779 "prefixed profile": {
780 Profile: "profile alt_profile_name",
781 Expected: SharedConfig{Region: "alt_profile_name_region"},
782 },
783 "prefixed profile 2": {
784 Profile: "profile short_profile_name_first",
785 Expected: SharedConfig{Region: "short_profile_name_first_alt"},
786 },
787 "profile with partial creds": {
788 Profile: "profile partial_creds",
789 Expected: SharedConfig{},
790 },
791 "profile with role duration": {
792 Profile: "profile with_role_duration",
793 Expected: SharedConfig{
794 RoleDurationSeconds: aws.Duration(3601 * time.Second),
795 },
796 },
797 "profile with complete creds": {
798 Profile: "profile complete_creds",
799 Expected: SharedConfig{
800 Credentials: aws.Credentials{
801 AccessKeyID: "complete_creds_akid",
802 SecretAccessKey: "complete_creds_secret",
803 Source: fmt.Sprintf("SharedConfigCredentials: %s", filename),
804 },
805 },
806 },
807 "profile with complete creds and token": {
808 Profile: "profile complete_creds_with_token",
809 Expected: SharedConfig{
810 Credentials: aws.Credentials{
811 AccessKeyID: "complete_creds_with_token_akid",
812 SecretAccessKey: "complete_creds_with_token_secret",
813 SessionToken: "complete_creds_with_token_token",
814 Source: fmt.Sprintf("SharedConfigCredentials: %s", filename),
815 },
816 },
817 },
818 "complete profile": {
819 Profile: "profile full_profile",
820 Expected: SharedConfig{
821 Credentials: aws.Credentials{
822 AccessKeyID: "full_profile_akid",
823 SecretAccessKey: "full_profile_secret",
824 Source: fmt.Sprintf("SharedConfigCredentials: %s", filename),
825 },
826 Region: "full_profile_region",
827 },
828 },
829 "profile with partial assume role": {
830 Profile: "profile partial_assume_role",
831 Expected: SharedConfig{
832 RoleARN: "partial_assume_role_role_arn",
833 },
834 },
835 "profile using assume role": {
836 Profile: "profile assume_role",
837 Expected: SharedConfig{
838 RoleARN: "assume_role_role_arn",
839 SourceProfileName: "complete_creds",
840 },
841 },
842 "profile with assume role and MFA": {
843 Profile: "profile assume_role_w_mfa",
844 Expected: SharedConfig{
845 RoleARN: "assume_role_role_arn",
846 SourceProfileName: "complete_creds",
847 MFASerial: "0123456789",
848 },
849 },
850 "does not exist": {
851 Profile: "does_not_exist",
852 Err: SharedConfigProfileNotExistError{
853 Filename: []string{filename},
854 Profile: "does_not_exist",
855 Err: nil,
856 },
857 },
858 "profile with mixed casing": {
859 Profile: "profile with_mixed_case_keys",
860 Expected: SharedConfig{
861 Credentials: aws.Credentials{
862 AccessKeyID: "accessKey",
863 SecretAccessKey: "secret",
864 Source: fmt.Sprintf("SharedConfigCredentials: %s", filename),
865 },
866 },
867 },
868 }
869
870 for name, c := range cases {
871 t.Run(name, func(t *testing.T) {
872 var cfg SharedConfig
873
874 section, ok := sections.GetSection(c.Profile)
875 if !ok {
876 if c.Err == nil {
877 t.Fatalf("expected section to be present, was not")
878 } else {
879 if e, a := c.Err.Error(), "failed to get shared config profile"; !strings.Contains(e, a) {
880 t.Fatalf("expect %q to be in %q", a, e)
881 }
882 return
883 }
884 }
885
886 err := cfg.setFromIniSection(c.Profile, section)
887 if c.Err != nil {
888 if e, a := c.Err.Error(), err.Error(); !strings.Contains(a, e) {
889 t.Errorf("expect %q to be in %q", e, a)
890 }
891 return
892 }
893 if err != nil {
894 t.Fatalf("expect no error, got %v", err)
895 }
896
897 if diff := cmpDiff(c.Expected, cfg); diff != "" {
898 t.Errorf("expect shared config match\n%s", diff)
899 }
900 })
901 }
902 }
903
904 func TestLoadSharedConfig(t *testing.T) {
905 origProf := defaultSharedConfigProfile
906 origConfigFiles := DefaultSharedConfigFiles
907 origCredentialFiles := DefaultSharedCredentialsFiles
908 defer func() {
909 defaultSharedConfigProfile = origProf
910 DefaultSharedConfigFiles = origConfigFiles
911 DefaultSharedCredentialsFiles = origCredentialFiles
912 }()
913
914 cases := []struct {
915 LoadOptionFn func(*LoadOptions) error
916 Files []string
917 Profile string
918 LoadFn func(context.Context, configs) (Config, error)
919 Expect SharedConfig
920 Err string
921 }{
922 {
923 LoadOptionFn: WithSharedConfigProfile("alt_profile_name"),
924 Files: []string{
925 filepath.Join("testdata", "shared_config"),
926 },
927 LoadFn: loadSharedConfig,
928 Expect: SharedConfig{
929 Profile: "alt_profile_name",
930 Region: "alt_profile_name_region",
931 },
932 },
933 {
934 LoadOptionFn: WithSharedConfigFiles([]string{
935 filepath.Join("testdata", "shared_config"),
936 }),
937 Profile: "alt_profile_name",
938 LoadFn: loadSharedConfig,
939 Expect: SharedConfig{
940 Profile: "alt_profile_name",
941 Region: "alt_profile_name_region",
942 },
943 },
944 {
945 LoadOptionFn: WithSharedConfigProfile("default"),
946 Files: []string{
947 filepath.Join("file_not_exist"),
948 },
949 LoadFn: loadSharedConfig,
950 Err: "failed to get shared config profile",
951 },
952 {
953 LoadOptionFn: WithSharedConfigProfile("profile_not_exist"),
954 Files: []string{
955 filepath.Join("testdata", "shared_config"),
956 },
957 LoadFn: loadSharedConfig,
958 Err: "failed to get shared config profile",
959 },
960 {
961 LoadOptionFn: WithSharedConfigProfile("default"),
962 Files: []string{
963 filepath.Join("file_not_exist"),
964 },
965 LoadFn: loadSharedConfigIgnoreNotExist,
966 },
967 {
968 LoadOptionFn: WithSharedConfigProfile("assume_role_invalid_source_profile"),
969 Files: []string{
970 testConfigOtherFilename, testConfigFilename,
971 },
972 LoadFn: loadSharedConfig,
973 Err: "failed to get shared config profile",
974 },
975 {
976 LoadOptionFn: WithSharedConfigProfile("assume_role_invalid_source_profile"),
977 Files: []string{
978 testConfigOtherFilename, testConfigFilename,
979 },
980 LoadFn: loadSharedConfigIgnoreNotExist,
981 Err: "failed to get shared config profile",
982 },
983 }
984
985 for i, c := range cases {
986 t.Run(strconv.Itoa(i), func(t *testing.T) {
987 defaultSharedConfigProfile = origProf
988 DefaultSharedConfigFiles = origConfigFiles
989 DefaultSharedCredentialsFiles = origCredentialFiles
990
991 if len(c.Profile) > 0 {
992 defaultSharedConfigProfile = c.Profile
993 }
994 if len(c.Files) > 0 {
995 DefaultSharedConfigFiles = c.Files
996 }
997
998 DefaultSharedCredentialsFiles = []string{}
999
1000 var options LoadOptions
1001 c.LoadOptionFn(&options)
1002
1003 cfg, err := c.LoadFn(context.Background(), configs{options})
1004 if len(c.Err) > 0 {
1005 if err == nil {
1006 t.Fatalf("expected error %v, got none", c.Err)
1007 }
1008 if e, a := c.Err, err.Error(); !strings.Contains(a, e) {
1009 t.Fatalf("expect %q to be in %q", e, a)
1010 }
1011 return
1012 } else if err != nil {
1013 t.Fatalf("expect no error, got %v", err)
1014 }
1015
1016 if e, a := c.Expect, cfg; !reflect.DeepEqual(e, a) {
1017 t.Errorf("expect %v got %v", e, a)
1018 }
1019 })
1020 }
1021 }
1022
1023 func TestSharedConfigLoading(t *testing.T) {
1024
1025 var loggerBuf bytes.Buffer
1026 logger := logging.NewStandardLogger(&loggerBuf)
1027
1028 cases := map[string]struct {
1029 LoadOptionFns []func(*LoadOptions) error
1030 LoadFn func(context.Context, configs) (Config, error)
1031 Expect SharedConfig
1032 ExpectLog string
1033 Err string
1034 }{
1035 "duplicate profiles in the configuration files": {
1036 LoadOptionFns: []func(*LoadOptions) error{
1037 WithSharedConfigProfile("duplicate-profile"),
1038 WithSharedConfigFiles([]string{filepath.Join("testdata", "load_config")}),
1039 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1040 WithLogConfigurationWarnings(true),
1041 WithLogger(logger),
1042 },
1043 LoadFn: loadSharedConfig,
1044 Expect: SharedConfig{
1045 Profile: "duplicate-profile",
1046 Region: "us-west-2",
1047 },
1048 ExpectLog: "For profile: profile duplicate-profile, overriding region value, with a region value found in a " +
1049 "duplicate profile defined later in the same file",
1050 },
1051
1052 "profile prefix not used in the configuration files": {
1053 LoadOptionFns: []func(*LoadOptions) error{
1054 WithSharedConfigProfile("no-such-profile"),
1055 WithSharedConfigFiles([]string{filepath.Join("testdata", "load_config")}),
1056 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1057 WithLogConfigurationWarnings(true),
1058 WithLogger(logger),
1059 },
1060 LoadFn: loadSharedConfig,
1061 Expect: SharedConfig{},
1062 Err: "failed to get shared config profile",
1063 },
1064
1065 "profile prefix overrides default": {
1066 LoadOptionFns: []func(*LoadOptions) error{
1067 WithSharedConfigFiles([]string{filepath.Join("testdata", "load_config")}),
1068 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1069 WithLogConfigurationWarnings(true),
1070 WithLogger(logger),
1071 },
1072 LoadFn: loadSharedConfig,
1073 Expect: SharedConfig{
1074 Profile: "default",
1075 Region: "ap-north-1",
1076 },
1077 ExpectLog: "non-default profile not prefixed with `profile `",
1078 },
1079
1080 "duplicate profiles in credentials file": {
1081 LoadOptionFns: []func(*LoadOptions) error{
1082 WithSharedConfigProfile("duplicate-profile"),
1083 WithSharedConfigFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1084 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "load_credentials")}),
1085 WithLogConfigurationWarnings(true),
1086 WithLogger(logger),
1087 },
1088 LoadFn: loadSharedConfig,
1089 Expect: SharedConfig{
1090 Profile: "duplicate-profile",
1091 Region: "us-west-2",
1092 },
1093 ExpectLog: "overriding region value, with a region value found in a duplicate profile defined later in the same file",
1094 Err: "",
1095 },
1096
1097 "profile prefix used in credentials files": {
1098 LoadOptionFns: []func(*LoadOptions) error{
1099 WithSharedConfigProfile("unused-profile"),
1100 WithSharedConfigFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1101 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "load_credentials")}),
1102 WithLogConfigurationWarnings(true),
1103 WithLogger(logger),
1104 },
1105 LoadFn: loadSharedConfig,
1106 ExpectLog: "profile defined with name `profile unused-profile` is ignored.",
1107 Err: "failed to get shared config profile, unused-profile",
1108 },
1109 "partial credentials in configuration files": {
1110 LoadOptionFns: []func(*LoadOptions) error{
1111 WithSharedConfigProfile("partial-creds-1"),
1112 WithSharedConfigFiles([]string{filepath.Join("testdata", "load_config")}),
1113 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1114 WithLogConfigurationWarnings(true),
1115 WithLogger(logger),
1116 },
1117 LoadFn: loadSharedConfig,
1118 Expect: SharedConfig{
1119 Profile: "partial-creds-1",
1120 },
1121 Err: "partial credentials",
1122 },
1123 "parital credentials in the credentials files": {
1124 LoadOptionFns: []func(*LoadOptions) error{
1125 WithSharedConfigProfile("partial-creds-1"),
1126 WithSharedConfigFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1127 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "load_credentials")}),
1128 WithLogConfigurationWarnings(true),
1129 WithLogger(logger),
1130 },
1131 LoadFn: loadSharedConfig,
1132 Expect: SharedConfig{
1133 Profile: "partial-creds-1",
1134 },
1135 Err: "partial credentials found for profile partial-creds-1",
1136 },
1137 "credentials override configuration profile": {
1138 LoadOptionFns: []func(*LoadOptions) error{
1139 WithSharedConfigProfile("complete"),
1140 WithSharedConfigFiles([]string{filepath.Join("testdata", "load_config")}),
1141 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "load_credentials")}),
1142 WithLogConfigurationWarnings(true),
1143 WithLogger(logger),
1144 },
1145 LoadFn: loadSharedConfig,
1146 Expect: SharedConfig{
1147 Profile: "complete",
1148 Credentials: aws.Credentials{
1149 AccessKeyID: "credsAccessKey",
1150 SecretAccessKey: "credsSecretKey",
1151 Source: fmt.Sprintf("SharedConfigCredentials: %v",
1152 filepath.Join("testdata", "load_credentials")),
1153 },
1154 Region: "us-west-2",
1155 },
1156 },
1157 "credentials profile has complete credentials": {
1158 LoadOptionFns: []func(*LoadOptions) error{
1159 WithSharedConfigProfile("complete"),
1160 WithSharedConfigFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1161 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "load_credentials")}),
1162 WithLogConfigurationWarnings(true),
1163 WithLogger(logger),
1164 },
1165 LoadFn: loadSharedConfig,
1166 Expect: SharedConfig{
1167 Profile: "complete",
1168 Credentials: aws.Credentials{
1169 AccessKeyID: "credsAccessKey",
1170 SecretAccessKey: "credsSecretKey",
1171 Source: fmt.Sprintf("SharedConfigCredentials: %v", filepath.Join("testdata", "load_credentials")),
1172 },
1173 },
1174 },
1175 "credentials split between multiple credentials files": {
1176 LoadOptionFns: []func(*LoadOptions) error{
1177 WithSharedConfigProfile("partial-creds-1"),
1178 WithSharedConfigFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1179 WithSharedCredentialsFiles([]string{
1180 filepath.Join("testdata", "load_credentials"),
1181 filepath.Join("testdata", "load_credentials_secondary"),
1182 }),
1183 WithLogConfigurationWarnings(true),
1184 WithLogger(logger),
1185 },
1186 LoadFn: loadSharedConfig,
1187 Expect: SharedConfig{
1188 Profile: "partial-creds-1",
1189 },
1190 Err: "partial credentials",
1191 },
1192 "credentials split between multiple configuration files": {
1193 LoadOptionFns: []func(*LoadOptions) error{
1194 WithSharedConfigProfile("partial-creds-1"),
1195 WithSharedCredentialsFiles([]string{filepath.Join("testdata", "empty_creds_config")}),
1196 WithSharedConfigFiles([]string{
1197 filepath.Join("testdata", "load_config"),
1198 filepath.Join("testdata", "load_config_secondary"),
1199 }),
1200 WithLogConfigurationWarnings(true),
1201 WithLogger(logger),
1202 },
1203 LoadFn: loadSharedConfig,
1204 Expect: SharedConfig{
1205 Profile: "partial-creds-1",
1206 Region: "us-west-2",
1207 },
1208 ExpectLog: "",
1209 Err: "partial credentials",
1210 },
1211 "credentials split between credentials and config files": {
1212 LoadOptionFns: []func(*LoadOptions) error{
1213 WithSharedConfigProfile("partial-creds-1"),
1214 WithSharedConfigFiles([]string{
1215 filepath.Join("testdata", "load_config"),
1216 }),
1217 WithSharedCredentialsFiles([]string{
1218 filepath.Join("testdata", "load_credentials"),
1219 }),
1220 WithLogConfigurationWarnings(true),
1221 WithLogger(logger),
1222 },
1223 LoadFn: loadSharedConfig,
1224 Expect: SharedConfig{
1225 Profile: "partial-creds-1",
1226 },
1227 ExpectLog: "",
1228 Err: "partial credentials",
1229 },
1230 "replaced profile with prefixed profile in config files": {
1231 LoadOptionFns: []func(*LoadOptions) error{
1232 WithSharedConfigProfile("replaced-profile"),
1233 WithSharedConfigFiles([]string{
1234 filepath.Join("testdata", "load_config"),
1235 }),
1236 WithSharedCredentialsFiles([]string{
1237 filepath.Join("testdata", "empty_creds_config"),
1238 }),
1239 WithLogConfigurationWarnings(true),
1240 WithLogger(logger),
1241 },
1242 LoadFn: loadSharedConfig,
1243 Expect: SharedConfig{
1244 Profile: "replaced-profile",
1245 Region: "eu-west-1",
1246 },
1247 ExpectLog: "non-default profile not prefixed with `profile `",
1248 },
1249 "replaced profile with prefixed profile in credentials files": {
1250 LoadOptionFns: []func(*LoadOptions) error{
1251 WithSharedConfigProfile("replaced-profile"),
1252 WithSharedCredentialsFiles([]string{
1253 filepath.Join("testdata", "load_credentials"),
1254 }),
1255 WithSharedConfigFiles([]string{
1256 filepath.Join("testdata", "empty_creds_config"),
1257 }),
1258 WithLogConfigurationWarnings(true),
1259 WithLogger(logger),
1260 },
1261 LoadFn: loadSharedConfig,
1262 Expect: SharedConfig{
1263 Profile: "replaced-profile",
1264 Region: "us-west-2",
1265 },
1266 ExpectLog: "profile defined with name `profile replaced-profile` is ignored.",
1267 },
1268 "ignored profiles w/o prefixed profile across credentials and config files": {
1269 LoadOptionFns: []func(*LoadOptions) error{
1270 WithSharedConfigProfile("replaced-profile"),
1271 WithSharedCredentialsFiles([]string{
1272 filepath.Join("testdata", "load_credentials"),
1273 }),
1274 WithSharedConfigFiles([]string{
1275 filepath.Join("testdata", "load_config"),
1276 }),
1277 WithLogConfigurationWarnings(true),
1278 WithLogger(logger),
1279 },
1280 LoadFn: loadSharedConfig,
1281 Expect: SharedConfig{
1282 Profile: "replaced-profile",
1283 Region: "us-west-2",
1284 },
1285 ExpectLog: "profile defined with name `profile replaced-profile` is ignored.",
1286 },
1287 "1. profile with name as `profile` in config file": {
1288 LoadOptionFns: []func(*LoadOptions) error{
1289 WithSharedConfigProfile("profile"),
1290 WithSharedCredentialsFiles([]string{
1291 filepath.Join("testdata", "empty_creds_config"),
1292 }),
1293 WithSharedConfigFiles([]string{
1294 filepath.Join("testdata", "load_config"),
1295 }),
1296 WithLogConfigurationWarnings(true),
1297 WithLogger(logger),
1298 },
1299 LoadFn: loadSharedConfig,
1300 Err: "failed to get shared config profile, profile",
1301 ExpectLog: "profile defined with name `profile` is ignored",
1302 },
1303 "2. profile with name as `profile ` in config file": {
1304 LoadOptionFns: []func(*LoadOptions) error{
1305 WithSharedConfigProfile("profile "),
1306 WithSharedCredentialsFiles([]string{
1307 filepath.Join("testdata", "empty_creds_config"),
1308 }),
1309 WithSharedConfigFiles([]string{
1310 filepath.Join("testdata", "load_config"),
1311 }),
1312 WithLogConfigurationWarnings(true),
1313 WithLogger(logger),
1314 },
1315 LoadFn: loadSharedConfig,
1316 Err: "failed to get shared config profile, profile",
1317 ExpectLog: "profile defined with name `profile` is ignored",
1318 },
1319 "3. profile with name as `profile\t` in config file": {
1320 LoadOptionFns: []func(*LoadOptions) error{
1321 WithSharedConfigProfile("profile"),
1322 WithSharedCredentialsFiles([]string{
1323 filepath.Join("testdata", "empty_creds_config"),
1324 }),
1325 WithSharedConfigFiles([]string{
1326 filepath.Join("testdata", "load_config"),
1327 }),
1328 WithLogConfigurationWarnings(true),
1329 WithLogger(logger),
1330 },
1331 LoadFn: loadSharedConfig,
1332 Err: "failed to get shared config profile, profile",
1333 ExpectLog: "profile defined with name `profile` is ignored",
1334 },
1335 "profile with tabs as delimiter for profile prefix in config file": {
1336 LoadOptionFns: []func(*LoadOptions) error{
1337 WithSharedConfigProfile("with-tab"),
1338 WithSharedCredentialsFiles([]string{
1339 filepath.Join("testdata", "empty_creds_config"),
1340 }),
1341 WithSharedConfigFiles([]string{
1342 filepath.Join("testdata", "load_config"),
1343 }),
1344 WithLogConfigurationWarnings(true),
1345 WithLogger(logger),
1346 },
1347 LoadFn: loadSharedConfig,
1348 Expect: SharedConfig{
1349 Profile: "with-tab",
1350 Region: "cn-north-1",
1351 },
1352 },
1353 "profile with tabs as delimiter for profile prefix in credentials file": {
1354 LoadOptionFns: []func(*LoadOptions) error{
1355 WithSharedConfigProfile("with-tab"),
1356 WithSharedCredentialsFiles([]string{
1357 filepath.Join("testdata", "load_credentials"),
1358 }),
1359 WithSharedConfigFiles([]string{
1360 filepath.Join("testdata", "empty_creds_config"),
1361 }),
1362 WithLogConfigurationWarnings(true),
1363 WithLogger(logger),
1364 },
1365 LoadFn: loadSharedConfig,
1366 Err: "failed to get shared config profile, with-tab",
1367 ExpectLog: "profile defined with name `profile with-tab` is ignored",
1368 },
1369 "profile with name as `profile profile` in credentials file": {
1370 LoadOptionFns: []func(*LoadOptions) error{
1371 WithSharedConfigProfile("profile"),
1372 WithSharedCredentialsFiles([]string{
1373 filepath.Join("testdata", "load_credentials"),
1374 }),
1375 WithSharedConfigFiles([]string{
1376 filepath.Join("testdata", "empty_creds_config"),
1377 }),
1378 WithLogConfigurationWarnings(true),
1379 WithLogger(logger),
1380 },
1381 LoadFn: loadSharedConfig,
1382 Err: "failed to get shared config profile, profile",
1383 ExpectLog: "profile defined with name `profile profile` is ignored",
1384 },
1385 "profile with name profile-bar in credentials file": {
1386 LoadOptionFns: []func(*LoadOptions) error{
1387 WithSharedConfigProfile("profile-bar"),
1388 WithSharedCredentialsFiles([]string{
1389 filepath.Join("testdata", "load_credentials"),
1390 }),
1391 WithSharedConfigFiles([]string{
1392 filepath.Join("testdata", "empty_creds_config"),
1393 }),
1394 WithLogConfigurationWarnings(true),
1395 WithLogger(logger),
1396 },
1397 LoadFn: loadSharedConfig,
1398 Expect: SharedConfig{
1399 Profile: "profile-bar",
1400 Region: "us-west-2",
1401 },
1402 },
1403 "profile with name profile-bar in config file": {
1404 LoadOptionFns: []func(*LoadOptions) error{
1405 WithSharedConfigProfile("profile-bar"),
1406 WithSharedCredentialsFiles([]string{
1407 filepath.Join("testdata", "empty_creds_config"),
1408 }),
1409 WithSharedConfigFiles([]string{
1410 filepath.Join("testdata", "load_config"),
1411 }),
1412 WithLogConfigurationWarnings(true),
1413 WithLogger(logger),
1414 },
1415 LoadFn: loadSharedConfig,
1416 Err: "failed to get shared config profile, profile-bar",
1417 ExpectLog: "profile defined with name `profile-bar` is ignored",
1418 },
1419 "profile ignored in credentials and config file": {
1420 LoadOptionFns: []func(*LoadOptions) error{
1421 WithSharedConfigProfile("ignored-profile"),
1422 WithSharedCredentialsFiles([]string{
1423 filepath.Join("testdata", "load_credentials"),
1424 }),
1425 WithSharedConfigFiles([]string{
1426 filepath.Join("testdata", "load_config"),
1427 }),
1428 WithLogConfigurationWarnings(true),
1429 WithLogger(logger),
1430 },
1431 LoadFn: loadSharedConfig,
1432 Err: "failed to get shared config profile, ignored-profile",
1433 ExpectLog: "profile defined with name `ignored-profile` is ignored.",
1434 },
1435 "profile with sso_session": {
1436 LoadOptionFns: []func(*LoadOptions) error{
1437 WithSharedConfigProfile("sso-session-test"),
1438 WithSharedCredentialsFiles([]string{
1439 filepath.Join("testdata", "load_credentials"),
1440 }),
1441 WithSharedConfigFiles([]string{
1442 filepath.Join("testdata", "load_config"),
1443 }),
1444 WithLogConfigurationWarnings(true),
1445 WithLogger(logger),
1446 },
1447 LoadFn: loadSharedConfig,
1448 Expect: SharedConfig{
1449 Profile: "sso-session-test",
1450 SSOSessionName: "dev-session",
1451 SSOSession: &SSOSession{
1452 Name: "dev-session",
1453 SSORegion: "us-west-2",
1454 SSOStartURL: "https://example.aws/start",
1455 },
1456 },
1457 },
1458 "config and creds files explicitly set to empty slice": {
1459 LoadOptionFns: []func(*LoadOptions) error{
1460 WithSharedCredentialsFiles([]string{}),
1461 WithSharedConfigFiles([]string{}),
1462 WithLogConfigurationWarnings(true),
1463 WithLogger(logger),
1464 },
1465 LoadFn: loadSharedConfig,
1466 Err: "failed to get shared config profile, default",
1467 },
1468 }
1469
1470 for name, c := range cases {
1471 t.Run(name, func(t *testing.T) {
1472 defer loggerBuf.Reset()
1473
1474 var options LoadOptions
1475
1476 for _, fn := range c.LoadOptionFns {
1477 fn(&options)
1478 }
1479
1480 cfg, err := c.LoadFn(context.Background(), configs{options})
1481
1482 if e, a := c.ExpectLog, loggerBuf.String(); !strings.Contains(a, e) {
1483 t.Errorf("expect %v logged in %v", e, a)
1484 }
1485 if loggerBuf.Len() == 0 && len(c.ExpectLog) != 0 {
1486 t.Errorf("expected log, got none")
1487 }
1488
1489 if len(c.Err) > 0 {
1490 if err == nil {
1491 t.Fatalf("expected error %v, got none", c.Err)
1492 }
1493 if e, a := c.Err, err.Error(); !strings.Contains(a, e) {
1494 t.Fatalf("expect %q to be in %q", e, a)
1495 }
1496 return
1497 } else if err != nil {
1498 t.Fatalf("expect no error, got %v", err)
1499 }
1500
1501 if diff := cmpDiff(c.Expect, cfg); diff != "" {
1502 t.Errorf("expect shared config match\n%s", diff)
1503 }
1504 })
1505 }
1506 }
1507
View as plain text