auth0-deploy-cli 8.31.0 → 8.33.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/CHANGELOG.md +46 -1
- package/lib/args.d.ts +4 -0
- package/lib/args.js +18 -0
- package/lib/commands/import.js +40 -3
- package/lib/context/directory/handlers/clients.js +14 -0
- package/lib/context/directory/handlers/connections.js +1 -0
- package/lib/context/directory/handlers/guardianFactors.js +8 -6
- package/lib/context/directory/handlers/tenant.d.ts +1 -6
- package/lib/context/directory/handlers/tenant.js +0 -1
- package/lib/context/index.js +5 -0
- package/lib/context/yaml/handlers/clients.js +12 -0
- package/lib/context/yaml/handlers/connections.js +1 -17
- package/lib/context/yaml/handlers/guardianFactors.js +3 -1
- package/lib/context/yaml/handlers/tenant.js +1 -1
- package/lib/sessionDurationsToMinutes.d.ts +9 -7
- package/lib/sessionDurationsToMinutes.js +11 -10
- package/lib/tools/auth0/handlers/actions.d.ts +1 -0
- package/lib/tools/auth0/handlers/actions.js +68 -29
- package/lib/tools/auth0/handlers/attackProtection.js +15 -0
- package/lib/tools/auth0/handlers/branding.js +7 -0
- package/lib/tools/auth0/handlers/clientGrants.d.ts +5 -0
- package/lib/tools/auth0/handlers/clientGrants.js +31 -9
- package/lib/tools/auth0/handlers/clients.d.ts +62 -2
- package/lib/tools/auth0/handlers/clients.js +187 -22
- package/lib/tools/auth0/handlers/connections.d.ts +18 -0
- package/lib/tools/auth0/handlers/connections.js +86 -5
- package/lib/tools/auth0/handlers/databases.d.ts +91 -0
- package/lib/tools/auth0/handlers/databases.js +162 -2
- package/lib/tools/auth0/handlers/default.d.ts +4 -0
- package/lib/tools/auth0/handlers/default.js +82 -4
- package/lib/tools/auth0/handlers/emailProvider.js +8 -0
- package/lib/tools/auth0/handlers/emailTemplates.js +7 -0
- package/lib/tools/auth0/handlers/flowVaultConnections.js +6 -1
- package/lib/tools/auth0/handlers/flows.js +13 -4
- package/lib/tools/auth0/handlers/forms.js +10 -1
- package/lib/tools/auth0/handlers/guardianFactors.js +7 -1
- package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +8 -1
- package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +8 -1
- package/lib/tools/auth0/handlers/guardianPolicies.js +7 -0
- package/lib/tools/auth0/handlers/hooks.d.ts +1 -0
- package/lib/tools/auth0/handlers/hooks.js +10 -0
- package/lib/tools/auth0/handlers/organizations.d.ts +11 -1
- package/lib/tools/auth0/handlers/organizations.js +48 -52
- package/lib/tools/auth0/handlers/pages.js +7 -0
- package/lib/tools/auth0/handlers/phoneProvider.js +7 -0
- package/lib/tools/auth0/handlers/prompts.js +7 -0
- package/lib/tools/auth0/handlers/resourceServers.d.ts +1 -2
- package/lib/tools/auth0/handlers/resourceServers.js +9 -25
- package/lib/tools/auth0/handlers/roles.js +7 -0
- package/lib/tools/auth0/handlers/rules.d.ts +1 -0
- package/lib/tools/auth0/handlers/rules.js +9 -0
- package/lib/tools/auth0/handlers/rulesConfigs.d.ts +1 -0
- package/lib/tools/auth0/handlers/rulesConfigs.js +3 -0
- package/lib/tools/auth0/handlers/scimHandler.js +8 -1
- package/lib/tools/auth0/handlers/selfServiceProfiles.d.ts +1 -1
- package/lib/tools/auth0/handlers/selfServiceProfiles.js +10 -17
- package/lib/tools/auth0/handlers/tenant.d.ts +18 -1
- package/lib/tools/auth0/handlers/tenant.js +48 -4
- package/lib/tools/auth0/handlers/themes.js +11 -2
- package/lib/tools/auth0/handlers/triggers.js +6 -0
- package/lib/tools/auth0/handlers/userAttributeProfiles.js +16 -10
- package/lib/tools/auth0/index.d.ts +3 -0
- package/lib/tools/auth0/index.js +204 -0
- package/lib/tools/calculateChanges.d.ts +2 -2
- package/lib/tools/calculateChanges.js +21 -6
- package/lib/tools/calculateDryRunChanges.d.ts +71 -0
- package/lib/tools/calculateDryRunChanges.js +492 -0
- package/lib/tools/deploy.js +25 -1
- package/lib/tools/utils.d.ts +5 -0
- package/lib/tools/utils.js +64 -3
- package/lib/types.d.ts +16 -0
- package/lib/utils.d.ts +7 -0
- package/lib/utils.js +33 -1
- package/package.json +7 -4
|
@@ -37,6 +37,11 @@ export declare const schema: {
|
|
|
37
37
|
};
|
|
38
38
|
api_behavior: {
|
|
39
39
|
type: string;
|
|
40
|
+
enum: string[];
|
|
41
|
+
};
|
|
42
|
+
signup_behavior: {
|
|
43
|
+
type: string;
|
|
44
|
+
enum: string[];
|
|
40
45
|
};
|
|
41
46
|
};
|
|
42
47
|
};
|
|
@@ -190,6 +195,90 @@ export declare const schema: {
|
|
|
190
195
|
};
|
|
191
196
|
};
|
|
192
197
|
};
|
|
198
|
+
password_options: {
|
|
199
|
+
type: string;
|
|
200
|
+
properties: {
|
|
201
|
+
complexity: {
|
|
202
|
+
type: string;
|
|
203
|
+
properties: {
|
|
204
|
+
min_length: {
|
|
205
|
+
type: string;
|
|
206
|
+
minimum: number;
|
|
207
|
+
maximum: number;
|
|
208
|
+
};
|
|
209
|
+
character_types: {
|
|
210
|
+
type: string;
|
|
211
|
+
items: {
|
|
212
|
+
type: string;
|
|
213
|
+
enum: string[];
|
|
214
|
+
};
|
|
215
|
+
};
|
|
216
|
+
character_type_rule: {
|
|
217
|
+
type: string;
|
|
218
|
+
enum: string[];
|
|
219
|
+
};
|
|
220
|
+
identical_characters: {
|
|
221
|
+
type: string;
|
|
222
|
+
enum: string[];
|
|
223
|
+
};
|
|
224
|
+
sequential_characters: {
|
|
225
|
+
type: string;
|
|
226
|
+
enum: string[];
|
|
227
|
+
};
|
|
228
|
+
max_length_exceeded: {
|
|
229
|
+
type: string;
|
|
230
|
+
enum: string[];
|
|
231
|
+
};
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
profile_data: {
|
|
235
|
+
type: string;
|
|
236
|
+
properties: {
|
|
237
|
+
active: {
|
|
238
|
+
type: string;
|
|
239
|
+
};
|
|
240
|
+
blocked_fields: {
|
|
241
|
+
type: string;
|
|
242
|
+
items: {
|
|
243
|
+
type: string;
|
|
244
|
+
};
|
|
245
|
+
maxItems: number;
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
history: {
|
|
250
|
+
type: string;
|
|
251
|
+
properties: {
|
|
252
|
+
active: {
|
|
253
|
+
type: string;
|
|
254
|
+
};
|
|
255
|
+
size: {
|
|
256
|
+
type: string;
|
|
257
|
+
minimum: number;
|
|
258
|
+
maximum: number;
|
|
259
|
+
};
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
dictionary: {
|
|
263
|
+
type: string;
|
|
264
|
+
properties: {
|
|
265
|
+
active: {
|
|
266
|
+
type: string;
|
|
267
|
+
};
|
|
268
|
+
default: {
|
|
269
|
+
type: string;
|
|
270
|
+
enum: string[];
|
|
271
|
+
};
|
|
272
|
+
custom: {
|
|
273
|
+
type: string;
|
|
274
|
+
items: {
|
|
275
|
+
type: string;
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
};
|
|
279
|
+
};
|
|
280
|
+
};
|
|
281
|
+
};
|
|
193
282
|
};
|
|
194
283
|
};
|
|
195
284
|
};
|
|
@@ -202,10 +291,12 @@ export default class DatabaseHandler extends DefaultAPIHandler {
|
|
|
202
291
|
objString(db: any): string;
|
|
203
292
|
getFormattedOptions(options: any, actions?: Action[]): any;
|
|
204
293
|
validate(assets: Assets): Promise<void>;
|
|
294
|
+
private validatePasswordOptions;
|
|
205
295
|
private validatePasswordlessSettings;
|
|
206
296
|
private validateEmailUniqueConstraints;
|
|
207
297
|
getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
|
|
208
298
|
getType(): Promise<Connection[]>;
|
|
209
299
|
calcChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
300
|
+
dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
210
301
|
processChanges(assets: Assets): Promise<void>;
|
|
211
302
|
}
|
|
@@ -49,6 +49,7 @@ const constants_1 = __importDefault(require("../../constants"));
|
|
|
49
49
|
const utils_1 = require("../../utils");
|
|
50
50
|
const client_1 = require("../client");
|
|
51
51
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
52
|
+
const calculateDryRunChanges_1 = require("../../calculateDryRunChanges");
|
|
52
53
|
const connections_1 = require("./connections");
|
|
53
54
|
exports.schema = {
|
|
54
55
|
type: 'array',
|
|
@@ -73,7 +74,8 @@ exports.schema = {
|
|
|
73
74
|
type: 'object',
|
|
74
75
|
properties: {
|
|
75
76
|
enabled: { type: 'boolean' },
|
|
76
|
-
api_behavior: { type: 'string' },
|
|
77
|
+
api_behavior: { type: 'string', enum: ['required', 'optional'] },
|
|
78
|
+
signup_behavior: { type: 'string', enum: ['allow', 'block'] },
|
|
77
79
|
},
|
|
78
80
|
},
|
|
79
81
|
email_otp: {
|
|
@@ -179,6 +181,54 @@ exports.schema = {
|
|
|
179
181
|
action_id: { type: 'string' },
|
|
180
182
|
},
|
|
181
183
|
},
|
|
184
|
+
password_options: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
complexity: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
min_length: { type: 'integer', minimum: 1, maximum: 72 },
|
|
191
|
+
character_types: {
|
|
192
|
+
type: 'array',
|
|
193
|
+
items: {
|
|
194
|
+
type: 'string',
|
|
195
|
+
enum: ['uppercase', 'lowercase', 'number', 'special'],
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
character_type_rule: { type: 'string', enum: ['all', 'three_of_four'] },
|
|
199
|
+
identical_characters: { type: 'string', enum: ['allow', 'block'] },
|
|
200
|
+
sequential_characters: { type: 'string', enum: ['allow', 'block'] },
|
|
201
|
+
max_length_exceeded: { type: 'string', enum: ['truncate', 'error'] },
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
profile_data: {
|
|
205
|
+
type: 'object',
|
|
206
|
+
properties: {
|
|
207
|
+
active: { type: 'boolean' },
|
|
208
|
+
blocked_fields: {
|
|
209
|
+
type: 'array',
|
|
210
|
+
items: { type: 'string' },
|
|
211
|
+
maxItems: 12,
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
history: {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
active: { type: 'boolean' },
|
|
219
|
+
size: { type: 'integer', minimum: 1, maximum: 24 },
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
dictionary: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
properties: {
|
|
225
|
+
active: { type: 'boolean' },
|
|
226
|
+
default: { type: 'string', enum: ['en_10k', 'en_100k'] },
|
|
227
|
+
custom: { type: 'array', items: { type: 'string' } },
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
},
|
|
182
232
|
},
|
|
183
233
|
},
|
|
184
234
|
},
|
|
@@ -220,10 +270,45 @@ class DatabaseHandler extends default_1.default {
|
|
|
220
270
|
// Validate each database
|
|
221
271
|
databases.forEach((database) => {
|
|
222
272
|
this.validateEmailUniqueConstraints(database);
|
|
223
|
-
|
|
273
|
+
this.validatePasswordOptions(database);
|
|
274
|
+
// this.validatePasswordlessSettings(database); // Enable only when feature is GA PR:#1282
|
|
224
275
|
});
|
|
225
276
|
await super.validate(assets);
|
|
226
277
|
}
|
|
278
|
+
validatePasswordOptions(payload) {
|
|
279
|
+
const options = payload?.options;
|
|
280
|
+
if (!options?.password_options)
|
|
281
|
+
return;
|
|
282
|
+
const legacyFields = [
|
|
283
|
+
'passwordPolicy',
|
|
284
|
+
'password_complexity_options',
|
|
285
|
+
'password_history',
|
|
286
|
+
'password_no_personal_info',
|
|
287
|
+
'password_dictionary',
|
|
288
|
+
];
|
|
289
|
+
const conflictingField = legacyFields.find((field) => field in options);
|
|
290
|
+
if (conflictingField) {
|
|
291
|
+
throw new Error(`Database "${payload.name}": Cannot use both legacy password policy field "${conflictingField}" and "password_options". Please migrate fully to "password_options".`);
|
|
292
|
+
}
|
|
293
|
+
const complexity = options.password_options?.complexity;
|
|
294
|
+
if (complexity?.character_type_rule === 'three_of_four') {
|
|
295
|
+
const allTypes = ['uppercase', 'lowercase', 'number', 'special'];
|
|
296
|
+
const hasAllTypes = allTypes.every((t) => complexity?.character_types?.includes(t));
|
|
297
|
+
if (!hasAllTypes) {
|
|
298
|
+
throw new Error(`Database "${payload.name}": "character_type_rule" can only be set to "three_of_four" when all four character types (uppercase, lowercase, number, special) are specified in "character_types".`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const blockedFields = options.password_options?.profile_data?.blocked_fields;
|
|
302
|
+
if (blockedFields) {
|
|
303
|
+
if (blockedFields.length > 12) {
|
|
304
|
+
throw new Error(`Database "${payload.name}": "profile_data.blocked_fields" cannot contain more than 12 items.`);
|
|
305
|
+
}
|
|
306
|
+
const tooLong = blockedFields.find((f) => f.length > 100);
|
|
307
|
+
if (tooLong) {
|
|
308
|
+
throw new Error(`Database "${payload.name}": Each item in "profile_data.blocked_fields" must not exceed 100 characters.`);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
227
312
|
validatePasswordlessSettings(payload) {
|
|
228
313
|
const options = payload?.options;
|
|
229
314
|
if (!options)
|
|
@@ -238,6 +323,11 @@ class DatabaseHandler extends default_1.default {
|
|
|
238
323
|
if (passwordEnabled === true && disableSelfServiceChangePassword === true) {
|
|
239
324
|
throw new Error(`Database "${payload.name}": disable_self_service_change_password must be false when password authentication is enabled.`);
|
|
240
325
|
}
|
|
326
|
+
const apiBehavior = options?.authentication_methods?.password?.api_behavior;
|
|
327
|
+
const signupBehavior = options?.authentication_methods?.password?.signup_behavior;
|
|
328
|
+
if (signupBehavior === 'block' && apiBehavior !== 'optional') {
|
|
329
|
+
throw new Error(`Database "${payload.name}": When "signup_behavior" is "block", "api_behavior" must be "optional".`);
|
|
330
|
+
}
|
|
241
331
|
}
|
|
242
332
|
validateEmailUniqueConstraints(payload) {
|
|
243
333
|
const attributes = payload?.options?.attributes;
|
|
@@ -288,6 +378,35 @@ class DatabaseHandler extends default_1.default {
|
|
|
288
378
|
else if (requiresUsername || validation) {
|
|
289
379
|
delete connection.options?.attributes;
|
|
290
380
|
}
|
|
381
|
+
// When switching between flexible and legacy password policy, strip the conflicting
|
|
382
|
+
// group from the existing state before merging to avoid a 400 from the API.
|
|
383
|
+
const payloadHasPasswordOptions = !!payload?.options?.password_options;
|
|
384
|
+
const payloadHasLegacyPasswordFields = payload?.options?.passwordPolicy ||
|
|
385
|
+
payload?.options?.password_complexity_options ||
|
|
386
|
+
payload?.options?.password_history ||
|
|
387
|
+
payload?.options?.password_no_personal_info ||
|
|
388
|
+
payload?.options?.password_dictionary;
|
|
389
|
+
if (payloadHasPasswordOptions) {
|
|
390
|
+
delete connection.options?.passwordPolicy;
|
|
391
|
+
delete connection.options?.password_complexity_options;
|
|
392
|
+
delete connection.options?.password_history;
|
|
393
|
+
delete connection.options?.password_no_personal_info;
|
|
394
|
+
delete connection.options?.password_dictionary;
|
|
395
|
+
}
|
|
396
|
+
else if (payloadHasLegacyPasswordFields) {
|
|
397
|
+
delete connection.options?.password_options;
|
|
398
|
+
}
|
|
399
|
+
// If signup_behavior is being set to "block", api_behavior must be "optional".
|
|
400
|
+
// Check the merged result upfront so the user gets a clear error rather than a
|
|
401
|
+
// cryptic 400 from the API.
|
|
402
|
+
const mergedApiBehavior = payload?.options?.authentication_methods?.password?.api_behavior ??
|
|
403
|
+
connection.options?.authentication_methods?.password?.api_behavior;
|
|
404
|
+
const payloadSignupBehavior = payload?.options?.authentication_methods?.password?.signup_behavior;
|
|
405
|
+
if (payloadSignupBehavior === 'block' && mergedApiBehavior !== 'optional') {
|
|
406
|
+
throw new Error(`Database "${payload.name}": Cannot set "signup_behavior" to "block" without "api_behavior" set to "optional". ` +
|
|
407
|
+
`The existing tenant value for "api_behavior" is "${mergedApiBehavior ?? 'required (default)'}". ` +
|
|
408
|
+
`Please explicitly set "api_behavior" to "optional" in your config.`);
|
|
409
|
+
}
|
|
291
410
|
payload.options = { ...connection.options, ...payload.options };
|
|
292
411
|
if (payload.options && Object.keys(payload.options).length === 0) {
|
|
293
412
|
delete payload.options;
|
|
@@ -388,6 +507,47 @@ class DatabaseHandler extends default_1.default {
|
|
|
388
507
|
});
|
|
389
508
|
return super.calcChanges({ ...assets, databases: formatted });
|
|
390
509
|
}
|
|
510
|
+
async dryRunChanges(assets) {
|
|
511
|
+
const { databases } = assets;
|
|
512
|
+
if (!databases) {
|
|
513
|
+
return {
|
|
514
|
+
del: [],
|
|
515
|
+
create: [],
|
|
516
|
+
update: [],
|
|
517
|
+
conflicts: [],
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
const [clients, existingDatabasesConnections, actions] = await Promise.all([
|
|
521
|
+
(0, client_1.paginate)(this.client.clients.list, {
|
|
522
|
+
paginate: true,
|
|
523
|
+
}),
|
|
524
|
+
(0, client_1.paginate)(this.client.connections.list, {
|
|
525
|
+
strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
|
|
526
|
+
checkpoint: true,
|
|
527
|
+
include_totals: true,
|
|
528
|
+
}),
|
|
529
|
+
(0, client_1.paginate)(this.client.actions.list, {
|
|
530
|
+
paginate: true,
|
|
531
|
+
include_totals: true,
|
|
532
|
+
}),
|
|
533
|
+
]);
|
|
534
|
+
const formatted = databases.map((db) => {
|
|
535
|
+
const { options, ...rest } = db;
|
|
536
|
+
const formattedOptions = this.getFormattedOptions(options, actions);
|
|
537
|
+
const formattedDb = { ...rest, options: formattedOptions };
|
|
538
|
+
if (db.enabled_clients) {
|
|
539
|
+
formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients);
|
|
540
|
+
}
|
|
541
|
+
return formattedDb;
|
|
542
|
+
});
|
|
543
|
+
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
544
|
+
type: this.type,
|
|
545
|
+
assets: formatted,
|
|
546
|
+
existing: existingDatabasesConnections,
|
|
547
|
+
identifiers: this.identifiers,
|
|
548
|
+
ignoreDryRunFields: this.ignoreDryRunFields,
|
|
549
|
+
});
|
|
550
|
+
}
|
|
391
551
|
// Run after clients are updated so we can convert all the enabled_clients names to id's
|
|
392
552
|
async processChanges(assets) {
|
|
393
553
|
const { databases } = assets;
|
|
@@ -23,6 +23,7 @@ export default class APIHandler {
|
|
|
23
23
|
create: ApiMethodOverride;
|
|
24
24
|
delete: ApiMethodOverride;
|
|
25
25
|
};
|
|
26
|
+
ignoreDryRunFields: string[];
|
|
26
27
|
constructor(options: {
|
|
27
28
|
id?: APIHandler['id'];
|
|
28
29
|
config: ConfigFunction;
|
|
@@ -39,17 +40,20 @@ export default class APIHandler {
|
|
|
39
40
|
create?: ApiMethodOverride;
|
|
40
41
|
delete?: ApiMethodOverride;
|
|
41
42
|
};
|
|
43
|
+
ignoreDryRunFields: APIHandler['ignoreDryRunFields'];
|
|
42
44
|
});
|
|
43
45
|
getClientFN(fn: ApiMethodOverride): Function;
|
|
44
46
|
didDelete(item: Asset): void;
|
|
45
47
|
didCreate(item: Asset): void;
|
|
46
48
|
didUpdate(item: Asset): void;
|
|
47
49
|
objString(item: Asset): string;
|
|
50
|
+
getResourceName(item: Asset): string;
|
|
48
51
|
getType(): Promise<Asset | Asset[] | null>;
|
|
49
52
|
load(): Promise<{
|
|
50
53
|
[key: string]: Asset | Asset[] | null;
|
|
51
54
|
}>;
|
|
52
55
|
calcChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
56
|
+
dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
53
57
|
validate(assets: Assets): Promise<void>;
|
|
54
58
|
processChanges(assets: Assets, changes: CalculatedChanges): Promise<void>;
|
|
55
59
|
}
|
|
@@ -9,6 +9,7 @@ const validationError_1 = __importDefault(require("../../validationError"));
|
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
10
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
11
11
|
const calculateChanges_1 = require("../../calculateChanges");
|
|
12
|
+
const calculateDryRunChanges_1 = require("../../calculateDryRunChanges");
|
|
12
13
|
function order(value) {
|
|
13
14
|
return function decorator(t, n, descriptor) {
|
|
14
15
|
const numericValue = Number(value);
|
|
@@ -75,6 +76,7 @@ class APIHandler {
|
|
|
75
76
|
this.stripUpdateFields = [...(options.stripUpdateFields || []), this.id];
|
|
76
77
|
this.sensitiveFieldsToObfuscate = options.sensitiveFieldsToObfuscate || [];
|
|
77
78
|
this.stripCreateFields = options.stripCreateFields || [];
|
|
79
|
+
this.ignoreDryRunFields = [...(options.ignoreDryRunFields || [])].filter((field, index, allFields) => allFields.indexOf(field) === index);
|
|
78
80
|
this.functions = {
|
|
79
81
|
list: 'list',
|
|
80
82
|
create: 'create',
|
|
@@ -115,6 +117,44 @@ class APIHandler {
|
|
|
115
117
|
objString(item) {
|
|
116
118
|
return (0, utils_1.convertJsonToString)(item);
|
|
117
119
|
}
|
|
120
|
+
getResourceName(item) {
|
|
121
|
+
// Get a human-readable identifier for the resource
|
|
122
|
+
if (item.name)
|
|
123
|
+
return item.name;
|
|
124
|
+
if (item.display_name)
|
|
125
|
+
return item.display_name;
|
|
126
|
+
if (item.template)
|
|
127
|
+
return item.template;
|
|
128
|
+
if (item.email)
|
|
129
|
+
return item.email;
|
|
130
|
+
// For some resources, create a descriptive name
|
|
131
|
+
if (this.type === 'clientGrants') {
|
|
132
|
+
const clientLabel = item._clientName || item.client_id;
|
|
133
|
+
return `${clientLabel} -> ${item.audience}`;
|
|
134
|
+
}
|
|
135
|
+
if (this.type === 'guardianFactors') {
|
|
136
|
+
return item.name || item.type || 'unknown factor';
|
|
137
|
+
}
|
|
138
|
+
if (this.type === 'emailTemplates') {
|
|
139
|
+
return item.template || 'unknown template';
|
|
140
|
+
}
|
|
141
|
+
if (this.type === 'networkACLs') {
|
|
142
|
+
return item.description || `priority:${item.priority}`;
|
|
143
|
+
}
|
|
144
|
+
if (this.type === 'customDomains') {
|
|
145
|
+
return item.domain || 'unnamed custom domain';
|
|
146
|
+
}
|
|
147
|
+
if (this.type === 'tenant' ||
|
|
148
|
+
this.type === 'attackProtection' ||
|
|
149
|
+
this.type === 'branding' ||
|
|
150
|
+
this.type === 'emailProvider' ||
|
|
151
|
+
this.type === 'guardianPhoneFactorSelectedProvider' ||
|
|
152
|
+
this.type === 'guardianPolicies' ||
|
|
153
|
+
this.type === 'riskAssessment') {
|
|
154
|
+
return `${this.type} settings`;
|
|
155
|
+
}
|
|
156
|
+
return 'unnamed resource';
|
|
157
|
+
}
|
|
118
158
|
async getType() {
|
|
119
159
|
// Each type to impl how to get the existing as its not consistent across the mgnt api.
|
|
120
160
|
throw new Error(`Must implement getType for type ${this.type}`);
|
|
@@ -145,14 +185,49 @@ class APIHandler {
|
|
|
145
185
|
};
|
|
146
186
|
}
|
|
147
187
|
const existing = await this.getType();
|
|
188
|
+
// if we are in dry run mode, calculate the changes
|
|
189
|
+
// Figure out what needs to be updated vs created
|
|
190
|
+
if (this.config('AUTH0_DRY_RUN') === true || this.config('AUTH0_DRY_RUN') === 'true') {
|
|
191
|
+
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
192
|
+
type: this.type,
|
|
193
|
+
assets: typeAssets,
|
|
194
|
+
// @ts-ignore TODO: investigate what happens when `existing` is null
|
|
195
|
+
existing,
|
|
196
|
+
identifiers: this.identifiers,
|
|
197
|
+
ignoreDryRunFields: this.ignoreDryRunFields,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// if we are not in dry run mode, calculate the changes
|
|
148
201
|
// Figure out what needs to be updated vs created
|
|
149
202
|
return (0, calculateChanges_1.calculateChanges)({
|
|
150
203
|
handler: this,
|
|
151
204
|
assets: typeAssets,
|
|
152
205
|
allowDelete: !!this.config('AUTH0_ALLOW_DELETE'),
|
|
153
|
-
|
|
206
|
+
// @ts-ignore TODO: investigate what happens when `existing` is null
|
|
207
|
+
existing,
|
|
208
|
+
identifiers: this.identifiers,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
async dryRunChanges(assets) {
|
|
212
|
+
const typeAssets = assets[this.type];
|
|
213
|
+
// Do nothing if not set
|
|
214
|
+
if (!typeAssets) {
|
|
215
|
+
return {
|
|
216
|
+
del: [],
|
|
217
|
+
create: [],
|
|
218
|
+
conflicts: [],
|
|
219
|
+
update: [],
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const existing = await this.getType();
|
|
223
|
+
// Figure out what needs to be created, updated or deleted
|
|
224
|
+
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
225
|
+
type: this.type,
|
|
226
|
+
assets: typeAssets,
|
|
227
|
+
// @ts-ignore TODO: investigate what happens when `existing` is null
|
|
154
228
|
existing,
|
|
155
229
|
identifiers: this.identifiers,
|
|
230
|
+
ignoreDryRunFields: this.ignoreDryRunFields,
|
|
156
231
|
});
|
|
157
232
|
}
|
|
158
233
|
async validate(assets) {
|
|
@@ -234,7 +309,8 @@ class APIHandler {
|
|
|
234
309
|
const updateFN = this.getClientFN(this.functions.update);
|
|
235
310
|
const updatePayload = (() => {
|
|
236
311
|
const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
|
|
237
|
-
|
|
312
|
+
const stripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
|
|
313
|
+
return (0, utils_1.validateNoUnresolvedPlaceholders)(stripped, this.type, this.objString(updateItem));
|
|
238
314
|
})();
|
|
239
315
|
return updateFN(updateItem[this.id], updatePayload);
|
|
240
316
|
}, retryConfig)
|
|
@@ -252,7 +328,8 @@ class APIHandler {
|
|
|
252
328
|
const createFunction = this.getClientFN(this.functions.create);
|
|
253
329
|
const createPayload = (() => {
|
|
254
330
|
const strippedPayload = (0, utils_1.stripFields)(createItem, this.stripCreateFields);
|
|
255
|
-
|
|
331
|
+
const stripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(strippedPayload, this.sensitiveFieldsToObfuscate);
|
|
332
|
+
return (0, utils_1.validateNoUnresolvedPlaceholders)(stripped, this.type, this.objString(createItem));
|
|
256
333
|
})();
|
|
257
334
|
return createFunction(createPayload);
|
|
258
335
|
}, retryConfig)
|
|
@@ -273,7 +350,8 @@ class APIHandler {
|
|
|
273
350
|
const updateFN = this.getClientFN(this.functions.update);
|
|
274
351
|
const updatePayload = (() => {
|
|
275
352
|
const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
|
|
276
|
-
|
|
353
|
+
const stripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
|
|
354
|
+
return (0, utils_1.validateNoUnresolvedPlaceholders)(stripped, this.type, this.objString(updateItem));
|
|
277
355
|
})();
|
|
278
356
|
return updateFN(updateItem[this.id], updatePayload);
|
|
279
357
|
}, retryConfig)
|
|
@@ -41,6 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
42
|
exports.schema = void 0;
|
|
43
43
|
const lodash_1 = require("lodash");
|
|
44
|
+
const utils_1 = require("../../utils");
|
|
44
45
|
const default_1 = __importStar(require("./default"));
|
|
45
46
|
exports.schema = { type: 'object' };
|
|
46
47
|
// The Management API requires the fields to be specified
|
|
@@ -50,6 +51,7 @@ class EmailProviderHandler extends default_1.default {
|
|
|
50
51
|
super({
|
|
51
52
|
...options,
|
|
52
53
|
type: 'emailProvider',
|
|
54
|
+
ignoreDryRunFields: ['smtp.credentials.smtp_pass', 'mandrill.credentials.api_key'],
|
|
53
55
|
});
|
|
54
56
|
}
|
|
55
57
|
async getType() {
|
|
@@ -73,6 +75,12 @@ class EmailProviderHandler extends default_1.default {
|
|
|
73
75
|
const { emailProvider } = assets;
|
|
74
76
|
if (!emailProvider)
|
|
75
77
|
return;
|
|
78
|
+
if ((0, utils_1.isDryRun)(this.config)) {
|
|
79
|
+
const { del, update, create } = await this.calcChanges(assets);
|
|
80
|
+
if (create.length === 0 && update.length === 0 && del.length === 0) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
76
84
|
const existing = await this.getType();
|
|
77
85
|
// HTTP DELETE on emails/provider is not supported, as this is not part of our vNext SDK.
|
|
78
86
|
if (Object.keys(emailProvider).length === 0) {
|
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.schema = exports.supportedTemplates = void 0;
|
|
46
46
|
const default_1 = __importStar(require("./default"));
|
|
47
47
|
const constants_1 = __importDefault(require("../../constants"));
|
|
48
|
+
const utils_1 = require("../../utils");
|
|
48
49
|
exports.supportedTemplates = constants_1.default.EMAIL_TEMPLATES_NAMES.filter((p) => p.includes('.json')).map((p) => p.replace('.json', ''));
|
|
49
50
|
exports.schema = {
|
|
50
51
|
type: 'array',
|
|
@@ -122,6 +123,12 @@ class EmailTemplateHandler extends default_1.default {
|
|
|
122
123
|
// Do nothing if not set
|
|
123
124
|
if (!emailTemplates || !emailTemplates.length)
|
|
124
125
|
return;
|
|
126
|
+
if ((0, utils_1.isDryRun)(this.config)) {
|
|
127
|
+
const { update, create } = await this.calcChanges(assets);
|
|
128
|
+
if (create.length === 0 && update.length === 0) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
125
132
|
await Promise.all(emailTemplates.map(async (emailTemplate) => {
|
|
126
133
|
await this.updateOrCreate(emailTemplate);
|
|
127
134
|
}));
|
|
@@ -47,6 +47,7 @@ const lodash_1 = require("lodash");
|
|
|
47
47
|
const default_1 = __importStar(require("./default"));
|
|
48
48
|
const constants_1 = __importDefault(require("../../constants"));
|
|
49
49
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
50
|
+
const utils_1 = require("../../utils");
|
|
50
51
|
exports.schema = {
|
|
51
52
|
type: 'array',
|
|
52
53
|
items: {
|
|
@@ -102,7 +103,11 @@ class FlowVaultHandler extends default_1.default {
|
|
|
102
103
|
if (!flowVaultConnections)
|
|
103
104
|
return;
|
|
104
105
|
const { del, update, create } = await this.calcChanges(assets);
|
|
105
|
-
|
|
106
|
+
if ((0, utils_1.isDryRun)(this.config)) {
|
|
107
|
+
if (create.length === 0 && update.length === 0 && del.length === 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
106
111
|
if (del.length > 0) {
|
|
107
112
|
await this.deleteVaultConnections(del);
|
|
108
113
|
}
|
|
@@ -48,7 +48,8 @@ const dot_prop_1 = __importDefault(require("dot-prop"));
|
|
|
48
48
|
const default_1 = __importStar(require("./default"));
|
|
49
49
|
const client_1 = require("../client");
|
|
50
50
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
51
|
-
const utils_1 = require("
|
|
51
|
+
const utils_1 = require("../../utils");
|
|
52
|
+
const utils_2 = require("../../../utils");
|
|
52
53
|
const flowVaultConnections_1 = require("./flowVaultConnections");
|
|
53
54
|
exports.schema = {
|
|
54
55
|
type: 'array',
|
|
@@ -113,6 +114,15 @@ class FlowHandler extends default_1.default {
|
|
|
113
114
|
// Do nothing if not set
|
|
114
115
|
if (!flows)
|
|
115
116
|
return;
|
|
117
|
+
const { del, update, create, conflicts } = await this.calcChanges(assets);
|
|
118
|
+
if ((0, utils_1.isDryRun)(this.config)) {
|
|
119
|
+
if (create.length === 0 &&
|
|
120
|
+
update.length === 0 &&
|
|
121
|
+
del.length === 0 &&
|
|
122
|
+
conflicts.length === 0) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
116
126
|
const allFlowConnections = await (0, flowVaultConnections_1.getAllFlowConnections)(this.client);
|
|
117
127
|
// create a map for name to id from allFlowConnections
|
|
118
128
|
const connectionNameMap = {};
|
|
@@ -120,7 +130,6 @@ class FlowHandler extends default_1.default {
|
|
|
120
130
|
connectionNameMap[c.name] = c.id;
|
|
121
131
|
});
|
|
122
132
|
assets.flows = await this.pargeFlowConnectionName(flows, connectionNameMap);
|
|
123
|
-
const { del, update, create, conflicts } = await this.calcChanges(assets);
|
|
124
133
|
const changes = {
|
|
125
134
|
del: del,
|
|
126
135
|
update: update,
|
|
@@ -134,7 +143,7 @@ class FlowHandler extends default_1.default {
|
|
|
134
143
|
async formateFlowConnectionId(flows, connectionIdMap) {
|
|
135
144
|
// replace connection_id with flow connection names
|
|
136
145
|
await Promise.all(flows.map(async (flow) => {
|
|
137
|
-
const flowConnetions = (0,
|
|
146
|
+
const flowConnetions = (0, utils_2.findKeyPathWithValue)(flow, 'connection_id');
|
|
138
147
|
await Promise.all(flowConnetions.map(async (f) => {
|
|
139
148
|
const connectionId = (dot_prop_1.default.get(flow, f.path) || '');
|
|
140
149
|
const flowConnectionName = connectionIdMap[connectionId];
|
|
@@ -152,7 +161,7 @@ class FlowHandler extends default_1.default {
|
|
|
152
161
|
async pargeFlowConnectionName(flows, connectionNameMap) {
|
|
153
162
|
// replace connection_id with flow connection names
|
|
154
163
|
const parsedFlows = await Promise.all(flows.map(async (flow) => {
|
|
155
|
-
const flowConnetions = (0,
|
|
164
|
+
const flowConnetions = (0, utils_2.findKeyPathWithValue)(flow, 'connection_id');
|
|
156
165
|
await Promise.all(flowConnetions.map(async (f) => {
|
|
157
166
|
const connectionName = (dot_prop_1.default.get(flow, f.path) || '');
|
|
158
167
|
const flowConnectionId = connectionNameMap[connectionName];
|
|
@@ -49,6 +49,7 @@ const default_1 = __importStar(require("./default"));
|
|
|
49
49
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
50
50
|
const client_1 = require("../client");
|
|
51
51
|
const utils_1 = require("../../../utils");
|
|
52
|
+
const utils_2 = require("../../utils");
|
|
52
53
|
exports.schema = {
|
|
53
54
|
type: 'array',
|
|
54
55
|
items: {
|
|
@@ -150,6 +151,15 @@ class FormsHandler extends default_1.default {
|
|
|
150
151
|
// Do nothing if not set
|
|
151
152
|
if (!forms)
|
|
152
153
|
return;
|
|
154
|
+
const { del, update, create, conflicts } = await this.calcChanges(assets);
|
|
155
|
+
if ((0, utils_2.isDryRun)(this.config)) {
|
|
156
|
+
if (create.length === 0 &&
|
|
157
|
+
update.length === 0 &&
|
|
158
|
+
del.length === 0 &&
|
|
159
|
+
conflicts.length === 0) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
153
163
|
const flows = await (0, client_1.paginate)(this.client.flows.list, {
|
|
154
164
|
paginate: true,
|
|
155
165
|
include_totals: true,
|
|
@@ -160,7 +170,6 @@ class FormsHandler extends default_1.default {
|
|
|
160
170
|
flowNamMap[f.name] = f.id;
|
|
161
171
|
});
|
|
162
172
|
assets.forms = await this.pargeFormFlowName(forms, flowNamMap);
|
|
163
|
-
const { del, update, create, conflicts } = await this.calcChanges(assets);
|
|
164
173
|
const changes = {
|
|
165
174
|
del: del,
|
|
166
175
|
update: update,
|