Skip to content

Commit 6e6acf2

Browse files
committed
test: add unit tests
1 parent 0450508 commit 6e6acf2

File tree

4 files changed

+128
-11
lines changed

4 files changed

+128
-11
lines changed

packages/credential-provider-ini/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"dependencies": {
2424
"@aws-sdk/credential-provider-env": "3.20.0",
2525
"@aws-sdk/credential-provider-imds": "3.20.0",
26+
"@aws-sdk/credential-provider-sso": "3.21.0",
2627
"@aws-sdk/credential-provider-web-identity": "3.20.0",
2728
"@aws-sdk/property-provider": "3.20.0",
2829
"@aws-sdk/shared-ini-file-loader": "3.20.0",

packages/credential-provider-ini/src/index.spec.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { fromEnv } from "@aws-sdk/credential-provider-env";
22
import { fromContainerMetadata, fromInstanceMetadata } from "@aws-sdk/credential-provider-imds";
3+
import { fromSSO, isSsoProfile, validateSsoProfile } from "@aws-sdk/credential-provider-sso";
34
import { fromTokenFile } from "@aws-sdk/credential-provider-web-identity";
45
import { ENV_CONFIG_PATH, ENV_CREDENTIALS_PATH } from "@aws-sdk/shared-ini-file-loader";
56
import { Credentials } from "@aws-sdk/types";
@@ -61,6 +62,8 @@ jest.mock("@aws-sdk/credential-provider-imds");
6162

6263
jest.mock("@aws-sdk/credential-provider-env");
6364

65+
jest.mock("@aws-sdk/credential-provider-sso");
66+
6467
const DEFAULT_CREDS = {
6568
accessKeyId: "AKIAIOSFODNN7EXAMPLE",
6669
secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
@@ -989,6 +992,120 @@ role_arn = ${roleArn}`.trim()
989992
});
990993
});
991994

995+
describe("assume role with SSO", () => {
996+
const DEFAULT_PATH = join(homedir(), ".aws", "credentials");
997+
it("should continue if profile is not configured with an SSO credential", async () => {
998+
__addMatcher(
999+
DEFAULT_PATH,
1000+
`[default]
1001+
aws_access_key_id = ${DEFAULT_CREDS.accessKeyId}
1002+
aws_secret_access_key = ${DEFAULT_CREDS.secretAccessKey}
1003+
aws_session_token = ${DEFAULT_CREDS.sessionToken}
1004+
`.trim()
1005+
);
1006+
await fromIni()();
1007+
expect(fromSSO).not.toHaveBeenCalled();
1008+
});
1009+
1010+
it("should throw if profile is configured with incomplete SSO credential", async () => {
1011+
(isSsoProfile as unknown as jest.Mock).mockImplementationOnce(() => true);
1012+
const originalValidator = jest.requireActual("@aws-sdk/credential-provider-sso").validateSsoProfile;
1013+
(validateSsoProfile as unknown as jest.Mock).mockImplementationOnce(originalValidator);
1014+
__addMatcher(
1015+
DEFAULT_PATH,
1016+
`[default]
1017+
sso_account_id = 1234567890
1018+
sso_start_url = https://example.com/sso/
1019+
`.trim()
1020+
);
1021+
try {
1022+
await fromIni()();
1023+
} catch (e) {
1024+
console.error(e.message);
1025+
expect(e.message).toEqual(expect.stringContaining("Profile is configured with invalid SSO credentials"));
1026+
}
1027+
});
1028+
1029+
it("should resolve valid SSO credential", async () => {
1030+
(isSsoProfile as unknown as jest.Mock).mockImplementationOnce(() => true);
1031+
const originalValidator = jest.requireActual("@aws-sdk/credential-provider-sso").validateSsoProfile;
1032+
(validateSsoProfile as jest.Mock).mockImplementationOnce(originalValidator);
1033+
(fromSSO as jest.Mock).mockImplementationOnce(() => async () => DEFAULT_CREDS);
1034+
const accountId = "1234567890";
1035+
const startUrl = "https://example.com/sso/";
1036+
const region = "us-east-1";
1037+
const roleName = "role";
1038+
__addMatcher(
1039+
DEFAULT_PATH,
1040+
`[default]
1041+
sso_account_id = ${accountId}
1042+
sso_start_url = ${startUrl}
1043+
sso_region = ${region}
1044+
sso_role_name = ${roleName}
1045+
`.trim()
1046+
);
1047+
await fromIni()();
1048+
expect(fromSSO as unknown as jest.Mock).toBeCalledWith({
1049+
ssoAccountId: accountId,
1050+
ssoStartUrl: startUrl,
1051+
ssoRegion: region,
1052+
ssoRoleName: roleName,
1053+
});
1054+
});
1055+
1056+
it("should call fromTokenFile with assume role chaining", async () => {
1057+
(isSsoProfile as unknown as jest.Mock).mockImplementationOnce(
1058+
jest.requireActual("@aws-sdk/credential-provider-sso").isSsoProfile
1059+
);
1060+
(validateSsoProfile as unknown as jest.Mock).mockImplementationOnce(
1061+
jest.requireActual("@aws-sdk/credential-provider-sso").validateSsoProfile
1062+
);
1063+
(fromSSO as jest.Mock).mockImplementationOnce(() => async () => DEFAULT_CREDS);
1064+
const accountId = "1234567890";
1065+
const startUrl = "https://example.com/sso/";
1066+
const region = "us-east-1";
1067+
const roleName = "role";
1068+
const roleAssumerWithWebIdentity = jest.fn();
1069+
1070+
const fooRoleArn = "arn:aws:iam::123456789:role/foo";
1071+
const fooSessionName = "fooSession";
1072+
__addMatcher(
1073+
DEFAULT_PATH,
1074+
`
1075+
[bar]
1076+
sso_account_id = ${accountId}
1077+
sso_start_url = ${startUrl}
1078+
sso_region = ${region}
1079+
sso_role_name = ${roleName}
1080+
1081+
[foo]
1082+
role_arn = ${fooRoleArn}
1083+
role_session_name = ${fooSessionName}
1084+
source_profile = bar`.trim()
1085+
);
1086+
1087+
const provider = fromIni({
1088+
profile: "foo",
1089+
roleAssumer(sourceCreds: Credentials, params: AssumeRoleParams): Promise<Credentials> {
1090+
expect(sourceCreds).toEqual(DEFAULT_CREDS);
1091+
expect(params.RoleArn).toEqual(fooRoleArn);
1092+
expect(params.RoleSessionName).toEqual(fooSessionName);
1093+
return Promise.resolve(FOO_CREDS);
1094+
},
1095+
roleAssumerWithWebIdentity,
1096+
});
1097+
1098+
expect(await provider()).toEqual(FOO_CREDS);
1099+
expect(fromSSO).toHaveBeenCalledTimes(1);
1100+
expect(fromSSO).toHaveBeenCalledWith({
1101+
ssoAccountId: accountId,
1102+
ssoStartUrl: startUrl,
1103+
ssoRegion: region,
1104+
ssoRoleName: roleName,
1105+
});
1106+
});
1107+
});
1108+
9921109
it("should prefer credentials in ~/.aws/credentials to those in ~/.aws/config", async () => {
9931110
__addMatcher(
9941111
join(homedir(), ".aws", "credentials"),

packages/credential-provider-ini/src/index.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,6 @@ const resolveProfileData = async (
146146
return resolveStaticCredentials(data);
147147
}
148148

149-
if (isSsoProfile(data)) {
150-
const { sso_start_url, sso_account_id, sso_region, sso_role_name } = validateSsoProfile(data);
151-
return fromSSO({
152-
ssoStartUrl: sso_start_url,
153-
ssoAccountId: sso_account_id,
154-
ssoRegion: sso_region,
155-
ssoRoleName: sso_role_name,
156-
})();
157-
}
158-
159149
// If this is the first profile visited, role assumption keys should be
160150
// given precedence over static credentials.
161151
if (isAssumeRoleWithSourceProfile(data) || isAssumeRoleWithProviderProfile(data)) {
@@ -217,6 +207,15 @@ const resolveProfileData = async (
217207
if (isWebIdentityProfile(data)) {
218208
return resolveWebIdentityCredentials(data, options);
219209
}
210+
if (isSsoProfile(data)) {
211+
const { sso_start_url, sso_account_id, sso_region, sso_role_name } = validateSsoProfile(data);
212+
return fromSSO({
213+
ssoStartUrl: sso_start_url,
214+
ssoAccountId: sso_account_id,
215+
ssoRegion: sso_region,
216+
ssoRoleName: sso_role_name,
217+
})();
218+
}
220219

221220
// If the profile cannot be parsed or contains neither static credentials
222221
// nor role assumption metadata, throw an error. This should be considered a

packages/credential-provider-sso/src/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ jest.setSystemTime(now);
44

55
const mockParseKnownFiles = jest.fn();
66
const mockGetMasterProfileName = jest.fn();
7-
jest.mock("@aws-sdk/credential-provider-ini", () => ({
7+
jest.mock("@aws-sdk/util-credentials", () => ({
88
parseKnownFiles: mockParseKnownFiles,
99
getMasterProfileName: mockGetMasterProfileName,
1010
}));

0 commit comments

Comments
 (0)