@@ -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,15 +61,12 @@ 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
- ( ) => {
61
- throw new Error ( "The promise should have been rejected." ) ;
62
- } ,
63
- err => {
64
- expect ( ( err as CredentialError ) . tryNextLink ) . toBe ( true ) ;
65
- }
66
- ) ;
64
+ it ( "should flag a lack of credentials as a non-terminal error" , ( ) => {
65
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
66
+ message :
67
+ "Profile default could not be found or parsed in shared credentials file." ,
68
+ tryNextLink : true
69
+ } ) ;
67
70
} ) ;
68
71
69
72
describe ( "shared credentials file" , ( ) => {
@@ -491,7 +494,7 @@ source_profile = default`.trim()
491
494
expect ( await provider ( ) ) . toEqual ( FOO_CREDS ) ;
492
495
} ) ;
493
496
494
- it ( "should reject the promise with a terminal error if no role assumer provided" , async ( ) => {
497
+ it ( "should reject the promise with a terminal error if no role assumer provided" , ( ) => {
495
498
__addMatcher (
496
499
join ( homedir ( ) , ".aws" , "credentials" ) ,
497
500
`
@@ -505,17 +508,14 @@ role_arn = arn:aws:iam::123456789:role/foo
505
508
source_profile = bar` . trim ( )
506
509
) ;
507
510
508
- await fromIni ( { profile : "foo" } ) ( ) . then (
509
- ( ) => {
510
- throw new Error ( "The promise should have been rejected" ) ;
511
- } ,
512
- err => {
513
- expect ( ( err as any ) . tryNextLink ) . toBeFalsy ( ) ;
514
- }
515
- ) ;
511
+ return expect ( fromIni ( { profile : "foo" } ) ( ) ) . rejects . toMatchObject ( {
512
+ message :
513
+ "Profile foo requires a role to be assumed, but no role assumption callback was provided." ,
514
+ tryNextLink : false
515
+ } ) ;
516
516
} ) ;
517
517
518
- it ( "should reject the promise if the source profile cannot be found" , async ( ) => {
518
+ it ( "should reject the promise if the source profile cannot be found" , ( ) => {
519
519
__addMatcher (
520
520
join ( homedir ( ) , ".aws" , "credentials" ) ,
521
521
`
@@ -529,14 +529,16 @@ role_arn = arn:aws:iam::123456789:role/foo
529
529
source_profile = bar` . trim ( )
530
530
) ;
531
531
532
- await fromIni ( { profile : "foo" } ) ( ) . then (
533
- ( ) => {
534
- throw new Error ( "The promise should have been rejected" ) ;
535
- } ,
536
- ( ) => {
537
- /* Promise rejected as expected */
538
- }
539
- ) ;
532
+ const provider = fromIni ( {
533
+ profile : "foo" ,
534
+ roleAssumer : jest . fn ( )
535
+ } ) ;
536
+
537
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
538
+ message :
539
+ "Profile bar could not be found or parsed in shared credentials file." ,
540
+ tryNextLink : false
541
+ } ) ;
540
542
} ) ;
541
543
542
544
it ( "should allow a profile in ~/.aws/credentials to use a source profile from ~/.aws/config" , async ( ) => {
@@ -716,7 +718,7 @@ source_profile = default`.trim()
716
718
expect ( await provider ( ) ) . toEqual ( FOO_CREDS ) ;
717
719
} ) ;
718
720
719
- it ( "should reject the promise with a terminal error if a MFA serial is present but no mfaCodeProvider was provided" , async ( ) => {
721
+ it ( "should reject the promise with a terminal error if a MFA serial is present but no mfaCodeProvider was provided" , ( ) => {
720
722
const roleArn = "arn:aws:iam::123456789:role/foo" ;
721
723
const mfaSerial = "mfaSerial" ;
722
724
__addMatcher (
@@ -738,14 +740,11 @@ source_profile = default`.trim()
738
740
roleAssumer : ( ) => Promise . resolve ( FOO_CREDS )
739
741
} ) ;
740
742
741
- await provider ( ) . then (
742
- ( ) => {
743
- throw new Error ( "The promise should have been rejected" ) ;
744
- } ,
745
- err => {
746
- expect ( ( err as any ) . tryNextLink ) . toBeFalsy ( ) ;
747
- }
748
- ) ;
743
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
744
+ message :
745
+ "Profile foo requires multi-factor authentication, but no MFA code callback was provided." ,
746
+ tryNextLink : false
747
+ } ) ;
749
748
} ) ;
750
749
} ) ;
751
750
@@ -771,7 +770,7 @@ aws_session_token = ${FOO_CREDS.sessionToken}`.trim()
771
770
expect ( await fromIni ( ) ( ) ) . toEqual ( DEFAULT_CREDS ) ;
772
771
} ) ;
773
772
774
- it ( "should reject credentials with no access key" , async ( ) => {
773
+ it ( "should reject credentials with no access key" , ( ) => {
775
774
__addMatcher (
776
775
join ( homedir ( ) , ".aws" , "credentials" ) ,
777
776
`
@@ -780,17 +779,14 @@ aws_secret_access_key = ${DEFAULT_CREDS.secretAccessKey}
780
779
` . trim ( )
781
780
) ;
782
781
783
- await fromIni ( ) ( ) . then (
784
- ( ) => {
785
- throw new Error ( "The promise should have been rejected" ) ;
786
- } ,
787
- ( ) => {
788
- /* Promise rejected as expected */
789
- }
790
- ) ;
782
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
783
+ message :
784
+ "Profile default could not be found or parsed in shared credentials file." ,
785
+ tryNextLink : true
786
+ } ) ;
791
787
} ) ;
792
788
793
- it ( "should reject credentials with no secret key" , async ( ) => {
789
+ it ( "should reject credentials with no secret key" , ( ) => {
794
790
__addMatcher (
795
791
join ( homedir ( ) , ".aws" , "credentials" ) ,
796
792
`
@@ -799,17 +795,14 @@ aws_access_key_id = ${DEFAULT_CREDS.accessKeyId}
799
795
` . trim ( )
800
796
) ;
801
797
802
- await fromIni ( ) ( ) . then (
803
- ( ) => {
804
- throw new Error ( "The promise should have been rejected" ) ;
805
- } ,
806
- ( ) => {
807
- /* Promise rejected as expected */
808
- }
809
- ) ;
798
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
799
+ message :
800
+ "Profile default could not be found or parsed in shared credentials file." ,
801
+ tryNextLink : true
802
+ } ) ;
810
803
} ) ;
811
804
812
- it ( "should not merge profile values together" , async ( ) => {
805
+ it ( "should not merge profile values together" , ( ) => {
813
806
__addMatcher (
814
807
join ( homedir ( ) , ".aws" , "credentials" ) ,
815
808
`
@@ -826,13 +819,81 @@ aws_secret_access_key = ${FOO_CREDS.secretAccessKey}
826
819
` . trim ( )
827
820
) ;
828
821
829
- await fromIni ( ) ( ) . then (
830
- ( ) => {
831
- throw new Error ( "The promise should have been rejected" ) ;
832
- } ,
833
- ( ) => {
834
- /* Promise rejected as expected */
822
+ return expect ( fromIni ( ) ( ) ) . rejects . toMatchObject ( {
823
+ message :
824
+ "Profile default could not be found or parsed in shared credentials file." ,
825
+ tryNextLink : true
826
+ } ) ;
827
+ } ) ;
828
+
829
+ it ( "should treat a profile with static credentials and role assumption keys as an assume role profile" , ( ) => {
830
+ __addMatcher (
831
+ join ( homedir ( ) , ".aws" , "credentials" ) ,
832
+ `
833
+ [default]
834
+ aws_secret_access_key = ${ DEFAULT_CREDS . secretAccessKey }
835
+ aws_secret_access_key = ${ DEFAULT_CREDS . secretAccessKey }
836
+ role_arn = foo
837
+ source_profile = foo
838
+
839
+ [foo]
840
+ aws_access_key_id = ${ FOO_CREDS . accessKeyId }
841
+ aws_secret_access_key = ${ FOO_CREDS . secretAccessKey }
842
+ aws_session_token = ${ FOO_CREDS . sessionToken }
843
+ ` . trim ( )
844
+ ) ;
845
+
846
+ const provider = fromIni ( {
847
+ roleAssumer (
848
+ sourceCreds : Credentials ,
849
+ params : AssumeRoleParams
850
+ ) : Promise < Credentials > {
851
+ expect ( sourceCreds ) . toEqual ( FOO_CREDS ) ;
852
+ expect ( params . RoleArn ) . toEqual ( "foo" ) ;
853
+
854
+ return Promise . resolve ( FIZZ_CREDS ) ;
835
855
}
856
+ } ) ;
857
+
858
+ return expect ( provider ( ) ) . resolves . toEqual ( FIZZ_CREDS ) ;
859
+ } ) ;
860
+
861
+ it ( "should reject credentials when profile role assumption creates a cycle" , ( ) => {
862
+ __addMatcher (
863
+ join ( homedir ( ) , ".aws" , "credentials" ) ,
864
+ `
865
+ [default]
866
+ role_arn = foo
867
+ source_profile = foo
868
+
869
+ [bar]
870
+ role_arn = baz
871
+ source_profile = baz
872
+
873
+ [fizz]
874
+ role_arn = buzz
875
+ source_profile = foo
876
+ ` . trim ( )
836
877
) ;
878
+
879
+ __addMatcher (
880
+ join ( homedir ( ) , ".aws" , "config" ) ,
881
+ `
882
+ [profile foo]
883
+ role_arn = bar
884
+ source_profile = bar
885
+
886
+ [profile baz]
887
+ role_arn = fizz
888
+ source_profile = fizz
889
+ ` . trim ( )
890
+ ) ;
891
+ const provider = fromIni ( { roleAssumer : jest . fn ( ) } ) ;
892
+
893
+ return expect ( provider ( ) ) . rejects . toMatchObject ( {
894
+ message :
895
+ "Detected a cycle attempting to resolve credentials for profile default. Profiles visited: foo, bar, baz, fizz" ,
896
+ tryNextLink : false
897
+ } ) ;
837
898
} ) ;
838
899
} ) ;
0 commit comments