@achs/env 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +3 -0
- package/.eslintrc.json +329 -0
- package/.vscode/extensions.json +18 -0
- package/.vscode/launch.json +30 -0
- package/.vscode/settings.json +29 -0
- package/CHANGELOG.md +13 -0
- package/README.md +14 -7
- package/jest.config.json +28 -0
- package/package.json +16 -16
- package/{arguments.js → src/arguments.ts} +38 -14
- package/src/commands/env.command.ts +139 -0
- package/src/commands/export.command.ts +88 -0
- package/{commands/index.d.ts → src/commands/index.ts} +0 -1
- package/src/commands/pull.command.ts +52 -0
- package/src/commands/push.command.ts +48 -0
- package/src/commands/schema.command.ts +31 -0
- package/src/exec.ts +221 -0
- package/{index.d.ts → src/index.ts} +0 -1
- package/{interfaces/index.d.ts → src/interfaces/index.ts} +0 -1
- package/src/interfaces/loader.interface.ts +66 -0
- package/src/main.ts +6 -0
- package/src/providers/app-settings.provider.ts +67 -0
- package/src/providers/azure-key-vault.provider.ts +277 -0
- package/src/providers/index.ts +29 -0
- package/src/providers/local.provider.ts +44 -0
- package/src/providers/package-json.provider.ts +39 -0
- package/src/utils/command.util.ts +223 -0
- package/{utils/index.d.ts → src/utils/index.ts} +0 -1
- package/src/utils/interpolate.util.ts +65 -0
- package/src/utils/json.util.ts +116 -0
- package/{utils/logger.js → src/utils/logger.ts} +6 -6
- package/src/utils/normalize.util.ts +142 -0
- package/src/utils/schema.util.ts +191 -0
- package/tests/env/appsettings.json +32 -0
- package/tests/env/dev.env.json +12 -0
- package/tests/env/dev.local.env.json +9 -0
- package/tests/env/env.schema.json +225 -0
- package/tests/env/keys.json +7 -0
- package/tests/env/settings/schema.json +239 -0
- package/tests/env/settings/settings.json +22 -0
- package/tests/env.int.test.ts +42 -0
- package/tests/exec.ts +19 -0
- package/tests/export.int.test.ts +9 -0
- package/tests/pull-push.int.test.ts +15 -0
- package/tests/run.js +32 -0
- package/tests/schema.int.test.ts +9 -0
- package/tests/setup.ts +13 -0
- package/tsconfig.build.json +10 -0
- package/tsconfig.json +37 -0
- package/arguments.d.ts +0 -25
- package/arguments.d.ts.map +0 -1
- package/arguments.js.map +0 -1
- package/commands/env.command.d.ts +0 -8
- package/commands/env.command.d.ts.map +0 -1
- package/commands/env.command.js +0 -85
- package/commands/env.command.js.map +0 -1
- package/commands/export.command.d.ts +0 -8
- package/commands/export.command.d.ts.map +0 -1
- package/commands/export.command.js +0 -54
- package/commands/export.command.js.map +0 -1
- package/commands/index.d.ts.map +0 -1
- package/commands/index.js +0 -14
- package/commands/index.js.map +0 -1
- package/commands/pull.command.d.ts +0 -7
- package/commands/pull.command.d.ts.map +0 -1
- package/commands/pull.command.js +0 -39
- package/commands/pull.command.js.map +0 -1
- package/commands/push.command.d.ts +0 -7
- package/commands/push.command.d.ts.map +0 -1
- package/commands/push.command.js +0 -38
- package/commands/push.command.js.map +0 -1
- package/commands/schema.command.d.ts +0 -4
- package/commands/schema.command.d.ts.map +0 -1
- package/commands/schema.command.js +0 -18
- package/commands/schema.command.js.map +0 -1
- package/exec.d.ts +0 -3
- package/exec.d.ts.map +0 -1
- package/exec.js +0 -142
- package/exec.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js +0 -20
- package/index.js.map +0 -1
- package/interfaces/index.d.ts.map +0 -1
- package/interfaces/index.js +0 -18
- package/interfaces/index.js.map +0 -1
- package/interfaces/loader.interface.d.ts +0 -21
- package/interfaces/loader.interface.d.ts.map +0 -1
- package/interfaces/loader.interface.js +0 -3
- package/interfaces/loader.interface.js.map +0 -1
- package/main.d.ts +0 -3
- package/main.d.ts.map +0 -1
- package/main.js +0 -6
- package/main.js.map +0 -1
- package/providers/app-settings.provider.d.ts +0 -8
- package/providers/app-settings.provider.d.ts.map +0 -1
- package/providers/app-settings.provider.js +0 -50
- package/providers/app-settings.provider.js.map +0 -1
- package/providers/azure-key-vault.provider.d.ts +0 -22
- package/providers/azure-key-vault.provider.d.ts.map +0 -1
- package/providers/azure-key-vault.provider.js +0 -164
- package/providers/azure-key-vault.provider.js.map +0 -1
- package/providers/index.d.ts +0 -8
- package/providers/index.d.ts.map +0 -1
- package/providers/index.js +0 -28
- package/providers/index.js.map +0 -1
- package/providers/package-json.provider.d.ts +0 -8
- package/providers/package-json.provider.d.ts.map +0 -1
- package/providers/package-json.provider.js +0 -29
- package/providers/package-json.provider.js.map +0 -1
- package/tsconfig.build.tsbuildinfo +0 -1
- package/utils/command.util.d.ts +0 -13
- package/utils/command.util.d.ts.map +0 -1
- package/utils/command.util.js +0 -134
- package/utils/command.util.js.map +0 -1
- package/utils/index.d.ts.map +0 -1
- package/utils/index.js +0 -23
- package/utils/index.js.map +0 -1
- package/utils/interpolate.util.d.ts +0 -4
- package/utils/interpolate.util.d.ts.map +0 -1
- package/utils/interpolate.util.js +0 -33
- package/utils/interpolate.util.js.map +0 -1
- package/utils/json.util.d.ts +0 -5
- package/utils/json.util.d.ts.map +0 -1
- package/utils/json.util.js +0 -48
- package/utils/json.util.js.map +0 -1
- package/utils/logger.d.ts +0 -3
- package/utils/logger.d.ts.map +0 -1
- package/utils/logger.js.map +0 -1
- package/utils/normalize.util.d.ts +0 -3
- package/utils/normalize.util.d.ts.map +0 -1
- package/utils/normalize.util.js +0 -61
- package/utils/normalize.util.js.map +0 -1
- package/utils/schema.util.d.ts +0 -11
- package/utils/schema.util.d.ts.map +0 -1
- package/utils/schema.util.js +0 -100
- package/utils/schema.util.js.map +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Arguments, Argv } from 'yargs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Result of provider environment load.
|
|
5
|
+
*
|
|
6
|
+
* @export
|
|
7
|
+
* @type EnvResult
|
|
8
|
+
*/
|
|
9
|
+
export type EnvResult =
|
|
10
|
+
| Record<string, unknown>
|
|
11
|
+
| Record<string, unknown>[]
|
|
12
|
+
| Promise<Record<string, unknown>>
|
|
13
|
+
| Promise<Record<string, unknown>[]>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Wrapped provider result for inject to env.
|
|
17
|
+
*
|
|
18
|
+
* @export
|
|
19
|
+
* @interface EnvProviderResult
|
|
20
|
+
*/
|
|
21
|
+
export interface EnvProviderResult {
|
|
22
|
+
key: string;
|
|
23
|
+
config?: Record<string, unknown>;
|
|
24
|
+
value: Record<string, any> | Record<string, any>[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Provider handler.
|
|
29
|
+
*
|
|
30
|
+
* @export
|
|
31
|
+
* @interface EnvProvider
|
|
32
|
+
* @template A define arguments used by provider
|
|
33
|
+
* @template C define config used by provider
|
|
34
|
+
*/
|
|
35
|
+
export interface EnvProvider<
|
|
36
|
+
A,
|
|
37
|
+
C extends Record<string, any> | undefined = undefined
|
|
38
|
+
> {
|
|
39
|
+
// unique key
|
|
40
|
+
key: string;
|
|
41
|
+
|
|
42
|
+
// modifies command building (adds or modifies commands, options .etc)
|
|
43
|
+
builder?: (builder: Argv<unknown>) => void;
|
|
44
|
+
|
|
45
|
+
// loads environment variables.
|
|
46
|
+
load: (argv: Arguments<A>, config?: C) => EnvResult | never;
|
|
47
|
+
|
|
48
|
+
// pulls vars
|
|
49
|
+
pull?: (argv: Arguments<A>, config?: C) => void;
|
|
50
|
+
|
|
51
|
+
// push vars
|
|
52
|
+
push?: (argv: Arguments<A>, config?: C) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Provider definition for config file.
|
|
57
|
+
*
|
|
58
|
+
* @export
|
|
59
|
+
* @interface EnvProviderConfig
|
|
60
|
+
*/
|
|
61
|
+
export interface EnvProviderConfig {
|
|
62
|
+
path: string;
|
|
63
|
+
type: 'integrated' | 'module' | 'script';
|
|
64
|
+
handler: EnvProvider<any, any>;
|
|
65
|
+
config?: Record<string, unknown>;
|
|
66
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { CommandArguments } from '../arguments';
|
|
3
|
+
import { EnvProvider } from '../interfaces';
|
|
4
|
+
import { logger as globalLogger, readJson, writeJson } from '../utils';
|
|
5
|
+
|
|
6
|
+
const KEY = 'app-settings';
|
|
7
|
+
|
|
8
|
+
const logger = globalLogger.getChildLogger({
|
|
9
|
+
prefix: [chalk.bold.blue(`[${KEY}]`)]
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const APP_SETTINGS_DEFAULT = {
|
|
13
|
+
'|DEFAULT|': {},
|
|
14
|
+
'|MODE|': {},
|
|
15
|
+
'|ENV|': {},
|
|
16
|
+
'|LOCAL|': {}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
interface AppSettingsCommandArguments extends CommandArguments {
|
|
20
|
+
envFile: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Loads config from appsettings.json.
|
|
25
|
+
*/
|
|
26
|
+
export const AppSettingsProvider: EnvProvider<AppSettingsCommandArguments> = {
|
|
27
|
+
key: KEY,
|
|
28
|
+
|
|
29
|
+
builder: (builder) => {
|
|
30
|
+
builder.options({
|
|
31
|
+
envFile: {
|
|
32
|
+
group: KEY,
|
|
33
|
+
alias: 'ef',
|
|
34
|
+
type: 'string',
|
|
35
|
+
default: '[[root]]/appsettings.json',
|
|
36
|
+
describe: 'Environment variables file path (non secrets)'
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
load: async ({ env, modes = [], envFile, local }) => {
|
|
42
|
+
const [appsettings = APP_SETTINGS_DEFAULT, wasFound] = await readJson(
|
|
43
|
+
envFile
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (!wasFound) {
|
|
47
|
+
logger.warn(`${chalk.blue(envFile)} not found`);
|
|
48
|
+
|
|
49
|
+
logger.debug(`creating default ${chalk.blue(envFile)} file`);
|
|
50
|
+
|
|
51
|
+
await writeJson(envFile, APP_SETTINGS_DEFAULT);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// only load local in env load cmd
|
|
55
|
+
if (!local) appsettings['|LOCAL|'] = null;
|
|
56
|
+
|
|
57
|
+
return [
|
|
58
|
+
appsettings['|DEFAULT|'],
|
|
59
|
+
|
|
60
|
+
appsettings['|ENV|']?.[env],
|
|
61
|
+
|
|
62
|
+
...modes.map((mode) => appsettings['|MODE|']?.[mode]),
|
|
63
|
+
|
|
64
|
+
appsettings['|LOCAL|']?.[env]
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import {
|
|
3
|
+
AzureKeyVault,
|
|
4
|
+
AzureKeyVaultSecrets,
|
|
5
|
+
createAzureKeyVaultMock
|
|
6
|
+
} from '@achs/azure-key-vault';
|
|
7
|
+
import { CommandArguments } from '../arguments';
|
|
8
|
+
import { EnvProvider } from '../interfaces';
|
|
9
|
+
import {
|
|
10
|
+
generateSchemaFrom,
|
|
11
|
+
logger as globalLogger,
|
|
12
|
+
readJson,
|
|
13
|
+
schemaToJson,
|
|
14
|
+
writeJson
|
|
15
|
+
} from '../utils';
|
|
16
|
+
import { Arguments } from 'yargs';
|
|
17
|
+
import { existsSync } from 'fs';
|
|
18
|
+
import { PullCommandArguments } from 'commands/pull.command';
|
|
19
|
+
|
|
20
|
+
const KEY = 'azure-key-vault';
|
|
21
|
+
|
|
22
|
+
const logger = globalLogger.getChildLogger({
|
|
23
|
+
prefix: [chalk.bold.blue(`[${KEY}]`)]
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
interface AzureKeyVaultCommandArguments extends CommandArguments {
|
|
27
|
+
secretsFile: string;
|
|
28
|
+
keysFile?: string[];
|
|
29
|
+
vaultUrl: string;
|
|
30
|
+
spn: string;
|
|
31
|
+
password: string;
|
|
32
|
+
tenant: string;
|
|
33
|
+
mock: boolean;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface AzureKeyVaultCommandConfig {
|
|
37
|
+
[key: string]: {
|
|
38
|
+
vaultUrl: string;
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Loads secrets from env files in env/secrets
|
|
44
|
+
* folder, loaded from Azure Key Vault.
|
|
45
|
+
*/
|
|
46
|
+
export const AzureKeyVaultProvider: EnvProvider<
|
|
47
|
+
AzureKeyVaultCommandArguments & PullCommandArguments,
|
|
48
|
+
AzureKeyVaultCommandConfig
|
|
49
|
+
> = {
|
|
50
|
+
key: KEY,
|
|
51
|
+
|
|
52
|
+
builder: (builder) => {
|
|
53
|
+
builder.options({
|
|
54
|
+
secretsFile: {
|
|
55
|
+
group: KEY,
|
|
56
|
+
type: 'string',
|
|
57
|
+
default: '[[root]]/[[env]].env.json',
|
|
58
|
+
describe: 'Secret variables file path'
|
|
59
|
+
},
|
|
60
|
+
keysFile: {
|
|
61
|
+
group: KEY,
|
|
62
|
+
alias: ['k', 'keys'],
|
|
63
|
+
type: 'array',
|
|
64
|
+
default: ['[[root]]/keys.json', '../keys.json'],
|
|
65
|
+
describe: 'Azure Key Vault keys file path'
|
|
66
|
+
},
|
|
67
|
+
vaultUrl: {
|
|
68
|
+
group: KEY,
|
|
69
|
+
alias: 'url',
|
|
70
|
+
type: 'string',
|
|
71
|
+
describe: 'Azure Key Vault URL'
|
|
72
|
+
},
|
|
73
|
+
spn: {
|
|
74
|
+
group: KEY,
|
|
75
|
+
alias: ['clientId', 'id'],
|
|
76
|
+
type: 'string',
|
|
77
|
+
describe: 'SPN Client ID'
|
|
78
|
+
},
|
|
79
|
+
password: {
|
|
80
|
+
group: KEY,
|
|
81
|
+
alias: ['p', 'pass', 'clientSecret'],
|
|
82
|
+
type: 'string',
|
|
83
|
+
describe: 'SPN Client Secret Password'
|
|
84
|
+
},
|
|
85
|
+
tenant: {
|
|
86
|
+
group: KEY,
|
|
87
|
+
alias: 't',
|
|
88
|
+
type: 'string',
|
|
89
|
+
describe: 'Azure Tenant ID'
|
|
90
|
+
},
|
|
91
|
+
mock: {
|
|
92
|
+
group: KEY,
|
|
93
|
+
type: 'boolean',
|
|
94
|
+
default: false,
|
|
95
|
+
describe: 'Mocks Azure Key Vault client'
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
push: async (argv, config) => {
|
|
101
|
+
const [secrets, secretsWasFound] = await readJson(argv.secretsFile);
|
|
102
|
+
|
|
103
|
+
if (!secretsWasFound) {
|
|
104
|
+
logger.error(`${chalk.blue(argv.secretFile)} not found`);
|
|
105
|
+
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
logger.silly('local secrets loaded:', secrets);
|
|
110
|
+
const akv = await loadAzureKeyVaultClient(
|
|
111
|
+
argv,
|
|
112
|
+
config?.[argv.env]?.vaultUrl
|
|
113
|
+
);
|
|
114
|
+
logger.info('pushing variables to store');
|
|
115
|
+
const results = await akv.setAll(secrets);
|
|
116
|
+
logger.silly('secrets pushed:', results);
|
|
117
|
+
|
|
118
|
+
const schema = await generateSchemaFrom(
|
|
119
|
+
[{ key: KEY, value: secrets }],
|
|
120
|
+
argv
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
logger.silly('schema for akv updated:', schema);
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
pull: async (argv, config) => {
|
|
127
|
+
const schema = argv.schema?.[KEY] as
|
|
128
|
+
| Record<string, unknown>
|
|
129
|
+
| undefined;
|
|
130
|
+
|
|
131
|
+
if (!schema) {
|
|
132
|
+
logger.error('no schema found');
|
|
133
|
+
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const jsonTemplate = schemaToJson(schema) as Record<string, unknown>;
|
|
138
|
+
|
|
139
|
+
const akv = await loadAzureKeyVaultClient(
|
|
140
|
+
argv,
|
|
141
|
+
config?.[argv.env]?.vaultUrl
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
logger.info('pulling variables from store');
|
|
145
|
+
|
|
146
|
+
const secrets = await akv.getFor(
|
|
147
|
+
jsonTemplate as AzureKeyVaultSecrets,
|
|
148
|
+
true
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
logger.silly('remote secrets loaded:', secrets);
|
|
152
|
+
|
|
153
|
+
await writeJson(argv.secretsFile, secrets, argv.overwrite, true);
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
load: async (argv, config) => {
|
|
157
|
+
const { secretsFile } = argv;
|
|
158
|
+
|
|
159
|
+
if (!existsSync(secretsFile)) {
|
|
160
|
+
logger.warn('secrets file not found, pulling from store');
|
|
161
|
+
|
|
162
|
+
await AzureKeyVaultProvider.pull!(argv, config);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const [secrets] = await readJson(secretsFile);
|
|
166
|
+
|
|
167
|
+
return [secrets];
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Validate SPN credentials/keys.
|
|
173
|
+
*
|
|
174
|
+
* @param {(Record<string, any> | null)} keys
|
|
175
|
+
*
|
|
176
|
+
* @returns {boolean}
|
|
177
|
+
*/
|
|
178
|
+
function keysAreValid(keys: Record<string, any> | null): boolean {
|
|
179
|
+
return keys && keys.clientId && keys.clientSecret && keys.tenantId;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Loads SPN Azure Key Vault credentials from keys file.
|
|
184
|
+
*
|
|
185
|
+
* @param {string} env
|
|
186
|
+
* @param {string[]} paths
|
|
187
|
+
*
|
|
188
|
+
* @returns {Record<string, string>} credentials
|
|
189
|
+
*/
|
|
190
|
+
async function loadKeysFile(
|
|
191
|
+
env: string,
|
|
192
|
+
paths: string[]
|
|
193
|
+
): Promise<Record<string, string>> {
|
|
194
|
+
logger.debug(`searching keys at ${chalk.yellow(paths.join(','))}`);
|
|
195
|
+
|
|
196
|
+
const readers = await Promise.all(paths.map((path) => readJson(path)));
|
|
197
|
+
|
|
198
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
199
|
+
const [keys, wasFound] = readers.find(
|
|
200
|
+
([keys, wasFound]) => wasFound && keysAreValid(keys[env])
|
|
201
|
+
) ?? [null, false];
|
|
202
|
+
|
|
203
|
+
// if (!wasFound || !keys) {
|
|
204
|
+
// logger.error(`no credentials found for ${chalk.green.underline(env)}`);
|
|
205
|
+
// logger.warn(
|
|
206
|
+
// 'if you use Azure CLI, set "keysFile": null in your env.config file'
|
|
207
|
+
// );
|
|
208
|
+
|
|
209
|
+
// process.exit(1);
|
|
210
|
+
// }
|
|
211
|
+
|
|
212
|
+
return keys?.[env] ?? {};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Loads credentials and initializes Azure Key Vault client.
|
|
217
|
+
*
|
|
218
|
+
* @param {Arguments<AzureKeyVaultCommandArguments>} argv command arguments
|
|
219
|
+
*
|
|
220
|
+
* @returns {*} {Promise<AzureKeyVault>}
|
|
221
|
+
*/
|
|
222
|
+
async function loadAzureKeyVaultClient(
|
|
223
|
+
{
|
|
224
|
+
env,
|
|
225
|
+
vaultUrl,
|
|
226
|
+
spn,
|
|
227
|
+
password,
|
|
228
|
+
tenant,
|
|
229
|
+
app,
|
|
230
|
+
keysFile,
|
|
231
|
+
mock
|
|
232
|
+
}: Arguments<AzureKeyVaultCommandArguments>,
|
|
233
|
+
configVaultUrl?: string
|
|
234
|
+
): Promise<AzureKeyVault> {
|
|
235
|
+
let url = process.env.AZURE_VAULT_URL ?? vaultUrl ?? configVaultUrl;
|
|
236
|
+
|
|
237
|
+
const config = {
|
|
238
|
+
project: process.env.AZURE_PROJECT ?? (app?.project as string),
|
|
239
|
+
group: process.env.AZURE_GROUP ?? (app?.name as string),
|
|
240
|
+
env
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
if (!config.project) {
|
|
244
|
+
logger.error(
|
|
245
|
+
`no project info from ${chalk.blue('package.json')} found`
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const credentials = {
|
|
252
|
+
clientId: process.env.AZURE_CLIENT_ID ?? spn,
|
|
253
|
+
clientSecret: process.env.AZURE_CLIENT_SECRET ?? password,
|
|
254
|
+
tenantId: process.env.AZURE_TENANT_ID ?? tenant
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
if (keysFile && keysFile.length > 0 && !keysAreValid(credentials)) {
|
|
258
|
+
const keys = await loadKeysFile(env, keysFile);
|
|
259
|
+
|
|
260
|
+
url ??= keys.vaultUrl;
|
|
261
|
+
credentials.clientId ??= keys.clientId;
|
|
262
|
+
credentials.clientSecret ??= keys.clientSecret;
|
|
263
|
+
credentials.tenantId ??= keys.tenantId;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
logger.debug(
|
|
267
|
+
`credentials loaded for project ${chalk.bold.underline.yellowBright(
|
|
268
|
+
config.project
|
|
269
|
+
)} and group ${chalk.bold.underline.yellowBright(config.group)}`
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
logger.debug(`connected to ${chalk.bold.underline.greenBright(url)}`);
|
|
273
|
+
|
|
274
|
+
return mock
|
|
275
|
+
? createAzureKeyVaultMock(config)
|
|
276
|
+
: new AzureKeyVault(url, config, credentials);
|
|
277
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { EnvProvider } from '../interfaces';
|
|
2
|
+
import { AppSettingsProvider } from './app-settings.provider';
|
|
3
|
+
import { PackageJsonProvider } from './package-json.provider';
|
|
4
|
+
import { AzureKeyVaultProvider } from './azure-key-vault.provider';
|
|
5
|
+
import { LocalProvider } from './local.provider';
|
|
6
|
+
|
|
7
|
+
const IntegratedProviders: Record<string, EnvProvider<any, any>> = {
|
|
8
|
+
[PackageJsonProvider.key]: PackageJsonProvider,
|
|
9
|
+
[AppSettingsProvider.key]: AppSettingsProvider,
|
|
10
|
+
[AzureKeyVaultProvider.key]: AzureKeyVaultProvider,
|
|
11
|
+
[LocalProvider.key]: LocalProvider
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const IntegratedProviderConfig = [
|
|
15
|
+
{
|
|
16
|
+
path: PackageJsonProvider.key
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
path: AppSettingsProvider.key
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
path: AzureKeyVaultProvider.key
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: LocalProvider.key
|
|
26
|
+
}
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export { IntegratedProviders, IntegratedProviderConfig };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { CommandArguments } from '../arguments';
|
|
3
|
+
import { EnvProvider } from '../interfaces';
|
|
4
|
+
import { readJson, writeJson } from '../utils';
|
|
5
|
+
|
|
6
|
+
const KEY = 'local';
|
|
7
|
+
|
|
8
|
+
interface LocalCommandArguments extends CommandArguments {
|
|
9
|
+
localFile: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Loads local variables from env files in env folder.
|
|
14
|
+
*/
|
|
15
|
+
export const LocalProvider: EnvProvider<LocalCommandArguments> = {
|
|
16
|
+
key: KEY,
|
|
17
|
+
|
|
18
|
+
builder: (builder) => {
|
|
19
|
+
builder.options({
|
|
20
|
+
localFile: {
|
|
21
|
+
group: KEY,
|
|
22
|
+
alias: 'lf',
|
|
23
|
+
type: 'string',
|
|
24
|
+
default: '[[root]]/[[env]].local.env.json',
|
|
25
|
+
describe: 'Local secret variables file path'
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
load: async ({ localFile, ci }) => {
|
|
31
|
+
// ci mode doesn't load local vars
|
|
32
|
+
if (ci) return [];
|
|
33
|
+
|
|
34
|
+
if (!existsSync(localFile)) {
|
|
35
|
+
await writeJson(localFile, {});
|
|
36
|
+
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const [vars] = await readJson(localFile);
|
|
41
|
+
|
|
42
|
+
return [vars];
|
|
43
|
+
}
|
|
44
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CommandArguments } from '../arguments';
|
|
2
|
+
import { EnvProvider } from '../interfaces';
|
|
3
|
+
|
|
4
|
+
const KEY = 'package-json';
|
|
5
|
+
|
|
6
|
+
interface PackageJsonCommandArguments extends CommandArguments {
|
|
7
|
+
varPrefix: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Loads project info from package.json.
|
|
12
|
+
*/
|
|
13
|
+
export const PackageJsonProvider: EnvProvider<PackageJsonCommandArguments> = {
|
|
14
|
+
key: KEY,
|
|
15
|
+
|
|
16
|
+
builder: (builder) => {
|
|
17
|
+
builder.options({
|
|
18
|
+
varPrefix: {
|
|
19
|
+
group: KEY,
|
|
20
|
+
alias: 'vp',
|
|
21
|
+
type: 'string',
|
|
22
|
+
default: '',
|
|
23
|
+
describe: 'Prefix for loaded variables'
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
load: ({ env, app, varPrefix }) => {
|
|
29
|
+
return {
|
|
30
|
+
[`${varPrefix}ENV`]: env,
|
|
31
|
+
|
|
32
|
+
[`${varPrefix}VERSION`]: app?.version,
|
|
33
|
+
[`${varPrefix}PROJECT`]: app?.project,
|
|
34
|
+
[`${varPrefix}NAME`]: app?.name,
|
|
35
|
+
[`${varPrefix}TITLE`]: app?.title,
|
|
36
|
+
[`${varPrefix}DESCRIPTION`]: app?.description
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|