Skip to content

Commit d6f805e

Browse files
committed
fix(credential-provider-node): read config files only once
1 parent 0878966 commit d6f805e

File tree

3 files changed

+37
-4
lines changed

3 files changed

+37
-4
lines changed

packages/credential-provider-node/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"@aws-sdk/credential-provider-ini": "3.4.1",
3232
"@aws-sdk/credential-provider-process": "3.4.1",
3333
"@aws-sdk/property-provider": "3.4.1",
34+
"@aws-sdk/shared-ini-file-loader": "3.4.1",
3435
"@aws-sdk/types": "3.4.1",
3536
"tslib": "^1.8.0"
3637
},

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

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ jest.mock("@aws-sdk/credential-provider-env", () => {
1010
});
1111
import { fromEnv } from "@aws-sdk/credential-provider-env";
1212

13+
const loadedConfig = {
14+
credentialsFile: {
15+
foo: { aws_access_key_id: "key", aws_secret_access_key: "secret" },
16+
},
17+
configFile: { bar: { aws_access_key_id: "key", aws_secret_access_key: "secret" } },
18+
};
19+
jest.mock("@aws-sdk/shared-ini-file-loader", () => ({
20+
loadSharedConfigFiles: jest.fn().mockReturnValue(loadedConfig),
21+
}));
22+
import { loadSharedConfigFiles } from "@aws-sdk/shared-ini-file-loader";
23+
1324
jest.mock("@aws-sdk/credential-provider-ini", () => {
1425
const iniProvider = jest.fn();
1526
return {
@@ -39,6 +50,7 @@ jest.mock("@aws-sdk/credential-provider-imds", () => {
3950
ENV_CMDS_RELATIVE_URI: "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
4051
};
4152
});
53+
4254
import {
4355
ENV_CMDS_FULL_URI,
4456
ENV_CMDS_RELATIVE_URI,
@@ -78,6 +90,7 @@ beforeEach(() => {
7890
(fromProcess as any).mockClear();
7991
(fromContainerMetadata as any).mockClear();
8092
(fromInstanceMetadata as any).mockClear();
93+
(loadSharedConfigFiles as any).mockClear();
8194
});
8295

8396
afterAll(() => {
@@ -200,6 +213,23 @@ describe("defaultProvider", () => {
200213
expect((fromInstanceMetadata() as any).mock.calls.length).toBe(0);
201214
});
202215

216+
it("should read config files only once for all providers", async () => {
217+
const creds = {
218+
accessKeyId: "foo",
219+
secretAccessKey: "bar",
220+
};
221+
222+
(fromEnv() as any).mockImplementation(() => Promise.reject(new ProviderError("Keep moving!")));
223+
(fromIni() as any).mockImplementation(() => Promise.reject(new ProviderError("Nothing here!")));
224+
(fromProcess() as any).mockImplementation(() => Promise.reject(new ProviderError("Nor here!")));
225+
(fromInstanceMetadata() as any).mockImplementation(() => Promise.resolve(creds));
226+
227+
await expect(defaultProvider()()).resolves;
228+
expect((loadSharedConfigFiles as any).mock.calls.length).toBe(1);
229+
expect((fromIni as any).mock.calls[1][0]).toMatchObject({ loadedConfig: loadSharedConfigFiles() });
230+
expect((fromProcess as any).mock.calls[1][0]).toMatchObject({ loadedConfig: loadSharedConfigFiles() });
231+
});
232+
203233
it("should pass configuration on to the ini provider", async () => {
204234
const iniConfig: FromIniInit = {
205235
profile: "foo",
@@ -226,7 +256,7 @@ describe("defaultProvider", () => {
226256
await expect(defaultProvider(iniConfig)()).resolves;
227257

228258
expect((fromIni as any).mock.calls.length).toBe(1);
229-
expect((fromIni as any).mock.calls[0][0]).toEqual(iniConfig);
259+
expect((fromIni as any).mock.calls[0][0]).toEqual({ ...iniConfig, loadedConfig });
230260
});
231261

232262
it("should pass configuration on to the process provider", async () => {
@@ -249,7 +279,7 @@ describe("defaultProvider", () => {
249279
await expect(defaultProvider(processConfig)()).resolves;
250280
expect((fromProcess as any).mock.calls.length).toBe(1);
251281
expect((fromProcess as any).mock.calls.length).toBe(1);
252-
expect((fromProcess as any).mock.calls[0][0]).toEqual(processConfig);
282+
expect((fromProcess as any).mock.calls[0][0]).toEqual({ ...processConfig, loadedConfig });
253283
});
254284

255285
it("should pass configuration on to the IMDS provider", async () => {
@@ -273,7 +303,7 @@ describe("defaultProvider", () => {
273303
await expect(defaultProvider(imdsConfig)()).resolves;
274304

275305
expect((fromInstanceMetadata as any).mock.calls.length).toBe(1);
276-
expect((fromInstanceMetadata as any).mock.calls[0][0]).toEqual(imdsConfig);
306+
expect((fromInstanceMetadata as any).mock.calls[0][0]).toEqual({ ...imdsConfig, loadedConfig });
277307
});
278308

279309
it("should pass configuration on to the ECS IMDS provider", async () => {
@@ -298,7 +328,7 @@ describe("defaultProvider", () => {
298328
await expect(defaultProvider(ecsImdsConfig)()).resolves;
299329

300330
expect((fromContainerMetadata as any).mock.calls.length).toBe(1);
301-
expect((fromContainerMetadata as any).mock.calls[0][0]).toEqual(ecsImdsConfig);
331+
expect((fromContainerMetadata as any).mock.calls[0][0]).toEqual({ ...ecsImdsConfig, loadedConfig });
302332
});
303333

304334
it("should return the same promise across invocations", async () => {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { ENV_PROFILE, fromIni, FromIniInit } from "@aws-sdk/credential-provider-ini";
1010
import { fromProcess, FromProcessInit } from "@aws-sdk/credential-provider-process";
1111
import { chain, memoize, ProviderError } from "@aws-sdk/property-provider";
12+
import { loadSharedConfigFiles } from "@aws-sdk/shared-ini-file-loader";
1213
import { CredentialProvider } from "@aws-sdk/types";
1314

1415
export const ENV_IMDS_DISABLED = "AWS_EC2_METADATA_DISABLED";
@@ -43,6 +44,7 @@ export const ENV_IMDS_DISABLED = "AWS_EC2_METADATA_DISABLED";
4344
*/
4445
export function defaultProvider(init: FromIniInit & RemoteProviderInit & FromProcessInit = {}): CredentialProvider {
4546
const options = { profile: process.env[ENV_PROFILE], ...init };
47+
if (!options.loadedConfig) options.loadedConfig = loadSharedConfigFiles(init);
4648
const providers = [fromIni(options), fromProcess(options), remoteProvider(options)];
4749
if (!options.profile) providers.unshift(fromEnv());
4850
const providerChain = chain(...providers);

0 commit comments

Comments
 (0)