auth0-deploy-cli 9.0.0-beta.2 → 9.0.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/AGENTS.md +2 -357
- package/CHANGELOG.md +158 -10
- package/CLAUDE.md +138 -2
- package/README.md +1 -1
- package/lib/context/defaults.d.ts +7 -0
- package/lib/context/defaults.js +74 -30
- package/lib/context/directory/handlers/actionModules.js +1 -4
- package/lib/context/directory/handlers/actions.js +1 -4
- package/lib/context/directory/handlers/attackProtection.js +1 -1
- package/lib/context/directory/handlers/branding.js +4 -1
- package/lib/context/directory/handlers/clientAuthCredentials.d.ts +5 -0
- package/lib/context/directory/handlers/clientAuthCredentials.js +13 -0
- package/lib/context/directory/handlers/clientGrants.js +78 -24
- package/lib/context/directory/handlers/clients.js +20 -3
- package/lib/context/directory/handlers/connections.js +19 -5
- package/lib/context/directory/handlers/databases.js +1 -4
- package/lib/context/directory/handlers/emailTemplates.js +5 -0
- package/lib/context/directory/handlers/guardianEmailFactorSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianEmailFactorSettings.js +38 -0
- package/lib/context/directory/handlers/guardianPhoneFactorSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianPhoneFactorSettings.js +38 -0
- package/lib/context/directory/handlers/guardianSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianSettings.js +38 -0
- package/lib/context/directory/handlers/hooks.js +1 -4
- package/lib/context/directory/handlers/index.js +12 -0
- package/lib/context/directory/handlers/networkACLKeys.d.ts +6 -0
- package/lib/context/directory/handlers/networkACLKeys.js +54 -0
- package/lib/context/directory/handlers/prompts.js +7 -3
- package/lib/context/directory/handlers/rateLimitPolicies.d.ts +6 -0
- package/lib/context/directory/handlers/rateLimitPolicies.js +53 -0
- package/lib/context/directory/handlers/rules.js +1 -4
- package/lib/context/directory/index.js +1 -4
- package/lib/context/index.js +31 -31
- package/lib/context/yaml/handlers/attackProtection.js +1 -1
- package/lib/context/yaml/handlers/branding.js +4 -1
- package/lib/context/yaml/handlers/clientAuthCredentials.d.ts +5 -0
- package/lib/context/yaml/handlers/clientAuthCredentials.js +13 -0
- package/lib/context/yaml/handlers/clients.js +19 -1
- package/lib/context/yaml/handlers/connections.js +8 -1
- package/lib/context/yaml/handlers/flows.js +3 -0
- package/lib/context/yaml/handlers/forms.js +3 -0
- package/lib/context/yaml/handlers/guardianEmailFactorSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianEmailFactorSettings.js +15 -0
- package/lib/context/yaml/handlers/guardianPhoneFactorSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianPhoneFactorSettings.js +15 -0
- package/lib/context/yaml/handlers/guardianSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianSettings.js +15 -0
- package/lib/context/yaml/handlers/index.js +12 -0
- package/lib/context/yaml/handlers/networkACLKeys.d.ts +6 -0
- package/lib/context/yaml/handlers/networkACLKeys.js +42 -0
- package/lib/context/yaml/handlers/prompts.js +3 -1
- package/lib/context/yaml/handlers/rateLimitPolicies.d.ts +6 -0
- package/lib/context/yaml/handlers/rateLimitPolicies.js +27 -0
- package/lib/context/yaml/index.js +1 -4
- package/lib/keywordPreservation.d.ts +1 -1
- package/lib/keywordPreservation.js +2 -1
- package/lib/readonly.js +5 -0
- package/lib/tools/auth0/handlers/attackProtection.js +19 -6
- package/lib/tools/auth0/handlers/clientAuthCredentials.d.ts +27 -0
- package/lib/tools/auth0/handlers/clientAuthCredentials.js +234 -0
- package/lib/tools/auth0/handlers/clientAuthCredentialsPre.d.ts +38 -0
- package/lib/tools/auth0/handlers/clientAuthCredentialsPre.js +123 -0
- package/lib/tools/auth0/handlers/clientGrants.d.ts +1 -1
- package/lib/tools/auth0/handlers/clients.d.ts +106 -0
- package/lib/tools/auth0/handlers/clients.js +206 -2
- package/lib/tools/auth0/handlers/connectionProfiles.d.ts +27 -0
- package/lib/tools/auth0/handlers/connectionProfiles.js +30 -0
- package/lib/tools/auth0/handlers/connections.d.ts +32 -6
- package/lib/tools/auth0/handlers/connections.js +49 -7
- package/lib/tools/auth0/handlers/databases.d.ts +28 -0
- package/lib/tools/auth0/handlers/databases.js +58 -24
- package/lib/tools/auth0/handlers/default.d.ts +23 -0
- package/lib/tools/auth0/handlers/default.js +47 -29
- package/lib/tools/auth0/handlers/eventStreams.js +10 -2
- package/lib/tools/auth0/handlers/guardianEmailFactorSettings.d.ts +22 -0
- package/lib/tools/auth0/handlers/guardianEmailFactorSettings.js +77 -0
- package/lib/tools/auth0/handlers/guardianFactorTemplates.js +13 -4
- package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +11 -9
- package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +11 -9
- package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.d.ts +22 -0
- package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.js +77 -0
- package/lib/tools/auth0/handlers/guardianPolicies.js +11 -1
- package/lib/tools/auth0/handlers/guardianSettings.d.ts +30 -0
- package/lib/tools/auth0/handlers/guardianSettings.js +85 -0
- package/lib/tools/auth0/handlers/hooks.js +1 -1
- package/lib/tools/auth0/handlers/index.js +16 -0
- package/lib/tools/auth0/handlers/networkACLKeys.d.ts +45 -0
- package/lib/tools/auth0/handlers/networkACLKeys.js +177 -0
- package/lib/tools/auth0/handlers/networkACLs.d.ts +132 -2
- package/lib/tools/auth0/handlers/networkACLs.js +100 -16
- package/lib/tools/auth0/handlers/organizations.d.ts +33 -1
- package/lib/tools/auth0/handlers/organizations.js +177 -19
- package/lib/tools/auth0/handlers/phoneProvider.js +10 -2
- package/lib/tools/auth0/handlers/phoneTemplates.d.ts +4 -1
- package/lib/tools/auth0/handlers/phoneTemplates.js +67 -10
- package/lib/tools/auth0/handlers/prompts.js +1 -1
- package/lib/tools/auth0/handlers/rateLimitPolicies.d.ts +81 -0
- package/lib/tools/auth0/handlers/rateLimitPolicies.js +203 -0
- package/lib/tools/auth0/handlers/resourceServers.d.ts +44 -0
- package/lib/tools/auth0/handlers/resourceServers.js +44 -0
- package/lib/tools/auth0/handlers/riskAssessment.d.ts +1 -1
- package/lib/tools/auth0/handlers/riskAssessment.js +19 -1
- package/lib/tools/auth0/handlers/roles.d.ts +4 -0
- package/lib/tools/auth0/handlers/roles.js +10 -0
- package/lib/tools/auth0/handlers/rules.js +19 -7
- package/lib/tools/auth0/handlers/tenant.d.ts +45 -0
- package/lib/tools/auth0/handlers/tenant.js +48 -0
- package/lib/tools/auth0/handlers/themes.d.ts +37 -1
- package/lib/tools/auth0/handlers/themes.js +64 -0
- package/lib/tools/auth0/handlers/tokenExchangeProfiles.js +3 -1
- package/lib/tools/auth0/index.js +12 -6
- package/lib/tools/calculateDryRunChanges.js +12 -8
- package/lib/tools/constants.d.ts +2 -0
- package/lib/tools/constants.js +3 -0
- package/lib/tools/utils.d.ts +3 -0
- package/lib/tools/utils.js +41 -2
- package/lib/types.d.ts +9 -1
- package/lib/utils.d.ts +6 -0
- package/lib/utils.js +17 -2
- package/package.json +2 -2
- package/references/code-style.md +133 -0
- package/references/commands.md +98 -0
- package/references/docs-update.md +34 -0
- package/references/git-workflow.md +135 -0
- package/references/pitfalls.md +62 -0
- package/references/testing.md +118 -0
|
@@ -103,6 +103,27 @@ export declare const schema: {
|
|
|
103
103
|
required: string[];
|
|
104
104
|
additionalProperties: boolean;
|
|
105
105
|
};
|
|
106
|
+
cross_app_access_requesting_app: {
|
|
107
|
+
type: string;
|
|
108
|
+
properties: {
|
|
109
|
+
active: {
|
|
110
|
+
type: string;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
required: string[];
|
|
114
|
+
additionalProperties: boolean;
|
|
115
|
+
};
|
|
116
|
+
cross_app_access_resource_app: {
|
|
117
|
+
type: string;
|
|
118
|
+
properties: {
|
|
119
|
+
status: {
|
|
120
|
+
type: string;
|
|
121
|
+
enum: string[];
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
required: string[];
|
|
125
|
+
additionalProperties: boolean;
|
|
126
|
+
};
|
|
106
127
|
directory_provisioning_configuration: {
|
|
107
128
|
type: string;
|
|
108
129
|
properties: {
|
|
@@ -138,6 +159,15 @@ export declare const schema: {
|
|
|
138
159
|
id: {
|
|
139
160
|
type: string;
|
|
140
161
|
};
|
|
162
|
+
name: {
|
|
163
|
+
type: string;
|
|
164
|
+
};
|
|
165
|
+
email: {
|
|
166
|
+
type: string;
|
|
167
|
+
};
|
|
168
|
+
direct_members_count: {
|
|
169
|
+
type: string;
|
|
170
|
+
};
|
|
141
171
|
};
|
|
142
172
|
required: string[];
|
|
143
173
|
};
|
|
@@ -152,9 +182,7 @@ type DirectoryProvisioningConfig = Management.DirectoryProvisioning;
|
|
|
152
182
|
export type Connection = Management.ConnectionForList & {
|
|
153
183
|
enabled_clients?: string[];
|
|
154
184
|
directory_provisioning_configuration?: Pick<DirectoryProvisioningConfig, 'mapping' | 'synchronize_automatically' | 'synchronize_groups'> & {
|
|
155
|
-
synchronized_groups?:
|
|
156
|
-
id: string;
|
|
157
|
-
}>;
|
|
185
|
+
synchronized_groups?: Management.SynchronizedGroupPayload[];
|
|
158
186
|
};
|
|
159
187
|
};
|
|
160
188
|
export declare const addExcludedConnectionPropertiesToChanges: ({ proposedChanges, existingConnections, config, }: {
|
|
@@ -230,9 +258,7 @@ export default class ConnectionsHandler extends DefaultAPIHandler {
|
|
|
230
258
|
/**
|
|
231
259
|
* Retrieves all synchronized groups for a connection using checkpoint pagination.
|
|
232
260
|
*/
|
|
233
|
-
getConnectionSynchronizedGroups(connectionId: string): Promise<
|
|
234
|
-
id: string;
|
|
235
|
-
}> | null>;
|
|
261
|
+
getConnectionSynchronizedGroups(connectionId: string): Promise<Management.SynchronizedGroupPayload[] | null>;
|
|
236
262
|
/**
|
|
237
263
|
* Replaces the synchronized groups for a connection (PUT replace-all semantics).
|
|
238
264
|
*/
|
|
@@ -129,6 +129,22 @@ exports.schema = {
|
|
|
129
129
|
required: ['active'],
|
|
130
130
|
additionalProperties: false,
|
|
131
131
|
},
|
|
132
|
+
cross_app_access_requesting_app: {
|
|
133
|
+
type: 'object',
|
|
134
|
+
properties: {
|
|
135
|
+
active: { type: 'boolean' },
|
|
136
|
+
},
|
|
137
|
+
required: ['active'],
|
|
138
|
+
additionalProperties: false,
|
|
139
|
+
},
|
|
140
|
+
cross_app_access_resource_app: {
|
|
141
|
+
type: 'object',
|
|
142
|
+
properties: {
|
|
143
|
+
status: { type: 'string', enum: ['enabled', 'disabled'] },
|
|
144
|
+
},
|
|
145
|
+
required: ['status'],
|
|
146
|
+
additionalProperties: false,
|
|
147
|
+
},
|
|
132
148
|
directory_provisioning_configuration: {
|
|
133
149
|
type: 'object',
|
|
134
150
|
properties: {
|
|
@@ -156,6 +172,9 @@ exports.schema = {
|
|
|
156
172
|
type: 'object',
|
|
157
173
|
properties: {
|
|
158
174
|
id: { type: 'string' },
|
|
175
|
+
name: { type: 'string' },
|
|
176
|
+
email: { type: 'string' },
|
|
177
|
+
direct_members_count: { type: 'number' },
|
|
159
178
|
},
|
|
160
179
|
required: ['id'],
|
|
161
180
|
},
|
|
@@ -361,12 +380,15 @@ class ConnectionsHandler extends default_1.default {
|
|
|
361
380
|
}
|
|
362
381
|
getFormattedOptions(connection, clients) {
|
|
363
382
|
try {
|
|
383
|
+
const { idpinitiated } = connection.options;
|
|
364
384
|
return {
|
|
365
385
|
options: {
|
|
366
386
|
...connection.options,
|
|
367
387
|
idpinitiated: {
|
|
368
|
-
...
|
|
369
|
-
|
|
388
|
+
...idpinitiated,
|
|
389
|
+
...(idpinitiated.client_id && {
|
|
390
|
+
client_id: (0, utils_1.convertClientNameToId)(idpinitiated.client_id, clients),
|
|
391
|
+
}),
|
|
370
392
|
},
|
|
371
393
|
},
|
|
372
394
|
};
|
|
@@ -467,12 +489,28 @@ class ConnectionsHandler extends default_1.default {
|
|
|
467
489
|
try {
|
|
468
490
|
const groups = [];
|
|
469
491
|
let page = await this.client.connections.directoryProvisioning.listSynchronizedGroups(connectionId, {});
|
|
470
|
-
for (const g of page.data ?? [])
|
|
471
|
-
groups.push({
|
|
492
|
+
for (const g of page.data ?? []) {
|
|
493
|
+
groups.push({
|
|
494
|
+
id: g.id,
|
|
495
|
+
...(g.name !== undefined && { name: g.name }),
|
|
496
|
+
...(g.email !== undefined && { email: g.email }),
|
|
497
|
+
...(g.direct_members_count !== undefined && {
|
|
498
|
+
direct_members_count: g.direct_members_count,
|
|
499
|
+
}),
|
|
500
|
+
});
|
|
501
|
+
}
|
|
472
502
|
while (page.hasNextPage?.()) {
|
|
473
503
|
page = await page.getNextPage();
|
|
474
|
-
for (const g of page.data ?? [])
|
|
475
|
-
groups.push({
|
|
504
|
+
for (const g of page.data ?? []) {
|
|
505
|
+
groups.push({
|
|
506
|
+
id: g.id,
|
|
507
|
+
...(g.name !== undefined && { name: g.name }),
|
|
508
|
+
...(g.email !== undefined && { email: g.email }),
|
|
509
|
+
...(g.direct_members_count !== undefined && {
|
|
510
|
+
direct_members_count: g.direct_members_count,
|
|
511
|
+
}),
|
|
512
|
+
});
|
|
513
|
+
}
|
|
476
514
|
}
|
|
477
515
|
return groups;
|
|
478
516
|
}
|
|
@@ -709,7 +747,11 @@ class ConnectionsHandler extends default_1.default {
|
|
|
709
747
|
...(enabledClients !== undefined && { enabled_clients: enabledClients }),
|
|
710
748
|
};
|
|
711
749
|
});
|
|
712
|
-
|
|
750
|
+
let proposedChanges = await super.dryRunChanges({ ...assets, connections: formatted });
|
|
751
|
+
const includedConnections = (assets.include && assets.include.connections) || [];
|
|
752
|
+
const excludedConnections = (assets.exclude && assets.exclude.connections) || [];
|
|
753
|
+
proposedChanges = (0, utils_1.filterExcluded)(proposedChanges, excludedConnections);
|
|
754
|
+
proposedChanges = (0, utils_1.filterIncluded)(proposedChanges, includedConnections);
|
|
713
755
|
return (0, exports.addExcludedConnectionPropertiesToChanges)({
|
|
714
756
|
proposedChanges,
|
|
715
757
|
existingConnections,
|
|
@@ -195,6 +195,33 @@ export declare const schema: {
|
|
|
195
195
|
};
|
|
196
196
|
};
|
|
197
197
|
};
|
|
198
|
+
otp_settings: {
|
|
199
|
+
type: string;
|
|
200
|
+
properties: {
|
|
201
|
+
email: {
|
|
202
|
+
type: string;
|
|
203
|
+
properties: {
|
|
204
|
+
otp_length: {
|
|
205
|
+
type: string;
|
|
206
|
+
};
|
|
207
|
+
otp_expiry: {
|
|
208
|
+
type: string;
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
phone: {
|
|
213
|
+
type: string;
|
|
214
|
+
properties: {
|
|
215
|
+
otp_length: {
|
|
216
|
+
type: string;
|
|
217
|
+
};
|
|
218
|
+
otp_expiry: {
|
|
219
|
+
type: string;
|
|
220
|
+
};
|
|
221
|
+
};
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
};
|
|
198
225
|
password_options: {
|
|
199
226
|
type: string;
|
|
200
227
|
properties: {
|
|
@@ -295,6 +322,7 @@ export default class DatabaseHandler extends DefaultAPIHandler {
|
|
|
295
322
|
private validatePasswordlessSettings;
|
|
296
323
|
private validateEmailUniqueConstraints;
|
|
297
324
|
getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
|
|
325
|
+
private enrichConnectionsWithEnabledClients;
|
|
298
326
|
getType(): Promise<Connection[]>;
|
|
299
327
|
calcChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
300
328
|
dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
|
|
@@ -181,6 +181,25 @@ exports.schema = {
|
|
|
181
181
|
action_id: { type: 'string' },
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
|
+
otp_settings: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
email: {
|
|
188
|
+
type: 'object',
|
|
189
|
+
properties: {
|
|
190
|
+
otp_length: { type: 'integer' },
|
|
191
|
+
otp_expiry: { type: 'integer' },
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
phone: {
|
|
195
|
+
type: 'object',
|
|
196
|
+
properties: {
|
|
197
|
+
otp_length: { type: 'integer' },
|
|
198
|
+
otp_expiry: { type: 'integer' },
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
184
203
|
password_options: {
|
|
185
204
|
type: 'object',
|
|
186
205
|
properties: {
|
|
@@ -419,6 +438,22 @@ class DatabaseHandler extends default_1.default {
|
|
|
419
438
|
}
|
|
420
439
|
return this.client.connections[fn].bind(this.client.connections);
|
|
421
440
|
}
|
|
441
|
+
// `enabled_clients` is no longer returned by connections.list; it must be fetched from the
|
|
442
|
+
// dedicated enabled-clients endpoint. Enriching the remote connections keeps the diff and the
|
|
443
|
+
// excluded-client preservation in `getEnabledClients` correct. Without it the dry-run diff
|
|
444
|
+
// reports a false "found in localObj but not in remoteObj" and a real import can silently
|
|
445
|
+
// disable an excluded-but-enabled client.
|
|
446
|
+
async enrichConnectionsWithEnabledClients(connections) {
|
|
447
|
+
return Promise.all(connections.map(async (con) => {
|
|
448
|
+
if (!con?.id)
|
|
449
|
+
return con;
|
|
450
|
+
const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
|
|
451
|
+
if (enabledClients?.length) {
|
|
452
|
+
return { ...con, enabled_clients: enabledClients };
|
|
453
|
+
}
|
|
454
|
+
return con;
|
|
455
|
+
}));
|
|
456
|
+
}
|
|
422
457
|
async getType() {
|
|
423
458
|
if (this.existing)
|
|
424
459
|
return this.existing;
|
|
@@ -433,16 +468,7 @@ class DatabaseHandler extends default_1.default {
|
|
|
433
468
|
include_totals: true,
|
|
434
469
|
}),
|
|
435
470
|
]);
|
|
436
|
-
const dbConnectionsWithEnabledClients = await
|
|
437
|
-
if (!con?.id)
|
|
438
|
-
return con;
|
|
439
|
-
const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
|
|
440
|
-
const connection = { ...con };
|
|
441
|
-
if (enabledClients && enabledClients?.length) {
|
|
442
|
-
connection.enabled_clients = enabledClients;
|
|
443
|
-
}
|
|
444
|
-
return connection;
|
|
445
|
-
}));
|
|
471
|
+
const dbConnectionsWithEnabledClients = await this.enrichConnectionsWithEnabledClients(connections);
|
|
446
472
|
// Convert action ID back to action name for export
|
|
447
473
|
const dbConnectionsWithActionNames = dbConnectionsWithEnabledClients.map((connection) => {
|
|
448
474
|
if (connection.options && 'custom_password_hash' in connection.options) {
|
|
@@ -462,12 +488,21 @@ class DatabaseHandler extends default_1.default {
|
|
|
462
488
|
}
|
|
463
489
|
return connection;
|
|
464
490
|
});
|
|
491
|
+
// A connection can return both legacy password fields and `password_options` on read, but
|
|
492
|
+
// they're mutually exclusive on write. Strip the legacy fields to keep the export deployable.
|
|
493
|
+
const dbConnectionsNormalized = dbConnectionsWithActionNames.map((connection) => {
|
|
494
|
+
if (connection.options && 'password_options' in connection.options) {
|
|
495
|
+
const { passwordPolicy, password_complexity_options, password_history, password_no_personal_info, password_dictionary, ...options } = connection.options;
|
|
496
|
+
return { ...connection, options };
|
|
497
|
+
}
|
|
498
|
+
return connection;
|
|
499
|
+
});
|
|
465
500
|
// If options option is empty for all connection, log the missing options scope.
|
|
466
|
-
const isOptionExists =
|
|
501
|
+
const isOptionExists = dbConnectionsNormalized.every((c) => c.options && Object.keys(c.options).length > 0);
|
|
467
502
|
if (!isOptionExists) {
|
|
468
503
|
logger_1.default.warn(`Insufficient scope the read:connections_options scope is required to get ${this.type} options.`);
|
|
469
504
|
}
|
|
470
|
-
this.existing =
|
|
505
|
+
this.existing = dbConnectionsNormalized;
|
|
471
506
|
return this.existing;
|
|
472
507
|
}
|
|
473
508
|
async calcChanges(assets) {
|
|
@@ -480,28 +515,26 @@ class DatabaseHandler extends default_1.default {
|
|
|
480
515
|
update: [],
|
|
481
516
|
conflicts: [],
|
|
482
517
|
};
|
|
483
|
-
// Convert enabled_clients by name to the id
|
|
484
|
-
//
|
|
485
|
-
|
|
518
|
+
// Convert enabled_clients by name to the id. `getType()` fetches and enriches the existing
|
|
519
|
+
// connections with `enabled_clients` and caches the result in `this.existing`, so the
|
|
520
|
+
// `super.calcChanges()` call below reuses it instead of fetching again.
|
|
521
|
+
const [clients, actions, existingWithEnabledClients] = await Promise.all([
|
|
486
522
|
(0, client_1.paginate)(this.client.clients.list, {
|
|
487
523
|
paginate: true,
|
|
488
524
|
}),
|
|
489
|
-
(0, client_1.paginate)(this.client.connections.list, {
|
|
490
|
-
strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
|
|
491
|
-
checkpoint: true,
|
|
492
|
-
include_totals: true,
|
|
493
|
-
}),
|
|
494
525
|
(0, client_1.paginate)(this.client.actions.list, {
|
|
495
526
|
paginate: true,
|
|
496
527
|
include_totals: true,
|
|
497
528
|
}),
|
|
529
|
+
this.getType(),
|
|
498
530
|
]);
|
|
531
|
+
const existingConnections = existingWithEnabledClients || [];
|
|
499
532
|
const formatted = databases.map((db) => {
|
|
500
533
|
const { options, ...rest } = db;
|
|
501
534
|
const formattedOptions = this.getFormattedOptions(options, actions);
|
|
502
535
|
const formattedDb = { ...rest, options: formattedOptions };
|
|
503
536
|
if (db.enabled_clients) {
|
|
504
|
-
formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db,
|
|
537
|
+
formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingConnections, clients);
|
|
505
538
|
}
|
|
506
539
|
return formattedDb;
|
|
507
540
|
});
|
|
@@ -531,21 +564,22 @@ class DatabaseHandler extends default_1.default {
|
|
|
531
564
|
include_totals: true,
|
|
532
565
|
}),
|
|
533
566
|
]);
|
|
567
|
+
const existingWithEnabledClients = await this.enrichConnectionsWithEnabledClients(existingDatabasesConnections);
|
|
534
568
|
const formatted = databases.map((db) => {
|
|
535
569
|
const { options, ...rest } = db;
|
|
536
570
|
const formattedOptions = this.getFormattedOptions(options, actions);
|
|
537
571
|
const formattedDb = { ...rest, options: formattedOptions };
|
|
538
572
|
if (db.enabled_clients) {
|
|
539
|
-
formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db,
|
|
573
|
+
formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingWithEnabledClients, clients);
|
|
540
574
|
}
|
|
541
575
|
return formattedDb;
|
|
542
576
|
});
|
|
543
577
|
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
544
578
|
type: this.type,
|
|
545
579
|
assets: formatted,
|
|
546
|
-
existing:
|
|
580
|
+
existing: existingWithEnabledClients,
|
|
547
581
|
identifiers: this.identifiers,
|
|
548
|
-
ignoreDryRunFields: this.
|
|
582
|
+
ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
|
|
549
583
|
});
|
|
550
584
|
}
|
|
551
585
|
// Run after clients are updated so we can convert all the enabled_clients names to id's
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { Asset, Assets, Auth0APIClient, CalculatedChanges } from '../../../types';
|
|
2
2
|
import { ConfigFunction } from '../../../configFactory';
|
|
3
3
|
export declare function order(value: any): (t: any, n: any, descriptor: any) => any;
|
|
4
|
+
export interface RetryOptions {
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
initialDelay?: number;
|
|
7
|
+
maxDelay?: number;
|
|
8
|
+
onRetry?: (error: any, attempt: number, delay: number) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Executes a function with exponential backoff retry logic for rate limit errors (429).
|
|
12
|
+
*
|
|
13
|
+
* @param fn - The function to execute with retry logic
|
|
14
|
+
* @param options - Configuration options for retry behavior
|
|
15
|
+
* @returns Promise that resolves with the function result or rejects after max retries
|
|
16
|
+
*/
|
|
17
|
+
export declare function retryWithExponentialBackoff<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
4
18
|
type ApiMethodOverride = string | Function;
|
|
5
19
|
export default class APIHandler {
|
|
6
20
|
config: ConfigFunction;
|
|
@@ -50,6 +64,15 @@ export default class APIHandler {
|
|
|
50
64
|
*/
|
|
51
65
|
getEffectiveIgnoreDryRunFields(): string[];
|
|
52
66
|
getClientFN(fn: ApiMethodOverride): Function;
|
|
67
|
+
/**
|
|
68
|
+
* Builds the exponential-backoff retry configuration for this handler from the
|
|
69
|
+
* shared `AUTH0_MAX_RETRIES` / `AUTH0_RETRY_INITIAL_DELAY_MS` /
|
|
70
|
+
* `AUTH0_RETRY_MAX_DELAY_MS` config keys. Exposed so that handlers which issue
|
|
71
|
+
* writes outside the default `processChanges` flow (e.g. organizations, which
|
|
72
|
+
* writes nested connections/grants directly) can wrap those calls in the same
|
|
73
|
+
* 429 backoff behaviour as the base handler.
|
|
74
|
+
*/
|
|
75
|
+
getRetryConfig(): RetryOptions;
|
|
53
76
|
didDelete(item: Asset): void;
|
|
54
77
|
didCreate(item: Asset): void;
|
|
55
78
|
didUpdate(item: Asset): void;
|
|
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.order = order;
|
|
7
|
-
|
|
7
|
+
exports.retryWithExponentialBackoff = retryWithExponentialBackoff;
|
|
8
8
|
const validationError_1 = __importDefault(require("../../validationError"));
|
|
9
9
|
const utils_1 = require("../../utils");
|
|
10
10
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
@@ -20,6 +20,19 @@ function order(value) {
|
|
|
20
20
|
return descriptor;
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* node-auth0 v7 removed the exported `JSONApiResponse` class, so we can no
|
|
25
|
+
* longer use `instanceof` to tell an SDK response envelope apart from a plain
|
|
26
|
+
* asset. Duck-type the `ApiResponse<T>` shape ({ data, status, headers })
|
|
27
|
+
* instead.
|
|
28
|
+
*/
|
|
29
|
+
function isApiResponseEnvelope(item) {
|
|
30
|
+
return (typeof item === 'object' &&
|
|
31
|
+
item !== null &&
|
|
32
|
+
'data' in item &&
|
|
33
|
+
'status' in item &&
|
|
34
|
+
'headers' in item);
|
|
35
|
+
}
|
|
23
36
|
// Retry configuration constants
|
|
24
37
|
const DEFAULT_MAX_RETRIES = 3;
|
|
25
38
|
const DEFAULT_INITIAL_DELAY_MS = 1000; // 1 second
|
|
@@ -114,24 +127,35 @@ class APIHandler {
|
|
|
114
127
|
}
|
|
115
128
|
return fn;
|
|
116
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Builds the exponential-backoff retry configuration for this handler from the
|
|
132
|
+
* shared `AUTH0_MAX_RETRIES` / `AUTH0_RETRY_INITIAL_DELAY_MS` /
|
|
133
|
+
* `AUTH0_RETRY_MAX_DELAY_MS` config keys. Exposed so that handlers which issue
|
|
134
|
+
* writes outside the default `processChanges` flow (e.g. organizations, which
|
|
135
|
+
* writes nested connections/grants directly) can wrap those calls in the same
|
|
136
|
+
* 429 backoff behaviour as the base handler.
|
|
137
|
+
*/
|
|
138
|
+
getRetryConfig() {
|
|
139
|
+
const retryConfig = {
|
|
140
|
+
maxRetries: this.config('AUTH0_MAX_RETRIES') || DEFAULT_MAX_RETRIES,
|
|
141
|
+
initialDelay: this.config('AUTH0_RETRY_INITIAL_DELAY_MS') || DEFAULT_INITIAL_DELAY_MS,
|
|
142
|
+
maxDelay: this.config('AUTH0_RETRY_MAX_DELAY_MS') || DEFAULT_MAX_DELAY_MS,
|
|
143
|
+
onRetry: (error, attempt, delay) => {
|
|
144
|
+
logger_1.default.warn(`Rate limit hit for [${this.type}]. Retrying attempt ${attempt}/${retryConfig.maxRetries} after ${Math.round(delay / 1000)}s...`);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
return retryConfig;
|
|
148
|
+
}
|
|
117
149
|
didDelete(item) {
|
|
118
150
|
logger_1.default.info(`Deleted [${this.type}]: ${this.objString(item)}`);
|
|
119
151
|
}
|
|
120
152
|
didCreate(item) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
logger_1.default.info(`Created [${this.type}]: ${this.objString(item)}`);
|
|
126
|
-
}
|
|
153
|
+
const payload = isApiResponseEnvelope(item) ? item.data : item;
|
|
154
|
+
logger_1.default.info(`Created [${this.type}]: ${this.objString(payload)}`);
|
|
127
155
|
}
|
|
128
156
|
didUpdate(item) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
logger_1.default.info(`Updated [${this.type}]: ${this.objString(item)}`);
|
|
134
|
-
}
|
|
157
|
+
const payload = isApiResponseEnvelope(item) ? item.data : item;
|
|
158
|
+
logger_1.default.info(`Updated [${this.type}]: ${this.objString(payload)}`);
|
|
135
159
|
}
|
|
136
160
|
objString(item) {
|
|
137
161
|
return (0, utils_1.convertJsonToString)(item);
|
|
@@ -168,6 +192,9 @@ class APIHandler {
|
|
|
168
192
|
this.type === 'branding' ||
|
|
169
193
|
this.type === 'emailProvider' ||
|
|
170
194
|
this.type === 'guardianPhoneFactorSelectedProvider' ||
|
|
195
|
+
this.type === 'guardianPhoneFactorSettings' ||
|
|
196
|
+
this.type === 'guardianEmailFactorSettings' ||
|
|
197
|
+
this.type === 'guardianSettings' ||
|
|
171
198
|
this.type === 'guardianPolicies' ||
|
|
172
199
|
this.type === 'riskAssessment') {
|
|
173
200
|
return `${this.type} settings`;
|
|
@@ -210,7 +237,6 @@ class APIHandler {
|
|
|
210
237
|
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
211
238
|
type: this.type,
|
|
212
239
|
assets: typeAssets,
|
|
213
|
-
// @ts-ignore TODO: investigate what happens when `existing` is null
|
|
214
240
|
existing,
|
|
215
241
|
identifiers: this.identifiers,
|
|
216
242
|
ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
|
|
@@ -243,7 +269,6 @@ class APIHandler {
|
|
|
243
269
|
return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
|
|
244
270
|
type: this.type,
|
|
245
271
|
assets: typeAssets,
|
|
246
|
-
// @ts-ignore TODO: investigate what happens when `existing` is null
|
|
247
272
|
existing,
|
|
248
273
|
identifiers: this.identifiers,
|
|
249
274
|
ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
|
|
@@ -282,14 +307,7 @@ class APIHandler {
|
|
|
282
307
|
const conflicts = changes.conflicts || [];
|
|
283
308
|
logger_1.default.debug(`Start processChanges for ${this.type} [delete:${del.length}] [update:${update.length}], [create:${create.length}], [conflicts:${conflicts.length}]`);
|
|
284
309
|
// Set retry configuration from config
|
|
285
|
-
const retryConfig =
|
|
286
|
-
maxRetries: this.config('AUTH0_MAX_RETRIES') || DEFAULT_MAX_RETRIES,
|
|
287
|
-
initialDelay: this.config('AUTH0_RETRY_INITIAL_DELAY_MS') || DEFAULT_INITIAL_DELAY_MS,
|
|
288
|
-
maxDelay: this.config('AUTH0_RETRY_MAX_DELAY_MS') || DEFAULT_MAX_DELAY_MS,
|
|
289
|
-
onRetry: (error, attempt, delay) => {
|
|
290
|
-
logger_1.default.warn(`Rate limit hit for [${this.type}]. Retrying attempt ${attempt}/${retryConfig.maxRetries} after ${Math.round(delay / 1000)}s...`);
|
|
291
|
-
},
|
|
292
|
-
};
|
|
310
|
+
const retryConfig = this.getRetryConfig();
|
|
293
311
|
// Process Deleted
|
|
294
312
|
if (del.length > 0) {
|
|
295
313
|
const allowDelete = this.config('AUTH0_ALLOW_DELETE') === 'true' || this.config('AUTH0_ALLOW_DELETE') === true;
|
|
@@ -328,8 +346,8 @@ class APIHandler {
|
|
|
328
346
|
const updateFN = this.getClientFN(this.functions.update);
|
|
329
347
|
const updatePayload = (() => {
|
|
330
348
|
const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
|
|
331
|
-
const
|
|
332
|
-
return (0, utils_1.
|
|
349
|
+
const obfuscatedStripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
|
|
350
|
+
return (0, utils_1.stripUnresolvedPlaceholders)(obfuscatedStripped, this.type, this.objString(updateItem));
|
|
333
351
|
})();
|
|
334
352
|
return updateFN(updateItem[this.id], updatePayload);
|
|
335
353
|
}, retryConfig)
|
|
@@ -347,8 +365,8 @@ class APIHandler {
|
|
|
347
365
|
const createFunction = this.getClientFN(this.functions.create);
|
|
348
366
|
const createPayload = (() => {
|
|
349
367
|
const strippedPayload = (0, utils_1.stripFields)(createItem, this.stripCreateFields);
|
|
350
|
-
const
|
|
351
|
-
return (0, utils_1.
|
|
368
|
+
const obfuscatedStripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(strippedPayload, this.sensitiveFieldsToObfuscate);
|
|
369
|
+
return (0, utils_1.stripUnresolvedPlaceholders)(obfuscatedStripped, this.type, this.objString(createItem));
|
|
352
370
|
})();
|
|
353
371
|
return createFunction(createPayload);
|
|
354
372
|
}, retryConfig)
|
|
@@ -369,8 +387,8 @@ class APIHandler {
|
|
|
369
387
|
const updateFN = this.getClientFN(this.functions.update);
|
|
370
388
|
const updatePayload = (() => {
|
|
371
389
|
const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
|
|
372
|
-
const
|
|
373
|
-
return (0, utils_1.
|
|
390
|
+
const obfuscatedStripped = (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
|
|
391
|
+
return (0, utils_1.stripUnresolvedPlaceholders)(obfuscatedStripped, this.type, this.objString(updateItem));
|
|
374
392
|
})();
|
|
375
393
|
return updateFN(updateItem[this.id], updatePayload);
|
|
376
394
|
}, retryConfig)
|
|
@@ -38,10 +38,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
return result;
|
|
39
39
|
};
|
|
40
40
|
})();
|
|
41
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
42
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
43
|
+
};
|
|
41
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
45
|
exports.schema = void 0;
|
|
43
46
|
const default_1 = __importStar(require("./default"));
|
|
44
47
|
const client_1 = require("../client");
|
|
48
|
+
const logger_1 = __importDefault(require("../../../logger"));
|
|
45
49
|
exports.schema = {
|
|
46
50
|
type: 'array',
|
|
47
51
|
items: {
|
|
@@ -161,8 +165,12 @@ class EventStreamsHandler extends default_1.default {
|
|
|
161
165
|
create: changesResponse.create.map((stream) => this.resolveActionId(stream)),
|
|
162
166
|
update: changesResponse.update.map((stream) => {
|
|
163
167
|
const resolved = this.resolveActionId(stream);
|
|
164
|
-
//
|
|
165
|
-
|
|
168
|
+
// A destination's type cannot be changed once an event stream is created. The API
|
|
169
|
+
// rejects the destination on PATCH for eventbridge and action streams, so strip it
|
|
170
|
+
// from the update payload and only apply the other mutable fields.
|
|
171
|
+
if (resolved.destination?.type === 'eventbridge' ||
|
|
172
|
+
resolved.destination?.type === 'action') {
|
|
173
|
+
logger_1.default.info(`Skipping destination update for event stream "${resolved.name}": ${resolved.destination.type} destinations cannot be changed after creation.`);
|
|
166
174
|
const { destination: _dest, ...rest } = resolved;
|
|
167
175
|
return rest;
|
|
168
176
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import DefaultHandler from './default';
|
|
2
|
+
import { Asset, Assets } from '../../../types';
|
|
3
|
+
export declare const schema: {
|
|
4
|
+
type: string;
|
|
5
|
+
properties: {
|
|
6
|
+
otp_length: {
|
|
7
|
+
type: string;
|
|
8
|
+
description: string;
|
|
9
|
+
};
|
|
10
|
+
otp_expiration_time: {
|
|
11
|
+
type: string;
|
|
12
|
+
description: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
additionalProperties: boolean;
|
|
16
|
+
};
|
|
17
|
+
export default class GuardianEmailFactorSettingsHandler extends DefaultHandler {
|
|
18
|
+
existing: Asset;
|
|
19
|
+
constructor(options: any);
|
|
20
|
+
getType(): Promise<Asset | null>;
|
|
21
|
+
processChanges(assets: Assets): Promise<void>;
|
|
22
|
+
}
|