auth0-deploy-cli 8.24.0 → 8.25.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 CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [8.25.0] - 2026-01-08
11
+
12
+ ### Added
13
+
14
+ - `AUTH0_INCLUDED_CONNECTIONS` config property to include only selected `connection`. [#1242]
15
+
16
+ ### Fixed
17
+
18
+ - Fix `tokenExchangeProfiles` profiles handling. [#1253]
19
+ - Fix `idle_ephemeral_session_lifetime` and `ephemeral_session_lifetime` handling while importing [#1261]
20
+
10
21
  ## [8.24.0] - 2025-12-22
11
22
 
12
23
  ### Added
@@ -1591,9 +1602,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1591
1602
  [#1232]: https://github.com/auth0/auth0-deploy-cli/issues/1232
1592
1603
  [#1239]: https://github.com/auth0/auth0-deploy-cli/issues/1239
1593
1604
  [#1240]: https://github.com/auth0/auth0-deploy-cli/issues/1240
1605
+ [#1242]: https://github.com/auth0/auth0-deploy-cli/issues/1242
1594
1606
  [#1244]: https://github.com/auth0/auth0-deploy-cli/issues/1244
1595
1607
  [#1246]: https://github.com/auth0/auth0-deploy-cli/issues/1246
1596
- [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.24.0...HEAD
1608
+ [#1253]: https://github.com/auth0/auth0-deploy-cli/issues/1253
1609
+ [Unreleased]: https://github.com/auth0/auth0-deploy-cli/compare/v8.25.0...HEAD
1610
+ [8.25.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.24.0...v8.25.0
1597
1611
  [8.24.0]: https://github.com/auth0/auth0-deploy-cli/compare/v8.23.2...v8.24.0
1598
1612
  [8.23.2]: https://github.com/auth0/auth0-deploy-cli/compare/v8.23.1...v8.23.2
1599
1613
  [8.23.1]: https://github.com/auth0/auth0-deploy-cli/compare/v8.23.0...v8.23.1
@@ -15,12 +15,17 @@ function parse(context) {
15
15
  return { tenant: null };
16
16
  }
17
17
  /* eslint-disable camelcase */
18
- const { session_lifetime, idle_session_lifetime, ...tenant } = (0, utils_1.loadJSON)(tenantFile, {
18
+ const { session_lifetime, idle_session_lifetime, idle_ephemeral_session_lifetime, ephemeral_session_lifetime, ...tenant } = (0, utils_1.loadJSON)(tenantFile, {
19
19
  mappings: context.mappings,
20
20
  disableKeywordReplacement: context.disableKeywordReplacement,
21
21
  });
22
22
  (0, utils_1.clearTenantFlags)(tenant);
23
- const sessionDurations = (0, sessionDurationsToMinutes_1.sessionDurationsToMinutes)({ session_lifetime, idle_session_lifetime });
23
+ const sessionDurations = (0, sessionDurationsToMinutes_1.sessionDurationsToMinutes)({
24
+ session_lifetime,
25
+ idle_session_lifetime,
26
+ idle_ephemeral_session_lifetime,
27
+ ephemeral_session_lifetime,
28
+ });
24
29
  return {
25
30
  //@ts-ignore
26
31
  tenant: {
@@ -63,6 +63,9 @@ class DirectoryContext {
63
63
  resourceServers: config.AUTH0_EXCLUDED_RESOURCE_SERVERS || [],
64
64
  defaults: config.AUTH0_EXCLUDED_DEFAULTS || [],
65
65
  };
66
+ this.assets.include = {
67
+ connections: config.AUTH0_INCLUDED_CONNECTIONS || [],
68
+ };
66
69
  }
67
70
  loadFile(f, folder) {
68
71
  const basePath = path.join(this.filePath, folder);
@@ -26,6 +26,7 @@ const nonPrimitiveProps = [
26
26
  'AUTH0_INCLUDED_ONLY',
27
27
  'EXCLUDED_PROPS',
28
28
  'INCLUDED_PROPS',
29
+ 'AUTH0_INCLUDED_CONNECTIONS',
29
30
  ];
30
31
  const EA_FEATURES = [];
31
32
  const setupContext = async (config, command) => {
@@ -97,6 +98,15 @@ const setupContext = async (config, command) => {
97
98
  logger_1.default.warn(`Usage of the ${usedDeprecatedParams.join(', ')} exclusion ${usedDeprecatedParams.length > 1 ? 'params are' : 'param is'} deprecated and may be removed from future major versions. See: https://github.com/auth0/auth0-deploy-cli/issues/451#user-content-deprecated-exclusion-props for details.`);
98
99
  }
99
100
  })(config);
101
+ ((config) => {
102
+ const hasIncludedConnections = config.AUTH0_INCLUDED_CONNECTIONS !== undefined &&
103
+ config.AUTH0_INCLUDED_CONNECTIONS.length > 0;
104
+ const hasExcludedConnections = config.AUTH0_EXCLUDED_CONNECTIONS !== undefined &&
105
+ config.AUTH0_EXCLUDED_CONNECTIONS.length > 0;
106
+ if (hasIncludedConnections && hasExcludedConnections) {
107
+ throw new Error('Both AUTH0_INCLUDED_CONNECTIONS and AUTH0_EXCLUDED_CONNECTIONS configuration values are defined, only one can be configured at a time.');
108
+ }
109
+ })(config);
100
110
  ((config) => {
101
111
  // Check if experimental early access features are enabled
102
112
  if (config.AUTH0_EXPERIMENTAL_EA) {
@@ -6,9 +6,14 @@ async function parse(context) {
6
6
  if (!context.assets.tenant)
7
7
  return { tenant: null };
8
8
  /* eslint-disable camelcase */
9
- const { session_lifetime, idle_session_lifetime, ...tenant } = context.assets.tenant;
9
+ const { session_lifetime, idle_session_lifetime, idle_ephemeral_session_lifetime, ephemeral_session_lifetime, ...tenant } = context.assets.tenant;
10
10
  (0, utils_1.clearTenantFlags)(tenant);
11
- const sessionDurations = (0, sessionDurationsToMinutes_1.sessionDurationsToMinutes)({ session_lifetime, idle_session_lifetime });
11
+ const sessionDurations = (0, sessionDurationsToMinutes_1.sessionDurationsToMinutes)({
12
+ session_lifetime,
13
+ idle_session_lifetime,
14
+ idle_ephemeral_session_lifetime,
15
+ ephemeral_session_lifetime,
16
+ });
12
17
  return {
13
18
  tenant: {
14
19
  ...tenant,
@@ -32,6 +32,9 @@ class YAMLContext {
32
32
  resourceServers: config.AUTH0_EXCLUDED_RESOURCE_SERVERS || [],
33
33
  defaults: config.AUTH0_EXCLUDED_DEFAULTS || [],
34
34
  };
35
+ this.assets.include = {
36
+ connections: config.AUTH0_INCLUDED_CONNECTIONS || [],
37
+ };
35
38
  this.basePath = (() => {
36
39
  if (!!config.AUTH0_BASE_PATH)
37
40
  return config.AUTH0_BASE_PATH;
@@ -80,6 +83,7 @@ class YAMLContext {
80
83
  }, {});
81
84
  const initialAssets = {
82
85
  exclude: this.assets.exclude, // Keep the exclude rules in result assets
86
+ include: this.assets.include, // Keep the include rules in result assets
83
87
  };
84
88
  this.assets = Object.keys(this.assets).reduce((acc, key) => {
85
89
  // Get the list of asset types to include
@@ -173,6 +177,7 @@ class YAMLContext {
173
177
  let cleaned = (0, readonly_1.default)(this.assets, this.config);
174
178
  // Delete exclude as it's not part of the auth0 tenant config
175
179
  delete cleaned.exclude;
180
+ delete cleaned.include;
176
181
  // Optionally Strip identifiers
177
182
  if (!this.config.AUTH0_EXPORT_IDENTIFIERS) {
178
183
  cleaned = (0, utils_1.stripIdentifiers)(auth0, cleaned);
@@ -1,7 +1,11 @@
1
- export declare const sessionDurationsToMinutes: ({ session_lifetime, idle_session_lifetime, }: {
1
+ export declare const sessionDurationsToMinutes: ({ session_lifetime, idle_session_lifetime, idle_ephemeral_session_lifetime, ephemeral_session_lifetime, }: {
2
2
  session_lifetime?: number;
3
3
  idle_session_lifetime?: number;
4
+ idle_ephemeral_session_lifetime?: number;
5
+ ephemeral_session_lifetime?: number;
4
6
  }) => {
5
7
  session_lifetime_in_minutes?: number;
6
8
  idle_session_lifetime_in_minutes?: number;
9
+ idle_ephemeral_session_lifetime_in_minutes?: number;
10
+ ephemeral_session_lifetime_in_minutes?: number;
7
11
  };
@@ -4,12 +4,16 @@ exports.sessionDurationsToMinutes = void 0;
4
4
  function hoursToMinutes(hours) {
5
5
  return Math.round(hours * 60);
6
6
  }
7
- const sessionDurationsToMinutes = ({ session_lifetime, idle_session_lifetime, }) => {
7
+ const sessionDurationsToMinutes = ({ session_lifetime, idle_session_lifetime, idle_ephemeral_session_lifetime, ephemeral_session_lifetime, }) => {
8
8
  const sessionDurations = {};
9
9
  if (!!session_lifetime)
10
10
  sessionDurations.session_lifetime_in_minutes = hoursToMinutes(session_lifetime);
11
11
  if (!!idle_session_lifetime)
12
12
  sessionDurations.idle_session_lifetime_in_minutes = hoursToMinutes(idle_session_lifetime);
13
+ if (!!idle_ephemeral_session_lifetime)
14
+ sessionDurations.idle_ephemeral_session_lifetime_in_minutes = hoursToMinutes(idle_ephemeral_session_lifetime);
15
+ if (!!ephemeral_session_lifetime)
16
+ sessionDurations.ephemeral_session_lifetime_in_minutes = hoursToMinutes(ephemeral_session_lifetime);
13
17
  return sessionDurations;
14
18
  };
15
19
  exports.sessionDurationsToMinutes = sessionDurationsToMinutes;
@@ -551,13 +551,16 @@ class ConnectionsHandler extends default_1.default {
551
551
  if (!isOptionExists) {
552
552
  logger_1.default.warn(`Insufficient scope the update:connections_options scope is required to update ${this.type} options.`);
553
553
  }
554
+ const includedConnections = (assets.include && assets.include.connections) || [];
554
555
  const excludedConnections = (assets.exclude && assets.exclude.connections) || [];
555
- const changes = await this.calcChanges(assets);
556
- await super.processChanges(assets, (0, utils_1.filterExcluded)(changes, excludedConnections));
556
+ let changes = await this.calcChanges(assets);
557
+ changes = (0, utils_1.filterExcluded)(changes, excludedConnections);
558
+ changes = (0, utils_1.filterIncluded)(changes, includedConnections);
559
+ await super.processChanges(assets, changes);
557
560
  // process enabled clients
558
- await (0, exports.processConnectionEnabledClients)(this.client, this.type, (0, utils_1.filterExcluded)(changes, excludedConnections));
561
+ await (0, exports.processConnectionEnabledClients)(this.client, this.type, changes);
559
562
  // process directory provisioning
560
- await this.processConnectionDirectoryProvisioning((0, utils_1.filterExcluded)(changes, excludedConnections));
563
+ await this.processConnectionDirectoryProvisioning(changes);
561
564
  }
562
565
  }
563
566
  exports.default = ConnectionsHandler;
@@ -4,5 +4,6 @@ declare const _default: { [key in AssetTypes]: {
4
4
  default: typeof APIHandler;
5
5
  excludeSchema?: any;
6
6
  schema: any;
7
+ includeSchema?: any;
7
8
  }; };
8
9
  export default _default;
@@ -11,10 +11,6 @@ export declare const schema: {
11
11
  type: string;
12
12
  description: string;
13
13
  };
14
- id: {
15
- type: string;
16
- description: string;
17
- };
18
14
  subject_token_type: {
19
15
  type: string;
20
16
  description: string;
@@ -28,16 +24,6 @@ export declare const schema: {
28
24
  enum: string[];
29
25
  description: string;
30
26
  };
31
- created_at: {
32
- type: string;
33
- format: string;
34
- description: string;
35
- };
36
- updated_at: {
37
- type: string;
38
- format: string;
39
- description: string;
40
- };
41
27
  };
42
28
  required: string[];
43
29
  };
@@ -55,10 +55,6 @@ exports.schema = {
55
55
  type: 'string',
56
56
  description: 'The name of the token exchange profile',
57
57
  },
58
- id: {
59
- type: 'string',
60
- description: 'The unique identifier of the token exchange profile',
61
- },
62
58
  subject_token_type: {
63
59
  type: 'string',
64
60
  description: 'The URI representing the subject token type',
@@ -72,16 +68,6 @@ exports.schema = {
72
68
  enum: ['custom_authentication'],
73
69
  description: 'The type of token exchange profile',
74
70
  },
75
- created_at: {
76
- type: 'string',
77
- format: 'date-time',
78
- description: 'The timestamp when the profile was created',
79
- },
80
- updated_at: {
81
- type: 'string',
82
- format: 'date-time',
83
- description: 'The timestamp when the profile was last updated',
84
- },
85
71
  },
86
72
  required: ['name', 'subject_token_type', 'action', 'type'],
87
73
  },
@@ -92,10 +78,10 @@ class TokenExchangeProfilesHandler extends default_1.default {
92
78
  ...config,
93
79
  type: 'tokenExchangeProfiles',
94
80
  id: 'id',
95
- identifiers: ['id', 'name'],
81
+ identifiers: ['id', 'subject_token_type'],
96
82
  // Only name and subject_token_type can be updated
97
- stripUpdateFields: ['id', 'created_at', 'updated_at', 'action_id', 'type'],
98
- stripCreateFields: ['id', 'created_at', 'updated_at'],
83
+ stripUpdateFields: ['created_at', 'updated_at', 'action_id', 'type'],
84
+ stripCreateFields: ['created_at', 'updated_at'],
99
85
  });
100
86
  }
101
87
  sanitizeForExport(profile, actions) {
@@ -145,9 +131,9 @@ class TokenExchangeProfilesHandler extends default_1.default {
145
131
  paginate: true,
146
132
  });
147
133
  // Fetch all actions to map action_id to action name
148
- const actions = await this.getActions();
134
+ this.actions = await this.getActions();
149
135
  // Map action_id to action name for each profile
150
- this.existing = profiles.map((profile) => this.sanitizeForExport(profile, actions));
136
+ this.existing = profiles.map((profile) => this.sanitizeForExport(profile, this.actions ?? []));
151
137
  return this.existing;
152
138
  }
153
139
  catch (err) {
@@ -163,31 +149,34 @@ class TokenExchangeProfilesHandler extends default_1.default {
163
149
  // Do nothing if not set
164
150
  if (!tokenExchangeProfiles)
165
151
  return;
166
- // Fetch actions to resolve action names to IDs
167
- const actions = await this.getActions();
168
- // Map action names to action_ids before processing
169
- const sanitizedProfiles = tokenExchangeProfiles.map((profile) => this.sanitizeForAPI(profile, actions));
170
- // Create modified assets with sanitized profiles
171
- const modifiedAssets = {
172
- ...assets,
173
- tokenExchangeProfiles: sanitizedProfiles,
174
- };
175
152
  // Calculate changes
176
- const { del, update, create, conflicts } = await this.calcChanges(modifiedAssets);
153
+ const { del, update, create, conflicts } = await this.calcChanges(assets);
177
154
  logger_1.default.debug(`Start processChanges for tokenExchangeProfiles [delete:${del.length}] [update:${update.length}], [create:${create.length}], [conflicts:${conflicts.length}]`);
155
+ // Fetch actions to resolve action names to IDs
156
+ if (!this.actions || this.actions.length === 0) {
157
+ this.actions = await this.getActions();
158
+ }
178
159
  // Process changes in order: delete, create, update
179
160
  if (del.length > 0) {
180
- await this.deleteTokenExchangeProfiles(del);
161
+ await this.deleteTokenExchangeProfiles(del.map((profile) => this.sanitizeForAPI(profile, this.actions ?? [])));
181
162
  }
182
163
  if (create.length > 0) {
183
- await this.createTokenExchangeProfiles(create);
164
+ await this.createTokenExchangeProfiles(create.map((profile) => this.sanitizeForAPI(profile, this.actions ?? [])));
184
165
  }
185
166
  if (update.length > 0) {
186
- await this.updateTokenExchangeProfiles(update);
167
+ await this.updateTokenExchangeProfiles(update.map((profile) => this.sanitizeForAPI(profile, this.actions ?? [])));
187
168
  }
188
169
  }
189
170
  async createTokenExchangeProfile(profile) {
190
- const { id, created_at, updated_at, ...createParams } = profile;
171
+ if (!profile.name || !profile.subject_token_type || !profile.action_id || !profile.type) {
172
+ throw new Error(`Cannot create token exchange profile missing required fields`);
173
+ }
174
+ const createParams = {
175
+ name: profile.name,
176
+ subject_token_type: profile.subject_token_type,
177
+ action_id: profile.action_id,
178
+ type: profile.type,
179
+ };
191
180
  const created = await this.client.tokenExchangeProfiles.create(createParams);
192
181
  return created;
193
182
  }
@@ -207,10 +196,14 @@ class TokenExchangeProfilesHandler extends default_1.default {
207
196
  .promise();
208
197
  }
209
198
  async updateTokenExchangeProfile(profile) {
210
- const { id, created_at, updated_at, action_id, type, ...updateParams } = profile;
199
+ const { id, name, subject_token_type } = profile;
211
200
  if (!id) {
212
201
  throw new Error(`Cannot update token exchange profile "${profile.name}" - missing id`);
213
202
  }
203
+ const updateParams = {
204
+ name,
205
+ subject_token_type,
206
+ };
214
207
  await this.client.tokenExchangeProfiles.update(id, updateParams);
215
208
  }
216
209
  async updateTokenExchangeProfiles(updates) {
@@ -9,6 +9,13 @@ declare const _default: {
9
9
  };
10
10
  default: {};
11
11
  };
12
+ include: {
13
+ type: string;
14
+ properties: {
15
+ [key: string]: Object;
16
+ };
17
+ default: {};
18
+ };
12
19
  };
13
20
  additionalProperties: boolean;
14
21
  };
@@ -14,6 +14,12 @@ const excludeSchema = Object.entries(handlers_1.default).reduce((map, [name, obj
14
14
  }
15
15
  return map;
16
16
  }, {});
17
+ const includeSchema = Object.entries(handlers_1.default).reduce((map, [name, obj]) => {
18
+ if (obj.includeSchema) {
19
+ map[name] = obj.includeSchema;
20
+ }
21
+ return map;
22
+ }, {});
17
23
  exports.default = {
18
24
  type: 'object',
19
25
  $schema: 'http://json-schema.org/draft-07/schema#',
@@ -24,6 +30,11 @@ exports.default = {
24
30
  properties: { ...excludeSchema },
25
31
  default: {},
26
32
  },
33
+ include: {
34
+ type: 'object',
35
+ properties: { ...includeSchema },
36
+ default: {},
37
+ },
27
38
  },
28
39
  additionalProperties: false,
29
40
  };
@@ -19,6 +19,7 @@ export declare function stripFields(obj: Asset, fields: string[]): Asset;
19
19
  export declare function getEnabledClients(assets: Assets, connection: Asset, existing: Asset[], clients: Asset[]): string[] | undefined;
20
20
  export declare function duplicateItems(arr: Asset[], key: string): Asset[];
21
21
  export declare function filterExcluded(changes: CalculatedChanges, exclude: string[]): CalculatedChanges;
22
+ export declare function filterIncluded(changes: CalculatedChanges, include: string[]): CalculatedChanges;
22
23
  export declare function areArraysEquals(x: any[], y: any[]): boolean;
23
24
  export declare const obfuscateSensitiveValues: (data: Asset | Asset[] | null, sensitiveFieldsToObfuscate: string[]) => Asset | Asset[] | null;
24
25
  export declare const stripObfuscatedFieldsFromPayload: (data: Asset | Asset[] | null, obfuscatedFields: string[]) => Asset | Asset[] | null;
@@ -50,6 +50,7 @@ exports.stripFields = stripFields;
50
50
  exports.getEnabledClients = getEnabledClients;
51
51
  exports.duplicateItems = duplicateItems;
52
52
  exports.filterExcluded = filterExcluded;
53
+ exports.filterIncluded = filterIncluded;
53
54
  exports.areArraysEquals = areArraysEquals;
54
55
  exports.sleep = sleep;
55
56
  exports.maskSecretAtPath = maskSecretAtPath;
@@ -213,6 +214,19 @@ function filterExcluded(changes, exclude) {
213
214
  conflicts: filter(conflicts),
214
215
  };
215
216
  }
217
+ function filterIncluded(changes, include) {
218
+ const { del, update, create, conflicts } = changes;
219
+ if (!include || !include.length) {
220
+ return changes;
221
+ }
222
+ const filter = (list) => list.filter((item) => include.includes(item.name));
223
+ return {
224
+ del: filter(del),
225
+ update: filter(update),
226
+ create: filter(create),
227
+ conflicts: filter(conflicts),
228
+ };
229
+ }
216
230
  function areArraysEquals(x, y) {
217
231
  return lodash_1.default.isEqual(x && x.sort(), y && y.sort());
218
232
  }
package/lib/types.d.ts CHANGED
@@ -76,6 +76,7 @@ export type Config = {
76
76
  INCLUDED_PROPS?: {
77
77
  [key: string]: string[];
78
78
  };
79
+ AUTH0_INCLUDED_CONNECTIONS?: string[];
79
80
  AUTH0_IGNORE_UNAVAILABLE_MIGRATIONS?: boolean;
80
81
  AUTH0_EXCLUDED_RULES?: string[];
81
82
  AUTH0_EXCLUDED_CLIENTS?: string[];
@@ -131,6 +132,9 @@ export type Assets = Partial<{
131
132
  exclude?: {
132
133
  [key: string]: string[];
133
134
  };
135
+ include?: {
136
+ [key: string]: string[];
137
+ };
134
138
  clientsOrig: Asset[] | null;
135
139
  themes: Theme[] | null;
136
140
  forms: Form[] | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth0-deploy-cli",
3
- "version": "8.24.0",
3
+ "version": "8.25.0",
4
4
  "description": "A command line tool for deploying updates to your Auth0 tenant",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -42,7 +42,7 @@
42
42
  "nconf": "^0.13.0",
43
43
  "promise-pool-executor": "^1.1.1",
44
44
  "sanitize-filename": "^1.6.3",
45
- "undici": "^7.16.0",
45
+ "undici": "^7.18.0",
46
46
  "winston": "^3.19.0",
47
47
  "yargs": "^15.4.1"
48
48
  },
@@ -52,8 +52,8 @@
52
52
  "@types/mocha": "^10.0.10",
53
53
  "@types/nconf": "^0.10.7",
54
54
  "@eslint/js": "^9.39.2",
55
- "@typescript-eslint/eslint-plugin": "^8.50.0",
56
- "@typescript-eslint/parser": "^8.50.0",
55
+ "@typescript-eslint/eslint-plugin": "^8.52.0",
56
+ "@typescript-eslint/parser": "^8.52.0",
57
57
  "chai": "^4.5.0",
58
58
  "chai-as-promised": "^7.1.2",
59
59
  "eslint": "^9.39.2",