Skip to content

Commit 2320c7c

Browse files
authored
fix(credential-provider-node): open credential provider lock after failed chain (#7692)
1 parent a1794f7 commit 2320c7c

2 files changed

Lines changed: 48 additions & 8 deletions

File tree

packages-internal/credential-provider-node/src/runtime/memoize-chain.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, test as it, vi } from "vitest";
33

44
import { credentialsWillNeedRefresh } from "../defaultProvider";
55
import { memoizeChain } from "./memoize-chain";
6+
import { CredentialsProviderError } from "@smithy/property-provider";
67

78
describe("memoize runtime config aware AWS credential chain", () => {
89
let staticCredentials!: RuntimeConfigAwsCredentialIdentityProvider;
@@ -156,4 +157,37 @@ describe("memoize runtime config aware AWS credential chain", () => {
156157

157158
expect(expiringCredentials).toHaveBeenCalledTimes(5);
158159
});
160+
161+
it("should release locks on credential resolution failure at the end of the chain", async () => {
162+
const neverAvailableCredentialProvider: () => RuntimeConfigAwsCredentialIdentityProvider = () => async () => {
163+
throw new CredentialsProviderError("never available", { tryNextLink: true });
164+
};
165+
166+
let n = 0;
167+
const eventuallyAvailableCredentialProvider: RuntimeConfigAwsCredentialIdentityProvider = async () => {
168+
if (n++ === 0) {
169+
throw new CredentialsProviderError("initially unavailable", { tryNextLink: false });
170+
}
171+
return {
172+
accessKeyId: "xyz",
173+
secretAccessKey: "xyz",
174+
};
175+
};
176+
177+
const provider = memoizeChain(
178+
[neverAvailableCredentialProvider(), neverAvailableCredentialProvider(), eventuallyAvailableCredentialProvider],
179+
credentialsWillNeedRefresh
180+
);
181+
182+
try {
183+
await provider();
184+
} catch (e) {
185+
const credentials = await provider();
186+
expect(credentials).toEqual({
187+
accessKeyId: "xyz",
188+
secretAccessKey: "xyz",
189+
});
190+
}
191+
expect.assertions(1);
192+
});
159193
});

packages-internal/credential-provider-node/src/runtime/memoize-chain.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,22 @@ export function memoizeChain(
4444
} else if (!credentials || treatAsExpired?.(credentials!)) {
4545
if (credentials) {
4646
if (!passiveLock) {
47-
passiveLock = chain(options).then((c) => {
48-
credentials = c;
49-
passiveLock = undefined;
50-
});
47+
passiveLock = chain(options)
48+
.then((c) => {
49+
credentials = c;
50+
})
51+
.finally(() => {
52+
passiveLock = undefined;
53+
});
5154
}
5255
} else {
53-
activeLock = chain(options).then((c) => {
54-
credentials = c;
55-
activeLock = undefined;
56-
});
56+
activeLock = chain(options)
57+
.then((c) => {
58+
credentials = c;
59+
})
60+
.finally(() => {
61+
activeLock = undefined;
62+
});
5763
return provider(options);
5864
}
5965
}

0 commit comments

Comments
 (0)