From 186128ac2d19159724fc76a75d531871e6cd8918 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Wed, 4 Nov 2020 07:18:57 -0800 Subject: [PATCH 1/7] feat: support for labels --- src/dotenv-azure.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/dotenv-azure.ts b/src/dotenv-azure.ts index 1a5ce761..0fa713c0 100644 --- a/src/dotenv-azure.ts +++ b/src/dotenv-azure.ts @@ -99,7 +99,11 @@ export default class DotenvAzure { async loadFromAzure(dotenvVars?: DotenvParseOutput): Promise { const credentials = this.getAzureCredentials(dotenvVars) const appConfigClient = new AppConfigurationClient(credentials.connectionString) - const { appConfigVars, keyVaultReferences } = await this.getAppConfigurations(appConfigClient) + const labels = dotenvVars?.AZURE_APP_CONFIG_LABELS || '' + const { appConfigVars, keyVaultReferences } = await this.getAppConfigurations( + appConfigClient, + labels + ) const keyVaultSecrets = await this.getSecretsFromKeyVault(credentials, keyVaultReferences) return { ...appConfigVars, ...keyVaultSecrets } } @@ -114,11 +118,14 @@ export default class DotenvAzure { } } - protected async getAppConfigurations(client: AppConfigurationClient): Promise { + protected async getAppConfigurations( + client: AppConfigurationClient, + labels = '' + ): Promise { const appConfigVars: VariablesObject = {} const keyVaultReferences: KeyVaultReferences = {} - for await (const config of client.listConfigurationSettings()) { + for await (const config of client.listConfigurationSettings({ labelFilter: labels })) { if (this.isKeyVaultReference(config)) { keyVaultReferences[config.key] = this.getKeyVaultReferenceInfo(config) } else { From 49670ee41292d6ca8db043e92d6102c3cfc3a9fe Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Wed, 4 Nov 2020 20:41:17 -0800 Subject: [PATCH 2/7] Checking for process env for Azure config --- src/dotenv-azure.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dotenv-azure.ts b/src/dotenv-azure.ts index 0fa713c0..c34b24b7 100644 --- a/src/dotenv-azure.ts +++ b/src/dotenv-azure.ts @@ -86,6 +86,8 @@ export default class DotenvAzure { */ async parse(src: string, options?: DotenvParseOptions): Promise { const dotenvVars = dotenv.parse(src, options) + dotenvVars.AZURE_APP_CONFIG_LABELS = dotenvVars.AZURE_APP_CONFIG_LABELS ? dotenvVars.AZURE_APP_CONFIG_LABELS : process.env.AZURE_APP_CONFIG_LABELS || '' + dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING = dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING ? dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING : process.env.AZURE_APP_CONFIG_CONNECTION_STRING || '' const azureVars = await this.loadFromAzure(dotenvVars) return { ...azureVars, ...dotenvVars } } From a0aeaa417c7cf5aa1c88ad12207c9845b092c651 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Wed, 4 Nov 2020 20:54:03 -0800 Subject: [PATCH 3/7] 2.0.3 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index e1ed44cb..cdc904a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.0", + "version": "2.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 394ad0c8..106068eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.0", + "version": "2.0.3", "description": "Load environment variables from Azure's services App Configuration, Key Vault or a .env file", "keywords": [ "azure", From ebcfc3f6215466dca04181be161f61b0fa77ac19 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Thu, 5 Nov 2020 10:49:00 -0800 Subject: [PATCH 4/7] Mixing in process.env for Azure loadFromAzure --- src/dotenv-azure.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/dotenv-azure.ts b/src/dotenv-azure.ts index c34b24b7..7e5aae66 100644 --- a/src/dotenv-azure.ts +++ b/src/dotenv-azure.ts @@ -1,7 +1,7 @@ import * as fs from 'fs' import { URL } from 'url' import Bottleneck from 'bottleneck' -import dotenv, { DotenvParseOptions, DotenvParseOutput } from 'dotenv' +import dotenv, { DotenvParseOptions } from 'dotenv' import { ManagedIdentityCredential, ClientSecretCredential } from '@azure/identity' import { SecretClient } from '@azure/keyvault-secrets' import { AppConfigurationClient, ConfigurationSetting } from '@azure/app-configuration' @@ -60,8 +60,8 @@ export default class DotenvAzure { async config(options: DotenvAzureConfigOptions = {}): Promise { const { safe = false } = options const dotenvResult = dotenv.config(options) - - const azureVars = await this.loadFromAzure(dotenvResult.parsed) + const vars:Record = {...(dotenvResult.parsed || {}), ...process.env} + const azureVars = await this.loadFromAzure(vars) const joinedVars = { ...azureVars, ...dotenvResult.parsed } populateProcessEnv(azureVars) @@ -86,8 +86,6 @@ export default class DotenvAzure { */ async parse(src: string, options?: DotenvParseOptions): Promise { const dotenvVars = dotenv.parse(src, options) - dotenvVars.AZURE_APP_CONFIG_LABELS = dotenvVars.AZURE_APP_CONFIG_LABELS ? dotenvVars.AZURE_APP_CONFIG_LABELS : process.env.AZURE_APP_CONFIG_LABELS || '' - dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING = dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING ? dotenvVars.AZURE_APP_CONFIG_CONNECTION_STRING : process.env.AZURE_APP_CONFIG_CONNECTION_STRING || '' const azureVars = await this.loadFromAzure(dotenvVars) return { ...azureVars, ...dotenvVars } } @@ -98,7 +96,8 @@ export default class DotenvAzure { * @param dotenvVars - dotenv parse() output containing azure credentials variables * @returns an object with keys and values */ - async loadFromAzure(dotenvVars?: DotenvParseOutput): Promise { + async loadFromAzure(dotenvVars?: Record): Promise { + // const vars = {...dotenvVars, ...process.env} const credentials = this.getAzureCredentials(dotenvVars) const appConfigClient = new AppConfigurationClient(credentials.connectionString) const labels = dotenvVars?.AZURE_APP_CONFIG_LABELS || '' @@ -203,10 +202,10 @@ export default class DotenvAzure { ) } - private getAzureCredentials(dotenvVars: DotenvParseOutput = {}): AzureCredentials { + private getAzureCredentials(dotenvVars: Record = {}): AzureCredentials { const vars = { ...dotenvVars, ...process.env } const connectionString = this.connectionString || vars.AZURE_APP_CONFIG_CONNECTION_STRING - + if (!connectionString) { throw new MissingAppConfigCredentialsError() } From 8eb8ff64af30279289f1b6e7b67bd43f9796ca14 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Thu, 5 Nov 2020 10:49:09 -0800 Subject: [PATCH 5/7] 2.0.4 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdc904a3..1be8530f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.3", + "version": "2.0.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 106068eb..2c599bf1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.3", + "version": "2.0.4", "description": "Load environment variables from Azure's services App Configuration, Key Vault or a .env file", "keywords": [ "azure", From b47d6501d1493d6a53e38eab55e714da84a3a5ec Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Thu, 5 Nov 2020 10:55:51 -0800 Subject: [PATCH 6/7] 2.0.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1be8530f..3f0fb96f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.4", + "version": "2.0.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 2c599bf1..bf97fcaf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.4", + "version": "2.0.5", "description": "Load environment variables from Azure's services App Configuration, Key Vault or a .env file", "keywords": [ "azure", From 0ca5e6c16ab91ee008ca8497e4df137276645887 Mon Sep 17 00:00:00 2001 From: Kyle Hayes Date: Wed, 4 Nov 2020 07:18:57 -0800 Subject: [PATCH 7/7] feat: support for labels - Adding support for labels - Mixing in process.env for Azure loadFromAzure --- package-lock.json | 2 +- package.json | 2 +- src/dotenv-azure.ts | 9 +++++---- test/azure.mock.ts | 1 + test/dotenv-azure.test.ts | 7 +++++++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f0fb96f..e1ed44cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.5", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index bf97fcaf..394ad0c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dotenv-azure", - "version": "2.0.5", + "version": "2.0.0", "description": "Load environment variables from Azure's services App Configuration, Key Vault or a .env file", "keywords": [ "azure", diff --git a/src/dotenv-azure.ts b/src/dotenv-azure.ts index 7e5aae66..4562ae22 100644 --- a/src/dotenv-azure.ts +++ b/src/dotenv-azure.ts @@ -60,7 +60,10 @@ export default class DotenvAzure { async config(options: DotenvAzureConfigOptions = {}): Promise { const { safe = false } = options const dotenvResult = dotenv.config(options) - const vars:Record = {...(dotenvResult.parsed || {}), ...process.env} + const vars: Record = { + ...(dotenvResult.parsed || {}), + ...process.env, + } const azureVars = await this.loadFromAzure(vars) const joinedVars = { ...azureVars, ...dotenvResult.parsed } @@ -97,7 +100,6 @@ export default class DotenvAzure { * @returns an object with keys and values */ async loadFromAzure(dotenvVars?: Record): Promise { - // const vars = {...dotenvVars, ...process.env} const credentials = this.getAzureCredentials(dotenvVars) const appConfigClient = new AppConfigurationClient(credentials.connectionString) const labels = dotenvVars?.AZURE_APP_CONFIG_LABELS || '' @@ -202,8 +204,7 @@ export default class DotenvAzure { ) } - private getAzureCredentials(dotenvVars: Record = {}): AzureCredentials { - const vars = { ...dotenvVars, ...process.env } + private getAzureCredentials(vars: Record = {}): AzureCredentials { const connectionString = this.connectionString || vars.AZURE_APP_CONFIG_CONNECTION_STRING if (!connectionString) { diff --git a/test/azure.mock.ts b/test/azure.mock.ts index eade5d46..16a8ed6f 100644 --- a/test/azure.mock.ts +++ b/test/azure.mock.ts @@ -18,6 +18,7 @@ export const appConfigListMock = jest.fn(() => isReadOnly: false, key: 'APP_CONFIG_VAR', value: 'ok', + label: 'the-label', }, { isReadOnly: true, diff --git a/test/dotenv-azure.test.ts b/test/dotenv-azure.test.ts index d20ad473..25c61001 100644 --- a/test/dotenv-azure.test.ts +++ b/test/dotenv-azure.test.ts @@ -19,6 +19,7 @@ const mockReadFileSync = readFileSync as jest.Mock describe('DotenvAzure', () => { const OLD_ENV = process.env const AZURE_APP_CONFIG_CONNECTION_STRING = 'app-config-conneciton-string' + const AZURE_APP_CONFIG_LABELS = 'app-config-labels' const AZURE_TENANT_ID = 'tenant-id' const AZURE_CLIENT_ID = 'client-id' const AZURE_CLIENT_SECRET = 'client-secret' @@ -44,6 +45,12 @@ describe('DotenvAzure', () => { expect(await dotenvAzure.config()).toBeDefined() }) + it('does not throw when AZURE_APP_CONFIG_LABELS is defined', async () => { + process.env = { ...OLD_ENV, AZURE_APP_CONFIG_CONNECTION_STRING, AZURE_APP_CONFIG_LABELS } + const dotenvAzure = new DotenvAzure() + expect(await dotenvAzure.config()).toBeDefined() + }) + it('throws when AZURE_APP_CONFIG_URL and AZURE_APP_CONFIG_CONNECTION_STRING are not defined', () => { const dotenvAzure = new DotenvAzure() expect(dotenvAzure.config()).rejects.toThrowError(MissingAppConfigCredentialsError)