Skip to content

Commit 1744455

Browse files
committed
test: fromTokenFile
1 parent 3cac271 commit 1744455

File tree

1 file changed

+310
-0
lines changed

1 file changed

+310
-0
lines changed
Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
import { AssumeRoleCommandInput, AssumeRoleWithWebIdentityCommandInput } from "@aws-sdk/client-sts";
2+
import { getMasterProfileName, parseKnownFiles } from "@aws-sdk/credential-provider-ini";
3+
import { ProviderError } from "@aws-sdk/property-provider";
4+
import { Credentials } from "@aws-sdk/types";
5+
import { readFileSync } from "fs";
6+
7+
import { ENV_ROLE_ARN, ENV_ROLE_SESSION_NAME, ENV_TOKEN_FILE, fromTokenFile, FromTokenFileInit } from "./fromTokenFile";
8+
9+
jest.mock("fs");
10+
jest.mock("@aws-sdk/credential-provider-ini");
11+
12+
const MOCK_CREDS = {
13+
accessKeyId: "accessKeyId",
14+
secretAccessKey: "secretAccessKey",
15+
sessionToken: "sessionToken",
16+
};
17+
18+
const mockTokenFile = "mockTokenFile";
19+
const mockTokenValue = "exampletoken";
20+
const mockRoleArn = "mockRoleArn";
21+
const mockRoleSessionName = "mockRoleSessionName";
22+
23+
describe(fromTokenFile.name, () => {
24+
beforeEach(() => {
25+
(readFileSync as jest.Mock).mockReturnValue(mockTokenValue);
26+
});
27+
28+
afterEach(() => {
29+
jest.clearAllMocks();
30+
jest.restoreAllMocks();
31+
});
32+
33+
const testRoleAssumerWithWebIdentityNotDefined = async (errorPrefix: string) => {
34+
try {
35+
// @ts-ignore An argument for 'init' was not provided.
36+
await fromTokenFile({})();
37+
fail(`Expected error to be thrown`);
38+
} catch (error) {
39+
expect(error).toEqual(new ProviderError(`${errorPrefix}, but no role assumption callback was provided.`, false));
40+
}
41+
};
42+
43+
const testReadFileSyncError = async (init: FromTokenFileInit) => {
44+
const readFileSyncError = new Error("readFileSyncError");
45+
(readFileSync as jest.Mock).mockImplementation(() => {
46+
throw readFileSyncError;
47+
});
48+
try {
49+
await fromTokenFile(init)();
50+
fail(`Exepcted error to be thrown`);
51+
} catch (error) {
52+
expect(error).toEqual(readFileSyncError);
53+
}
54+
expect(readFileSync).toHaveBeenCalledTimes(1);
55+
};
56+
57+
const testRoleAssumerWithWebIdentitySuccess = async (init: FromTokenFileInit) => {
58+
const creds = await fromTokenFile(init)();
59+
expect(creds).toEqual(MOCK_CREDS);
60+
expect(readFileSync).toHaveBeenCalledTimes(1);
61+
expect(readFileSync).toHaveBeenCalledWith(mockTokenFile, { encoding: "ascii" });
62+
};
63+
64+
const testRandomValueForRoleSessionName = async () => {
65+
const mockDateNow = Date.now();
66+
const spyDateNow = jest.spyOn(Date, "now").mockReturnValueOnce(mockDateNow);
67+
68+
const creds = await fromTokenFile({
69+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
70+
expect(params.RoleSessionName).toEqual(`aws-sdk-js-session-${mockDateNow}`);
71+
return MOCK_CREDS;
72+
},
73+
})();
74+
expect(creds).toEqual(MOCK_CREDS);
75+
expect(spyDateNow).toHaveBeenCalledTimes(1);
76+
};
77+
78+
describe("reads config from env", () => {
79+
const original_ENV_TOKEN_FILE = process.env[ENV_TOKEN_FILE];
80+
const original_ENV_ROLE_ARN = process.env[ENV_ROLE_ARN];
81+
const original_ENV_ROLE_SESSION_NAME = process.env[ENV_ROLE_SESSION_NAME];
82+
83+
beforeEach(() => {
84+
process.env[ENV_TOKEN_FILE] = mockTokenFile;
85+
process.env[ENV_ROLE_ARN] = mockRoleArn;
86+
process.env[ENV_ROLE_SESSION_NAME] = mockRoleSessionName;
87+
});
88+
89+
afterAll(() => {
90+
process.env[ENV_TOKEN_FILE] = original_ENV_TOKEN_FILE;
91+
process.env[ENV_ROLE_ARN] = original_ENV_ROLE_ARN;
92+
process.env[ENV_ROLE_SESSION_NAME] = original_ENV_ROLE_SESSION_NAME;
93+
});
94+
95+
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
96+
return testRoleAssumerWithWebIdentityNotDefined(
97+
`Role Arn '${process.env[ENV_ROLE_ARN]}' needs to be assumed with web identity`
98+
);
99+
});
100+
101+
it("throws if ENV_TOKEN_FILE read from disk failed", async () => {
102+
return testReadFileSyncError({
103+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
104+
return MOCK_CREDS;
105+
},
106+
});
107+
});
108+
109+
it("passes values to roleAssumerWithWebIdentity", async () => {
110+
return testRoleAssumerWithWebIdentitySuccess({
111+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
112+
expect(params.WebIdentityToken).toEqual(mockTokenValue);
113+
expect(params.RoleArn).toEqual(mockRoleArn);
114+
expect(params.RoleSessionName).toEqual(mockRoleSessionName);
115+
return MOCK_CREDS;
116+
},
117+
});
118+
});
119+
120+
it("generates a random value for RoleSessionName if not available", async () => {
121+
delete process.env[ENV_ROLE_SESSION_NAME];
122+
return testRandomValueForRoleSessionName();
123+
});
124+
});
125+
126+
describe("reads config from shared ini", () => {
127+
const original_ENV_TOKEN_FILE = process.env[ENV_TOKEN_FILE];
128+
const masterProfileName = "masterProfileName";
129+
130+
beforeAll(() => {
131+
delete process.env[ENV_TOKEN_FILE];
132+
});
133+
134+
afterAll(() => {
135+
process.env[ENV_TOKEN_FILE] = original_ENV_TOKEN_FILE;
136+
});
137+
138+
beforeEach(() => {
139+
(getMasterProfileName as jest.Mock).mockReturnValue(masterProfileName);
140+
});
141+
142+
describe("without source_profile", () => {
143+
beforeEach(() => {
144+
(parseKnownFiles as jest.Mock).mockResolvedValue({
145+
[masterProfileName]: {
146+
web_identity_token_file: mockTokenFile,
147+
role_arn: mockRoleArn,
148+
role_session_name: mockRoleSessionName,
149+
},
150+
});
151+
});
152+
153+
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
154+
return testRoleAssumerWithWebIdentityNotDefined(
155+
`Profile '${masterProfileName}' requires a role to be assumed with web identity`
156+
);
157+
});
158+
159+
it("throws if web_identity_token_file read from disk failed", async () => {
160+
return testReadFileSyncError({
161+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
162+
return MOCK_CREDS;
163+
},
164+
});
165+
});
166+
167+
it("passes values to roleAssumerWithWebIdentity", async () => {
168+
return testRoleAssumerWithWebIdentitySuccess({
169+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
170+
expect(params.WebIdentityToken).toEqual(mockTokenValue);
171+
expect(params.RoleArn).toEqual(mockRoleArn);
172+
expect(params.RoleSessionName).toEqual(mockRoleSessionName);
173+
return MOCK_CREDS;
174+
},
175+
});
176+
});
177+
178+
it("generates a random value for RoleSessionName if not available", async () => {
179+
(parseKnownFiles as jest.Mock).mockResolvedValue({
180+
[masterProfileName]: {
181+
web_identity_token_file: mockTokenFile,
182+
role_arn: mockRoleArn,
183+
},
184+
});
185+
return testRandomValueForRoleSessionName();
186+
});
187+
});
188+
189+
describe("with source_profile", () => {
190+
const MOCK_SOURCE_CREDS = {
191+
accessKeyId: "accessKeyIdSource",
192+
secretAccessKey: "secretAccessKeySource",
193+
sessionToken: "sessionTokenSource",
194+
};
195+
196+
const sourceProfileName = "sourceProfileName";
197+
const mockMasterRoleArn = "mockMasterRoleArn";
198+
const mockMasterRoleSessionName = "mockMasterRoleSessionName";
199+
200+
beforeEach(() => {
201+
(parseKnownFiles as jest.Mock).mockResolvedValue({
202+
[sourceProfileName]: {
203+
web_identity_token_file: mockTokenFile,
204+
role_arn: mockRoleArn,
205+
role_session_name: mockRoleSessionName,
206+
},
207+
[masterProfileName]: {
208+
source_profile: sourceProfileName,
209+
role_arn: mockMasterRoleArn,
210+
role_session_name: mockMasterRoleSessionName,
211+
},
212+
});
213+
});
214+
215+
it("throws if roleAssumer is not defined", async () => {
216+
try {
217+
// @ts-ignore An argument for 'init' was not provided.
218+
await fromTokenFile({})();
219+
fail(`Expected error to be thrown`);
220+
} catch (error) {
221+
expect(error).toEqual(
222+
new ProviderError(
223+
`Profile '${masterProfileName}' requires a role to be assumed, but no role assumption callback was provided.`,
224+
false
225+
)
226+
);
227+
}
228+
});
229+
230+
it("throws if roleAssumerWithWebIdentity is not defined", async () => {
231+
try {
232+
// @ts-ignore An argument for 'init' was not provided.
233+
await fromTokenFile({
234+
roleAssumer: async (sourceCreds: Credentials, params: AssumeRoleCommandInput) => {
235+
return MOCK_CREDS;
236+
},
237+
})();
238+
fail(`Expected error to be thrown`);
239+
} catch (error) {
240+
expect(error).toEqual(
241+
new ProviderError(
242+
`Profile '${sourceProfileName}' requires a role to be assumed with web identity, but no role assumption callback was provided.`,
243+
false
244+
)
245+
);
246+
}
247+
});
248+
249+
it("throws if web_identity_token_file read from disk failed", async () => {
250+
return testReadFileSyncError({
251+
roleAssumer: async (sourceCreds: Credentials, params: AssumeRoleCommandInput) => {
252+
return MOCK_CREDS;
253+
},
254+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
255+
return MOCK_SOURCE_CREDS;
256+
},
257+
});
258+
});
259+
260+
it("passes values to roleAssumerWithWebIdentity", async () => {
261+
return testRoleAssumerWithWebIdentitySuccess({
262+
roleAssumer: async (sourceCreds: Credentials, params: AssumeRoleCommandInput) => {
263+
expect(sourceCreds).toEqual(MOCK_SOURCE_CREDS);
264+
expect(params.RoleArn).toEqual(mockMasterRoleArn);
265+
expect(params.RoleSessionName).toEqual(mockMasterRoleSessionName);
266+
return MOCK_CREDS;
267+
},
268+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
269+
expect(params.WebIdentityToken).toEqual(mockTokenValue);
270+
expect(params.RoleArn).toEqual(mockRoleArn);
271+
expect(params.RoleSessionName).toEqual(mockRoleSessionName);
272+
return MOCK_SOURCE_CREDS;
273+
},
274+
});
275+
});
276+
277+
it("generates a random value for RoleSessionName if not available", async () => {
278+
(parseKnownFiles as jest.Mock).mockResolvedValue({
279+
[sourceProfileName]: {
280+
web_identity_token_file: mockTokenFile,
281+
role_arn: mockRoleArn,
282+
},
283+
[masterProfileName]: {
284+
source_profile: sourceProfileName,
285+
role_arn: mockMasterRoleArn,
286+
},
287+
});
288+
const mockDateNowFirst = Date.now();
289+
const mockDateNowSecond = mockDateNowFirst + 1;
290+
const spyDateNow = jest
291+
.spyOn(Date, "now")
292+
.mockReturnValueOnce(mockDateNowFirst)
293+
.mockReturnValueOnce(mockDateNowSecond);
294+
295+
const creds = await fromTokenFile({
296+
roleAssumer: async (sourceCreds: Credentials, params: AssumeRoleCommandInput) => {
297+
expect(params.RoleSessionName).toEqual(`aws-sdk-js-session-${mockDateNowFirst}`);
298+
return MOCK_CREDS;
299+
},
300+
roleAssumerWithWebIdentity: async (params: AssumeRoleWithWebIdentityCommandInput) => {
301+
expect(params.RoleSessionName).toEqual(`aws-sdk-js-session-${mockDateNowSecond}`);
302+
return MOCK_SOURCE_CREDS;
303+
},
304+
})();
305+
expect(creds).toEqual(MOCK_CREDS);
306+
expect(spyDateNow).toHaveBeenCalledTimes(2);
307+
});
308+
});
309+
});
310+
});

0 commit comments

Comments
 (0)