@@ -27,6 +27,12 @@ const FOO_CREDS = {
27
27
sessionToken : 'baz' ,
28
28
} ;
29
29
30
+ const FIZZ_CREDS = {
31
+ accessKeyId : 'fizz' ,
32
+ secretAccessKey : 'buzz' ,
33
+ sessionToken : 'pop' ,
34
+ } ;
35
+
30
36
const envAtLoadTime : { [ key : string ] : string } = [
31
37
ENV_CONFIG_PATH ,
32
38
ENV_CREDENTIALS_PATH ,
@@ -55,13 +61,11 @@ afterAll(() => {
55
61
} ) ;
56
62
57
63
describe ( 'fromIni' , ( ) => {
58
- it ( 'should flag a lack of credentials as a non-terminal error' , async ( ) => {
59
- await fromIni ( ) ( ) . then (
60
- ( ) => { throw new Error ( 'The promise should have been rejected.' ) ; } ,
61
- err => {
62
- expect ( ( err as CredentialError ) . tryNextLink ) . toBe ( true ) ;
63
- }
64
- ) ;
64
+ it ( 'should flag a lack of credentials as a non-terminal error' , ( ) => {
65
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
66
+ message : 'Profile default could not be found or parsed in shared credentials file.' ,
67
+ tryNextLink : true ,
68
+ } ) ;
65
69
} ) ;
66
70
67
71
describe ( 'shared credentials file' , ( ) => {
@@ -475,7 +479,7 @@ source_profile = default`.trim()
475
479
476
480
it (
477
481
'should reject the promise with a terminal error if no role assumer provided' ,
478
- async ( ) => {
482
+ ( ) => {
479
483
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
480
484
[default]
481
485
aws_access_key_id = ${ DEFAULT_CREDS . accessKeyId }
@@ -487,18 +491,16 @@ role_arn = arn:aws:iam::123456789:role/foo
487
491
source_profile = bar` . trim ( )
488
492
) ;
489
493
490
- await fromIni ( { profile : 'foo' } ) ( ) . then (
491
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
492
- err => {
493
- expect ( ( err as any ) . tryNextLink ) . toBeFalsy ( ) ;
494
- }
495
- ) ;
494
+ return expect ( fromIni ( { profile : 'foo' } ) ( ) ) . rejects . toMatchObject ( {
495
+ message : 'Profile foo requires a role to be assumed, but no role assumption callback was provided.' ,
496
+ tryNextLink : false ,
497
+ } ) ;
496
498
}
497
499
) ;
498
500
499
501
it (
500
502
'should reject the promise if the source profile cannot be found' ,
501
- async ( ) => {
503
+ ( ) => {
502
504
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
503
505
[default]
504
506
aws_access_key_id = ${ DEFAULT_CREDS . accessKeyId }
@@ -510,10 +512,15 @@ role_arn = arn:aws:iam::123456789:role/foo
510
512
source_profile = bar` . trim ( )
511
513
) ;
512
514
513
- await fromIni ( { profile : 'foo' } ) ( ) . then (
514
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
515
- ( ) => { /* Promise rejected as expected */ }
516
- ) ;
515
+ const provider = fromIni ( {
516
+ profile : 'foo' ,
517
+ roleAssumer : jest . fn ( )
518
+ } ) ;
519
+
520
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
521
+ message : 'Profile bar could not be found or parsed in shared credentials file.' ,
522
+ tryNextLink : false ,
523
+ } ) ;
517
524
}
518
525
) ;
519
526
@@ -692,7 +699,7 @@ source_profile = default`.trim()
692
699
693
700
it (
694
701
'should reject the promise with a terminal error if a MFA serial is present but no mfaCodeProvider was provided' ,
695
- async ( ) => {
702
+ ( ) => {
696
703
const roleArn = 'arn:aws:iam::123456789:role/foo' ;
697
704
const mfaSerial = 'mfaSerial' ;
698
705
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
@@ -712,12 +719,10 @@ source_profile = default`.trim()
712
719
roleAssumer : ( ) => Promise . resolve ( FOO_CREDS ) ,
713
720
} ) ;
714
721
715
- await provider ( ) . then (
716
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
717
- err => {
718
- expect ( ( err as any ) . tryNextLink ) . toBeFalsy ( ) ;
719
- }
720
- ) ;
722
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
723
+ message : 'Profile foo requires multi-factor authentication, but no MFA code callback was provided.' ,
724
+ tryNextLink : false ,
725
+ } ) ;
721
726
}
722
727
) ;
723
728
} ) ;
@@ -741,31 +746,31 @@ aws_session_token = ${FOO_CREDS.sessionToken}`.trim());
741
746
}
742
747
) ;
743
748
744
- it ( 'should reject credentials with no access key' , async ( ) => {
749
+ it ( 'should reject credentials with no access key' , ( ) => {
745
750
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
746
751
[default]
747
752
aws_secret_access_key = ${ DEFAULT_CREDS . secretAccessKey }
748
753
` . trim ( ) ) ;
749
754
750
- await fromIni ( ) ( ) . then (
751
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
752
- ( ) => { /* Promise rejected as expected */ }
753
- ) ;
755
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
756
+ message : 'Profile default could not be found or parsed in shared credentials file.' ,
757
+ tryNextLink : true ,
758
+ } ) ;
754
759
} ) ;
755
760
756
- it ( 'should reject credentials with no secret key' , async ( ) => {
761
+ it ( 'should reject credentials with no secret key' , ( ) => {
757
762
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
758
763
[default]
759
764
aws_access_key_id = ${ DEFAULT_CREDS . accessKeyId }
760
765
` . trim ( ) ) ;
761
766
762
- await fromIni ( ) ( ) . then (
763
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
764
- ( ) => { /* Promise rejected as expected */ }
765
- ) ;
767
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
768
+ message : 'Profile default could not be found or parsed in shared credentials file.' ,
769
+ tryNextLink : true ,
770
+ } ) ;
766
771
} ) ;
767
772
768
- it ( 'should not merge profile values together' , async ( ) => {
773
+ it ( 'should not merge profile values together' , ( ) => {
769
774
__addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
770
775
[default]
771
776
aws_access_key_id = ${ DEFAULT_CREDS . accessKeyId }
@@ -776,9 +781,76 @@ aws_access_key_id = ${DEFAULT_CREDS.accessKeyId}
776
781
aws_secret_access_key = ${ FOO_CREDS . secretAccessKey }
777
782
` . trim ( ) ) ;
778
783
779
- await fromIni ( ) ( ) . then (
780
- ( ) => { throw new Error ( 'The promise should have been rejected' ) ; } ,
781
- ( ) => { /* Promise rejected as expected */ }
782
- ) ;
784
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
785
+ message : 'Profile default could not be found or parsed in shared credentials file.' ,
786
+ tryNextLink : true ,
787
+ } ) ;
783
788
} ) ;
789
+
790
+ it (
791
+ 'should treat a profile with static credentials and role assumption keys as an assume role profile' ,
792
+ ( ) => {
793
+ __addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
794
+ [default]
795
+ aws_secret_access_key = ${ DEFAULT_CREDS . secretAccessKey }
796
+ aws_secret_access_key = ${ DEFAULT_CREDS . secretAccessKey }
797
+ role_arn = foo
798
+ source_profile = foo
799
+
800
+ [foo]
801
+ aws_access_key_id = ${ FOO_CREDS . accessKeyId }
802
+ aws_secret_access_key = ${ FOO_CREDS . secretAccessKey }
803
+ aws_session_token = ${ FOO_CREDS . sessionToken }
804
+ ` . trim ( ) ) ;
805
+
806
+ const provider = fromIni ( {
807
+ roleAssumer (
808
+ sourceCreds : Credentials ,
809
+ params : AssumeRoleParams
810
+ ) : Promise < Credentials > {
811
+ expect ( sourceCreds ) . toEqual ( FOO_CREDS ) ;
812
+ expect ( params . RoleArn ) . toEqual ( 'foo' ) ;
813
+
814
+ return Promise . resolve ( FIZZ_CREDS ) ;
815
+ }
816
+ } ) ;
817
+
818
+ return expect ( provider ( ) ) . resolves . toEqual ( FIZZ_CREDS ) ;
819
+ }
820
+ ) ;
821
+
822
+ it (
823
+ 'should reject credentials when profile role assumption creates a cycle' ,
824
+ ( ) => {
825
+ __addMatcher ( join ( homedir ( ) , '.aws' , 'credentials' ) , `
826
+ [default]
827
+ role_arn = foo
828
+ source_profile = foo
829
+
830
+ [bar]
831
+ role_arn = baz
832
+ source_profile = baz
833
+
834
+ [fizz]
835
+ role_arn = buzz
836
+ source_profile = foo
837
+ ` . trim ( ) ) ;
838
+
839
+ __addMatcher ( join ( homedir ( ) , '.aws' , 'config' ) , `
840
+ [profile foo]
841
+ role_arn = bar
842
+ source_profile = bar
843
+
844
+ [profile baz]
845
+ role_arn = fizz
846
+ source_profile = fizz
847
+ ` . trim ( ) ) ;
848
+ const provider = fromIni ( { roleAssumer : jest . fn ( ) } ) ;
849
+
850
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
851
+ message : 'Detected a cycle attempting to resolve credentials for profile default. Profiles visited: foo, bar, baz, fizz' ,
852
+ tryNextLink : false ,
853
+ } ) ;
854
+ }
855
+ ) ;
784
856
} ) ;
0 commit comments