Skip to content

Commit 67e7e57

Browse files
Merge branch 'zhiyuanliang/secret-refresh' of https://github.com/Azure/AppConfiguration-JavaScriptProvider into zhiyuanliang/secret-refresh
2 parents 16dff9f + 969c0dd commit 67e7e57

File tree

4 files changed

+26
-16
lines changed

4 files changed

+26
-16
lines changed

src/AzureAppConfigurationImpl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ export class AzureAppConfigurationImpl implements AzureAppConfiguration {
176176
const { secretRefreshIntervalInMs } = options.keyVaultOptions;
177177
if (secretRefreshIntervalInMs !== undefined) {
178178
if (secretRefreshIntervalInMs < MIN_SECRET_REFRESH_INTERVAL_IN_MS) {
179-
throw new RangeError(`The key vault secret refresh interval cannot be less than ${MIN_SECRET_REFRESH_INTERVAL_IN_MS} milliseconds.`);
179+
throw new RangeError(`The Key Vault secret refresh interval cannot be less than ${MIN_SECRET_REFRESH_INTERVAL_IN_MS} milliseconds.`);
180180
}
181181
this.#secretRefreshEnabled = true;
182182
this.#secretRefreshTimer = new RefreshTimer(secretRefreshIntervalInMs);

src/keyvault/AzureKeyVaultSecretProvider.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,21 +31,22 @@ export class AzureKeyVaultSecretProvider {
3131
}
3232

3333
async getSecretValue(secretIdentifier: KeyVaultSecretIdentifier): Promise<unknown> {
34-
// The map key is a combination of sourceId and version: "{sourceId}\n{version}"
34+
// The map key is a combination of sourceId and version: "{sourceId}\n{version}".
3535
const identifierKey = `${secretIdentifier.sourceId}\n${secretIdentifier.version ?? ""}`;
36+
37+
// If the secret has a version, always use the cached value if available.
38+
if (secretIdentifier.version && this.#cachedSecretValue.has(identifierKey)) {
39+
return this.#cachedSecretValue.get(identifierKey);
40+
}
41+
3642
if (this.#refreshTimer && !this.#refreshTimer.canRefresh()) {
37-
// return the cached secret value if it exists
43+
// If the refresh interval is not expired, return the cached value if available.
3844
if (this.#cachedSecretValue.has(identifierKey)) {
39-
const cachedValue = this.#cachedSecretValue.get(identifierKey);
40-
return cachedValue;
45+
return this.#cachedSecretValue.get(identifierKey);
4146
}
42-
// not found in cache, get the secret value from key vault
43-
const secretValue = await this.#getSecretValueFromKeyVault(secretIdentifier);
44-
this.#cachedSecretValue.set(identifierKey, secretValue);
45-
return secretValue;
4647
}
4748

48-
// Always reload the secret value from key vault when the refresh timer expires.
49+
// Fallback to fetching the secret value from Key Vault.
4950
const secretValue = await this.#getSecretValueFromKeyVault(secretIdentifier);
5051
this.#cachedSecretValue.set(identifierKey, secretValue);
5152
return secretValue;
@@ -85,7 +86,7 @@ export class AzureKeyVaultSecretProvider {
8586
return client;
8687
}
8788
if (this.#keyVaultOptions?.credential) {
88-
client = new SecretClient(vaultUrl.toString(), this.#keyVaultOptions.credential);
89+
client = new SecretClient(vaultUrl.toString(), this.#keyVaultOptions.credential, this.#keyVaultOptions.clientOptions);
8990
this.#secretClients.set(vaultUrl.host, client);
9091
return client;
9192
}

src/keyvault/KeyVaultOptions.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Licensed under the MIT license.
33

44
import { TokenCredential } from "@azure/identity";
5-
import { SecretClient } from "@azure/keyvault-secrets";
5+
import { SecretClient, SecretClientOptions } from "@azure/keyvault-secrets";
66

77
export const MIN_SECRET_REFRESH_INTERVAL_IN_MS = 60_000;
88

@@ -21,16 +21,25 @@ export interface KeyVaultOptions {
2121
credential?: TokenCredential;
2222

2323
/**
24-
* Specifies the refresh interval in milliseconds for periodically reloading secret from Key Vault.
24+
* * Configures the client options used when connecting to key vaults that have no registered SecretClient.
25+
*
2526
* @remarks
26-
* If specified, the value must be greater than 60 seconds.
27+
* The client options will not affect the registered SecretClient instances.
2728
*/
28-
secretRefreshIntervalInMs?: number;
29+
clientOptions?: SecretClientOptions;
2930

3031
/**
3132
* Specifies the callback used to resolve key vault references that have no applied SecretClient.
3233
* @param keyVaultReference The Key Vault reference to resolve.
3334
* @returns The secret value.
3435
*/
3536
secretResolver?: (keyVaultReference: URL) => string | Promise<string>;
37+
38+
/**
39+
* Specifies the refresh interval in milliseconds for periodically reloading secret from Key Vault.
40+
*
41+
* @remarks
42+
* If specified, the value must be greater than 60 seconds.
43+
*/
44+
secretRefreshIntervalInMs?: number;
3645
}

test/keyvault.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ describe("key vault secret refresh", function () {
155155
secretRefreshIntervalInMs: 59999 // less than 60_000 milliseconds
156156
}
157157
});
158-
return expect(loadWithInvalidSecretRefreshInterval).eventually.rejectedWith("The key vault secret refresh interval cannot be less than 60000 milliseconds.");
158+
return expect(loadWithInvalidSecretRefreshInterval).eventually.rejectedWith("The Key Vault secret refresh interval cannot be less than 60000 milliseconds.");
159159
});
160160

161161
it("should reload key vault secret when there is no change to key-values", async () => {

0 commit comments

Comments
 (0)