mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 12:57:29 -08:00
feat: Introduce Azure Key Vault as external secrets provider (#10054)
This commit is contained in:
parent
5a9a2713b4
commit
1b6c2d3a37
|
@ -81,6 +81,8 @@
|
|||
"ts-essentials": "^7.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@azure/identity": "^4.3.0",
|
||||
"@azure/keyvault-secrets": "^4.8.0",
|
||||
"@n8n/client-oauth2": "workspace:*",
|
||||
"@n8n/config": "workspace:*",
|
||||
"@n8n/localtunnel": "2.1.0",
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Service } from 'typedi';
|
|||
import { InfisicalProvider } from './providers/infisical';
|
||||
import { VaultProvider } from './providers/vault';
|
||||
import { AwsSecretsManager } from './providers/aws-secrets/aws-secrets-manager';
|
||||
import { AzureKeyVault } from './providers/azure-key-vault/azure-key-vault';
|
||||
|
||||
@Service()
|
||||
export class ExternalSecretsProviders {
|
||||
|
@ -10,6 +11,7 @@ export class ExternalSecretsProviders {
|
|||
awsSecretsManager: AwsSecretsManager,
|
||||
infisical: InfisicalProvider,
|
||||
vault: VaultProvider,
|
||||
azureKeyVault: AzureKeyVault,
|
||||
};
|
||||
|
||||
getProvider(name: string): { new (): SecretsProvider } | null {
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
import type { INodeProperties } from 'n8n-workflow';
|
||||
|
||||
export const EXTERNAL_SECRETS_DB_KEY = 'feature.externalSecrets';
|
||||
export const EXTERNAL_SECRETS_INITIAL_BACKOFF = 10 * 1000;
|
||||
export const EXTERNAL_SECRETS_MAX_BACKOFF = 5 * 60 * 1000;
|
||||
|
||||
export const EXTERNAL_SECRETS_NAME_REGEX = /^[a-zA-Z0-9\-\_\/]+$/;
|
||||
|
||||
export const DOCS_HELP_NOTICE: INodeProperties = {
|
||||
displayName:
|
||||
'Need help filling out these fields? <a href="https://docs.n8n.io/external-secrets/#connect-n8n-to-your-secrets-store" target="_blank">Open docs</a>',
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
noDataExpression: true,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
import { SecretClient } from '@azure/keyvault-secrets';
|
||||
import type { KeyVaultSecret } from '@azure/keyvault-secrets';
|
||||
import { AzureKeyVault } from '../azure-key-vault/azure-key-vault';
|
||||
import { mock } from 'jest-mock-extended';
|
||||
import type { AzureKeyVaultContext } from '../azure-key-vault/types';
|
||||
|
||||
jest.mock('@azure/identity');
|
||||
jest.mock('@azure/keyvault-secrets');
|
||||
|
||||
describe('AzureKeyVault', () => {
|
||||
const azureKeyVault = new AzureKeyVault();
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('should update cached secrets', async () => {
|
||||
/**
|
||||
* Arrange
|
||||
*/
|
||||
await azureKeyVault.init(
|
||||
mock<AzureKeyVaultContext>({
|
||||
settings: {
|
||||
vaultName: 'my-vault',
|
||||
tenantId: 'my-tenant-id',
|
||||
clientId: 'my-client-id',
|
||||
clientSecret: 'my-client-secret',
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const listSpy = jest
|
||||
.spyOn(SecretClient.prototype, 'listPropertiesOfSecrets')
|
||||
// @ts-expect-error Partial mock
|
||||
.mockImplementation(() => ({
|
||||
async *[Symbol.asyncIterator]() {
|
||||
yield { name: 'secret1' };
|
||||
yield { name: 'secret2' };
|
||||
yield { name: 'secret3' }; // no value
|
||||
yield { name: '#@&' }; // invalid name
|
||||
},
|
||||
}));
|
||||
|
||||
const getSpy = jest
|
||||
.spyOn(SecretClient.prototype, 'getSecret')
|
||||
.mockImplementation(async (name: string) => {
|
||||
return mock<KeyVaultSecret>({ value: { secret1: 'value1', secret2: 'value2' }[name] });
|
||||
});
|
||||
|
||||
/**
|
||||
* Act
|
||||
*/
|
||||
await azureKeyVault.connect();
|
||||
await azureKeyVault.update();
|
||||
|
||||
/**
|
||||
* Assert
|
||||
*/
|
||||
expect(listSpy).toHaveBeenCalled();
|
||||
expect(getSpy).toHaveBeenCalledWith('secret1');
|
||||
expect(getSpy).toHaveBeenCalledWith('secret2');
|
||||
expect(getSpy).toHaveBeenCalledWith('secret3');
|
||||
expect(getSpy).not.toHaveBeenCalledWith('#@&');
|
||||
|
||||
expect(azureKeyVault.getSecret('secret1')).toBe('value1');
|
||||
expect(azureKeyVault.getSecret('secret2')).toBe('value2');
|
||||
expect(azureKeyVault.getSecret('secret3')).toBeUndefined(); // no value
|
||||
expect(azureKeyVault.getSecret('#@&')).toBeUndefined(); // invalid name
|
||||
});
|
||||
});
|
|
@ -1,6 +1,6 @@
|
|||
import { AwsSecretsClient } from './aws-secrets-client';
|
||||
import { UnknownAuthTypeError } from '@/errors/unknown-auth-type.error';
|
||||
import { EXTERNAL_SECRETS_NAME_REGEX } from '@/ExternalSecrets/constants';
|
||||
import { DOCS_HELP_NOTICE, EXTERNAL_SECRETS_NAME_REGEX } from '@/ExternalSecrets/constants';
|
||||
import type { SecretsProvider, SecretsProviderState } from '@/Interfaces';
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
import type { AwsSecretsManagerContext } from './types';
|
||||
|
@ -13,14 +13,7 @@ export class AwsSecretsManager implements SecretsProvider {
|
|||
state: SecretsProviderState = 'initializing';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName:
|
||||
'Need help filling out these fields? <a href="https://docs.n8n.io/external-secrets/#connect-n8n-to-your-secrets-store" target="_blank">Open docs</a>',
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
noDataExpression: true,
|
||||
},
|
||||
DOCS_HELP_NOTICE,
|
||||
{
|
||||
displayName: 'Region',
|
||||
name: 'region',
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { SecretClient } from '@azure/keyvault-secrets';
|
||||
import type { SecretsProvider, SecretsProviderState } from '@/Interfaces';
|
||||
import type { INodeProperties } from 'n8n-workflow';
|
||||
import type { AzureKeyVaultContext } from './types';
|
||||
import { DOCS_HELP_NOTICE, EXTERNAL_SECRETS_NAME_REGEX } from '@/ExternalSecrets/constants';
|
||||
|
||||
export class AzureKeyVault implements SecretsProvider {
|
||||
name = 'azureKeyVault';
|
||||
|
||||
displayName = 'Azure Key Vault';
|
||||
|
||||
state: SecretsProviderState = 'initializing';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
DOCS_HELP_NOTICE,
|
||||
{
|
||||
displayName: 'Vault Name',
|
||||
hint: 'The name of your existing Azure Key Vault.',
|
||||
name: 'vaultName',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
placeholder: 'e.g. my-vault',
|
||||
noDataExpression: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Tenant ID',
|
||||
name: 'tenantId',
|
||||
hint: 'In Azure, this can be called "Directory (Tenant) ID".',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
placeholder: 'e.g. 7dec9324-7074-72b7-a3ca-a9bb3012f466',
|
||||
noDataExpression: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client ID',
|
||||
name: 'clientId',
|
||||
hint: 'In Azure, this can be called "Application (Client) ID".',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
placeholder: 'e.g. 7753d8c2-e41f-22ed-3dd7-c9e96463622c',
|
||||
typeOptions: { password: true },
|
||||
noDataExpression: true,
|
||||
},
|
||||
{
|
||||
displayName: 'Client Secret',
|
||||
name: 'clientSecret',
|
||||
hint: 'The client secret value of your registered application.',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
typeOptions: { password: true },
|
||||
noDataExpression: true,
|
||||
},
|
||||
];
|
||||
|
||||
private cachedSecrets: Record<string, string> = {};
|
||||
|
||||
private client: SecretClient;
|
||||
|
||||
private settings: AzureKeyVaultContext['settings'];
|
||||
|
||||
async init(context: AzureKeyVaultContext) {
|
||||
this.settings = context.settings;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
const { vaultName, tenantId, clientId, clientSecret } = this.settings;
|
||||
|
||||
try {
|
||||
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
|
||||
this.client = new SecretClient(`https://${vaultName}.vault.azure.net/`, credential);
|
||||
this.state = 'connected';
|
||||
} catch (error) {
|
||||
this.state = 'error';
|
||||
}
|
||||
}
|
||||
|
||||
async test(): Promise<[boolean] | [boolean, string]> {
|
||||
if (!this.client) return [false, 'Failed to connect to Azure Key Vault'];
|
||||
|
||||
try {
|
||||
await this.client.listPropertiesOfSecrets().next();
|
||||
return [true];
|
||||
} catch (error: unknown) {
|
||||
return [false, error instanceof Error ? error.message : 'unknown error'];
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
// unused
|
||||
}
|
||||
|
||||
async update() {
|
||||
const secretNames: string[] = [];
|
||||
|
||||
for await (const secret of this.client.listPropertiesOfSecrets()) {
|
||||
secretNames.push(secret.name);
|
||||
}
|
||||
|
||||
const promises = secretNames
|
||||
.filter((name) => EXTERNAL_SECRETS_NAME_REGEX.test(name))
|
||||
.map(async (name) => {
|
||||
const { value } = await this.client.getSecret(name);
|
||||
return { name, value };
|
||||
});
|
||||
|
||||
const secrets = await Promise.all(promises);
|
||||
|
||||
this.cachedSecrets = secrets.reduce<Record<string, string>>((acc, cur) => {
|
||||
if (cur.value === undefined) return acc;
|
||||
acc[cur.name] = cur.value;
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
getSecret(name: string) {
|
||||
return this.cachedSecrets[name];
|
||||
}
|
||||
|
||||
hasSecret(name: string) {
|
||||
return name in this.cachedSecrets;
|
||||
}
|
||||
|
||||
getSecretNames() {
|
||||
return Object.keys(this.cachedSecrets);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import type { SecretsProviderSettings } from '@/Interfaces';
|
||||
|
||||
export type AzureKeyVaultContext = SecretsProviderSettings<{
|
||||
vaultName: string;
|
||||
tenantId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
}>;
|
|
@ -3,7 +3,7 @@ import InfisicalClient from 'infisical-node';
|
|||
import { populateClientWorkspaceConfigsHelper } from 'infisical-node/lib/helpers/key';
|
||||
import { getServiceTokenData } from 'infisical-node/lib/api/serviceTokenData';
|
||||
import { ApplicationError, type IDataObject, type INodeProperties } from 'n8n-workflow';
|
||||
import { EXTERNAL_SECRETS_NAME_REGEX } from '../constants';
|
||||
import { DOCS_HELP_NOTICE, EXTERNAL_SECRETS_NAME_REGEX } from '../constants';
|
||||
|
||||
export interface InfisicalSettings {
|
||||
token: string;
|
||||
|
@ -24,13 +24,7 @@ interface InfisicalServiceToken {
|
|||
|
||||
export class InfisicalProvider implements SecretsProvider {
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName:
|
||||
'Need help filling out these fields? <a href="https://docs.n8n.io/external-secrets/#connect-n8n-to-your-secrets-store" target="_blank">Open docs</a>',
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
},
|
||||
DOCS_HELP_NOTICE,
|
||||
{
|
||||
displayName: 'Service Token',
|
||||
name: 'token',
|
||||
|
|
|
@ -4,7 +4,7 @@ import type { IDataObject, INodeProperties } from 'n8n-workflow';
|
|||
import type { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import axios from 'axios';
|
||||
import { Logger } from '@/Logger';
|
||||
import { EXTERNAL_SECRETS_NAME_REGEX } from '../constants';
|
||||
import { DOCS_HELP_NOTICE, EXTERNAL_SECRETS_NAME_REGEX } from '../constants';
|
||||
import { preferGet } from '../externalSecretsHelper.ee';
|
||||
import { Container } from 'typedi';
|
||||
|
||||
|
@ -85,13 +85,7 @@ interface VaultSecretList {
|
|||
|
||||
export class VaultProvider extends SecretsProvider {
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName:
|
||||
'Need help filling out these fields? <a href="https://docs.n8n.io/external-secrets/#connect-n8n-to-your-secrets-store" target="_blank">Open docs</a>',
|
||||
name: 'notice',
|
||||
type: 'notice',
|
||||
default: '',
|
||||
},
|
||||
DOCS_HELP_NOTICE,
|
||||
{
|
||||
displayName: 'Vault URL',
|
||||
name: 'url',
|
||||
|
|
23
packages/editor-ui/src/assets/images/azure-key-vault.svg
Normal file
23
packages/editor-ui/src/assets/images/azure-key-vault.svg
Normal file
|
@ -0,0 +1,23 @@
|
|||
<svg width="150" height="150" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="e399c19f-b68f-429d-b176-18c2117ff73c" x1="-1032.172" x2="-1059.213" y1="145.312" y2="65.426" gradientTransform="matrix(1 0 0 -1 1075 158)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#114a8b"/>
|
||||
<stop offset="1" stop-color="#0669bc"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="ac2a6fc2-ca48-4327-9a3c-d4dcc3256e15" x1="-1023.725" x2="-1029.98" y1="108.083" y2="105.968" gradientTransform="matrix(1 0 0 -1 1075 158)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-opacity=".3"/>
|
||||
<stop offset=".071" stop-opacity=".2"/>
|
||||
<stop offset=".321" stop-opacity=".1"/>
|
||||
<stop offset=".623" stop-opacity=".05"/>
|
||||
<stop offset="1" stop-opacity="0"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="a7fee970-a784-4bb1-af8d-63d18e5f7db9" x1="-1027.165" x2="-997.482" y1="147.642" y2="68.561" gradientTransform="matrix(1 0 0 -1 1075 158)" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0" stop-color="#3ccbf4"/>
|
||||
<stop offset="1" stop-color="#2892df"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<path fill="url(#e399c19f-b68f-429d-b176-18c2117ff73c)" d="M33.338 6.544h26.038l-27.03 80.087a4.152 4.152 0 0 1-3.933 2.824H8.149a4.145 4.145 0 0 1-3.928-5.47L29.404 9.368a4.152 4.152 0 0 1 3.934-2.825z"/>
|
||||
<path fill="#0078d4" d="M71.175 60.261h-41.29a1.911 1.911 0 0 0-1.305 3.309l26.532 24.764a4.171 4.171 0 0 0 2.846 1.121h23.38z"/>
|
||||
<path fill="url(#ac2a6fc2-ca48-4327-9a3c-d4dcc3256e15)" d="M33.338 6.544a4.118 4.118 0 0 0-3.943 2.879L4.252 83.917a4.14 4.14 0 0 0 3.908 5.538h20.787a4.443 4.443 0 0 0 3.41-2.9l5.014-14.777 17.91 16.705a4.237 4.237 0 0 0 2.666.972H81.24L71.024 60.261l-29.781.007L59.47 6.544z"/>
|
||||
<path fill="url(#a7fee970-a784-4bb1-af8d-63d18e5f7db9)" d="M66.595 9.364a4.145 4.145 0 0 0-3.928-2.82H33.648a4.146 4.146 0 0 1 3.928 2.82l25.184 74.62a4.146 4.146 0 0 1-3.928 5.472h29.02a4.146 4.146 0 0 0 3.927-5.472z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -6,6 +6,7 @@ import infisical from '../assets/images/infisical.webp';
|
|||
import doppler from '../assets/images/doppler.webp';
|
||||
import vault from '../assets/images/hashicorp.webp';
|
||||
import awsSecretsManager from '../assets/images/aws-secrets-manager.svg';
|
||||
import azureKeyVault from '../assets/images/azure-key-vault.svg';
|
||||
|
||||
const props = defineProps<{
|
||||
provider: ExternalSecretsProvider;
|
||||
|
@ -18,6 +19,7 @@ const image = computed(
|
|||
infisical,
|
||||
vault,
|
||||
awsSecretsManager,
|
||||
azureKeyVault,
|
||||
})[props.provider.name],
|
||||
);
|
||||
</script>
|
||||
|
|
127
pnpm-lock.yaml
127
pnpm-lock.yaml
|
@ -538,6 +538,12 @@ importers:
|
|||
|
||||
packages/cli:
|
||||
dependencies:
|
||||
'@azure/identity':
|
||||
specifier: ^4.3.0
|
||||
version: 4.3.0
|
||||
'@azure/keyvault-secrets':
|
||||
specifier: ^4.8.0
|
||||
version: 4.8.0
|
||||
'@n8n/client-oauth2':
|
||||
specifier: workspace:*
|
||||
version: link:../@n8n/client-oauth2
|
||||
|
@ -1978,14 +1984,18 @@ packages:
|
|||
resolution: {integrity: sha512-3X9wzaaGgRaBCwhLQZDtFp5uLIXCPrGbwJNWPPugvL4xbIGgScv77YzzxToKGLAKvG9amDoofMoP+9hsH1vs1w==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@azure/core-client@1.6.1':
|
||||
resolution: {integrity: sha512-mZ1MSKhZBYoV8GAWceA+PEJFWV2VpdNSpxxcj1wjIAOi00ykRuIQChT99xlQGZWLY3/NApWhSImlFwsmCEs4vA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
'@azure/core-client@1.9.2':
|
||||
resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@azure/core-http-compat@1.3.0':
|
||||
resolution: {integrity: sha512-ZN9avruqbQ5TxopzG3ih3KRy52n8OAbitX3fnZT5go4hzu0J+KVPSzkL+Wt3hpJpdG8WIfg1sBD1tWkgUdEpBA==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@azure/core-http-compat@2.1.2':
|
||||
resolution: {integrity: sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@azure/core-http@2.3.2':
|
||||
resolution: {integrity: sha512-Z4dfbglV9kNZO177CNx4bo5ekFuYwwsvjLiKdZI4r84bYGv3irrbQz7JC3/rUfFH2l4T/W6OFleJaa2X0IaQqw==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
@ -2018,10 +2028,18 @@ packages:
|
|||
resolution: {integrity: sha512-0q5DL4uyR0EZ4RXQKD8MadGH6zTIcloUoS/RVbCpNpej4pwte0xpqYxk8K97Py2RiuUvI7F4GXpoT4046VfufA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@azure/identity@4.3.0':
|
||||
resolution: {integrity: sha512-LHZ58/RsIpIWa4hrrE2YuJ/vzG1Jv9f774RfTTAVDZDriubvJ0/S5u4pnw4akJDlS0TiJb6VMphmVUFsWmgodQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@azure/keyvault-keys@4.6.0':
|
||||
resolution: {integrity: sha512-0112LegxeR03L8J4k+q6HwBVvrpd9y+oInG0FG3NaHXN7YUubVBon/eb5jFI6edGrvNigpxSR0XIsprFXdkzCQ==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
||||
'@azure/keyvault-secrets@4.8.0':
|
||||
resolution: {integrity: sha512-RGfpFk6XUXHfWuTAiokOe8t6ej5C4ijf4HVyJUmTfN6VjDBVPvTtoiOi/C5072/ENHScYZFhiYOgIjLgYjfJ/A==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@azure/logger@1.0.3':
|
||||
resolution: {integrity: sha512-aK4s3Xxjrx3daZr3VylxejK3vG5ExXck5WOHDJ8in/k9AqlfIyFMMT1uG7u8mNjX+QRILTIn0/Xgschfh/dQ9g==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
|
@ -2030,10 +2048,22 @@ packages:
|
|||
resolution: {integrity: sha512-mnmi8dCXVNZI+AGRq0jKQ3YiodlIC4W9npr6FCB9WN6NQT+6rq+cIlxgUb//BjLyzKsnYo+i4LROGeMyU+6v1A==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
'@azure/msal-browser@3.19.0':
|
||||
resolution: {integrity: sha512-3unHlh3qWtXbqks/TLq3qGWzxfmwRfk9tXSGvVCcHHnCH5QKtcg/JiDIeP/1B2qFlqnSgtYY0JPLy9EIVoZ7Ag==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
'@azure/msal-common@14.13.0':
|
||||
resolution: {integrity: sha512-b4M/tqRzJ4jGU91BiwCsLTqChveUEyFK3qY2wGfZ0zBswIBZjAxopx5CYt5wzZFKuN15HqRDYXQbztttuIC3nA==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
'@azure/msal-common@14.7.1':
|
||||
resolution: {integrity: sha512-v96btzjM7KrAu4NSEdOkhQSTGOuNUIIsUdB8wlyB9cdgl5KqEKnTonHUZ8+khvZ6Ap542FCErbnTyDWl8lZ2rA==}
|
||||
engines: {node: '>=0.8.0'}
|
||||
|
||||
'@azure/msal-node@2.11.0':
|
||||
resolution: {integrity: sha512-yNRCp4Do4CGSBe1WXq4DWhfa/vYZCUgGrweYLC5my/6eDnYMt0fYGPHuTMw0iRslQGXF3CecGAxXp7ab57V4zg==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
'@azure/msal-node@2.6.4':
|
||||
resolution: {integrity: sha512-nNvEPx009/80UATCToF+29NZYocn01uKrB91xtFr7bSqkqO1PuQGXRyYwryWRztUrYZ1YsSbw9A+LmwOhpVvcg==}
|
||||
engines: {node: '>=16'}
|
||||
|
@ -14146,9 +14176,9 @@ snapshots:
|
|||
'@azure/core-util': 1.7.0
|
||||
tslib: 2.6.2
|
||||
|
||||
'@azure/core-client@1.6.1':
|
||||
'@azure/core-client@1.9.2':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/abort-controller': 2.0.0
|
||||
'@azure/core-auth': 1.6.0
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
'@azure/core-tracing': 1.0.1
|
||||
|
@ -14161,7 +14191,15 @@ snapshots:
|
|||
'@azure/core-http-compat@1.3.0':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/core-client': 1.6.1
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@azure/core-http-compat@2.1.2':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 2.0.0
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -14229,7 +14267,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/core-auth': 1.6.0
|
||||
'@azure/core-client': 1.6.1
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
'@azure/core-tracing': 1.0.1
|
||||
'@azure/core-util': 1.7.0
|
||||
|
@ -14244,11 +14282,30 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@azure/identity@4.3.0':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/core-auth': 1.6.0
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
'@azure/core-tracing': 1.0.1
|
||||
'@azure/core-util': 1.7.0
|
||||
'@azure/logger': 1.0.3
|
||||
'@azure/msal-browser': 3.19.0
|
||||
'@azure/msal-node': 2.11.0
|
||||
events: 3.3.0
|
||||
jws: 4.0.0
|
||||
open: 8.4.0
|
||||
stoppable: 1.1.0
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@azure/keyvault-keys@4.6.0':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/core-auth': 1.6.0
|
||||
'@azure/core-client': 1.6.1
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-http-compat': 1.3.0
|
||||
'@azure/core-lro': 2.4.0
|
||||
'@azure/core-paging': 1.3.0
|
||||
|
@ -14260,6 +14317,22 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@azure/keyvault-secrets@4.8.0':
|
||||
dependencies:
|
||||
'@azure/abort-controller': 1.1.0
|
||||
'@azure/core-auth': 1.6.0
|
||||
'@azure/core-client': 1.9.2
|
||||
'@azure/core-http-compat': 2.1.2
|
||||
'@azure/core-lro': 2.4.0
|
||||
'@azure/core-paging': 1.3.0
|
||||
'@azure/core-rest-pipeline': 1.9.2
|
||||
'@azure/core-tracing': 1.0.1
|
||||
'@azure/core-util': 1.7.0
|
||||
'@azure/logger': 1.0.3
|
||||
tslib: 2.6.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@azure/logger@1.0.3':
|
||||
dependencies:
|
||||
tslib: 2.6.2
|
||||
|
@ -14268,8 +14341,20 @@ snapshots:
|
|||
dependencies:
|
||||
'@azure/msal-common': 14.7.1
|
||||
|
||||
'@azure/msal-browser@3.19.0':
|
||||
dependencies:
|
||||
'@azure/msal-common': 14.13.0
|
||||
|
||||
'@azure/msal-common@14.13.0': {}
|
||||
|
||||
'@azure/msal-common@14.7.1': {}
|
||||
|
||||
'@azure/msal-node@2.11.0':
|
||||
dependencies:
|
||||
'@azure/msal-common': 14.13.0
|
||||
jsonwebtoken: 9.0.2
|
||||
uuid: 8.3.2
|
||||
|
||||
'@azure/msal-node@2.6.4':
|
||||
dependencies:
|
||||
'@azure/msal-common': 14.7.1
|
||||
|
@ -14320,7 +14405,7 @@ snapshots:
|
|||
'@babel/traverse': 7.24.0
|
||||
'@babel/types': 7.24.0
|
||||
convert-source-map: 2.0.0
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
gensync: 1.0.0-beta.2
|
||||
json5: 2.2.3
|
||||
semver: 7.6.0
|
||||
|
@ -14441,7 +14526,7 @@ snapshots:
|
|||
'@babel/core': 7.24.6
|
||||
'@babel/helper-compilation-targets': 7.24.6
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
|
@ -14452,7 +14537,7 @@ snapshots:
|
|||
'@babel/core': 7.24.6
|
||||
'@babel/helper-compilation-targets': 7.24.6
|
||||
'@babel/helper-plugin-utils': 7.24.6
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
lodash.debounce: 4.0.8
|
||||
resolve: 1.22.8
|
||||
transitivePeerDependencies:
|
||||
|
@ -15336,7 +15421,7 @@ snapshots:
|
|||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/parser': 7.24.0
|
||||
'@babel/types': 7.24.0
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -15351,7 +15436,7 @@ snapshots:
|
|||
'@babel/helper-split-export-declaration': 7.24.6
|
||||
'@babel/parser': 7.24.6
|
||||
'@babel/types': 7.24.6
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -18923,7 +19008,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@typescript-eslint/types': 6.7.5
|
||||
'@typescript-eslint/visitor-keys': 6.7.5
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.6.0
|
||||
|
@ -19344,7 +19429,7 @@ snapshots:
|
|||
|
||||
agent-base@7.1.0:
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -20790,7 +20875,7 @@ snapshots:
|
|||
detect-port@1.5.1:
|
||||
dependencies:
|
||||
address: 1.2.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -21168,7 +21253,7 @@ snapshots:
|
|||
|
||||
esbuild-register@3.5.0(esbuild@0.20.2):
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
esbuild: 0.20.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
@ -22405,7 +22490,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@tootallnate/once': 1.1.2
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
optional: true
|
||||
|
@ -22414,7 +22499,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@tootallnate/once': 2.0.0
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
@ -22823,7 +22908,7 @@ snapshots:
|
|||
|
||||
istanbul-lib-source-maps@4.0.1:
|
||||
dependencies:
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
source-map: 0.6.1
|
||||
transitivePeerDependencies:
|
||||
|
@ -26241,7 +26326,7 @@ snapshots:
|
|||
socks-proxy-agent@6.2.1:
|
||||
dependencies:
|
||||
agent-base: 6.0.2
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
debug: 4.3.5(supports-color@8.1.1)
|
||||
socks: 2.7.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
|
Loading…
Reference in a new issue