auth0-deploy-cli 9.0.0-beta.2 → 9.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.
Files changed (129) hide show
  1. package/AGENTS.md +2 -357
  2. package/CHANGELOG.md +185 -10
  3. package/CLAUDE.md +138 -2
  4. package/README.md +1 -1
  5. package/lib/context/defaults.d.ts +7 -0
  6. package/lib/context/defaults.js +74 -30
  7. package/lib/context/directory/handlers/actionModules.js +1 -4
  8. package/lib/context/directory/handlers/actions.js +1 -4
  9. package/lib/context/directory/handlers/attackProtection.js +11 -1
  10. package/lib/context/directory/handlers/branding.js +4 -1
  11. package/lib/context/directory/handlers/clientAuthCredentials.d.ts +5 -0
  12. package/lib/context/directory/handlers/clientAuthCredentials.js +13 -0
  13. package/lib/context/directory/handlers/clientGrants.js +78 -24
  14. package/lib/context/directory/handlers/clients.js +20 -3
  15. package/lib/context/directory/handlers/connections.js +19 -5
  16. package/lib/context/directory/handlers/databases.js +1 -4
  17. package/lib/context/directory/handlers/emailTemplates.js +5 -0
  18. package/lib/context/directory/handlers/guardianEmailFactorSettings.d.ts +5 -0
  19. package/lib/context/directory/handlers/guardianEmailFactorSettings.js +38 -0
  20. package/lib/context/directory/handlers/guardianPhoneFactorSettings.d.ts +5 -0
  21. package/lib/context/directory/handlers/guardianPhoneFactorSettings.js +38 -0
  22. package/lib/context/directory/handlers/guardianSettings.d.ts +5 -0
  23. package/lib/context/directory/handlers/guardianSettings.js +38 -0
  24. package/lib/context/directory/handlers/hooks.js +1 -4
  25. package/lib/context/directory/handlers/index.js +12 -0
  26. package/lib/context/directory/handlers/networkACLKeys.d.ts +6 -0
  27. package/lib/context/directory/handlers/networkACLKeys.js +54 -0
  28. package/lib/context/directory/handlers/prompts.js +7 -3
  29. package/lib/context/directory/handlers/rateLimitPolicies.d.ts +6 -0
  30. package/lib/context/directory/handlers/rateLimitPolicies.js +53 -0
  31. package/lib/context/directory/handlers/rules.js +1 -4
  32. package/lib/context/directory/index.js +1 -4
  33. package/lib/context/index.js +32 -31
  34. package/lib/context/yaml/handlers/attackProtection.js +5 -2
  35. package/lib/context/yaml/handlers/branding.js +4 -1
  36. package/lib/context/yaml/handlers/clientAuthCredentials.d.ts +5 -0
  37. package/lib/context/yaml/handlers/clientAuthCredentials.js +13 -0
  38. package/lib/context/yaml/handlers/clients.js +19 -1
  39. package/lib/context/yaml/handlers/connections.js +8 -1
  40. package/lib/context/yaml/handlers/flows.js +3 -0
  41. package/lib/context/yaml/handlers/forms.js +3 -0
  42. package/lib/context/yaml/handlers/guardianEmailFactorSettings.d.ts +5 -0
  43. package/lib/context/yaml/handlers/guardianEmailFactorSettings.js +15 -0
  44. package/lib/context/yaml/handlers/guardianPhoneFactorSettings.d.ts +5 -0
  45. package/lib/context/yaml/handlers/guardianPhoneFactorSettings.js +15 -0
  46. package/lib/context/yaml/handlers/guardianSettings.d.ts +5 -0
  47. package/lib/context/yaml/handlers/guardianSettings.js +15 -0
  48. package/lib/context/yaml/handlers/index.js +12 -0
  49. package/lib/context/yaml/handlers/networkACLKeys.d.ts +6 -0
  50. package/lib/context/yaml/handlers/networkACLKeys.js +42 -0
  51. package/lib/context/yaml/handlers/prompts.js +3 -1
  52. package/lib/context/yaml/handlers/rateLimitPolicies.d.ts +6 -0
  53. package/lib/context/yaml/handlers/rateLimitPolicies.js +27 -0
  54. package/lib/context/yaml/index.js +85 -7
  55. package/lib/keywordPreservation.d.ts +1 -1
  56. package/lib/keywordPreservation.js +2 -1
  57. package/lib/readonly.js +5 -0
  58. package/lib/tools/auth0/handlers/attackProtection.d.ts +12 -0
  59. package/lib/tools/auth0/handlers/attackProtection.js +66 -6
  60. package/lib/tools/auth0/handlers/clientAuthCredentials.d.ts +27 -0
  61. package/lib/tools/auth0/handlers/clientAuthCredentials.js +234 -0
  62. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.d.ts +38 -0
  63. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.js +123 -0
  64. package/lib/tools/auth0/handlers/clientGrants.d.ts +1 -1
  65. package/lib/tools/auth0/handlers/clients.d.ts +106 -0
  66. package/lib/tools/auth0/handlers/clients.js +207 -3
  67. package/lib/tools/auth0/handlers/connectionProfiles.d.ts +27 -0
  68. package/lib/tools/auth0/handlers/connectionProfiles.js +30 -0
  69. package/lib/tools/auth0/handlers/connections.d.ts +34 -6
  70. package/lib/tools/auth0/handlers/connections.js +75 -11
  71. package/lib/tools/auth0/handlers/databases.d.ts +28 -0
  72. package/lib/tools/auth0/handlers/databases.js +58 -24
  73. package/lib/tools/auth0/handlers/default.d.ts +23 -0
  74. package/lib/tools/auth0/handlers/default.js +47 -29
  75. package/lib/tools/auth0/handlers/eventStreams.js +10 -2
  76. package/lib/tools/auth0/handlers/guardianEmailFactorSettings.d.ts +22 -0
  77. package/lib/tools/auth0/handlers/guardianEmailFactorSettings.js +77 -0
  78. package/lib/tools/auth0/handlers/guardianFactorTemplates.js +13 -4
  79. package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +11 -9
  80. package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +11 -9
  81. package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.d.ts +22 -0
  82. package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.js +77 -0
  83. package/lib/tools/auth0/handlers/guardianPolicies.js +11 -1
  84. package/lib/tools/auth0/handlers/guardianSettings.d.ts +30 -0
  85. package/lib/tools/auth0/handlers/guardianSettings.js +85 -0
  86. package/lib/tools/auth0/handlers/hooks.js +1 -1
  87. package/lib/tools/auth0/handlers/index.js +16 -0
  88. package/lib/tools/auth0/handlers/networkACLKeys.d.ts +45 -0
  89. package/lib/tools/auth0/handlers/networkACLKeys.js +177 -0
  90. package/lib/tools/auth0/handlers/networkACLs.d.ts +132 -2
  91. package/lib/tools/auth0/handlers/networkACLs.js +100 -16
  92. package/lib/tools/auth0/handlers/organizations.d.ts +33 -1
  93. package/lib/tools/auth0/handlers/organizations.js +177 -19
  94. package/lib/tools/auth0/handlers/phoneProvider.js +10 -2
  95. package/lib/tools/auth0/handlers/phoneTemplates.d.ts +4 -1
  96. package/lib/tools/auth0/handlers/phoneTemplates.js +67 -10
  97. package/lib/tools/auth0/handlers/prompts.d.ts +17 -0
  98. package/lib/tools/auth0/handlers/prompts.js +47 -14
  99. package/lib/tools/auth0/handlers/rateLimitPolicies.d.ts +81 -0
  100. package/lib/tools/auth0/handlers/rateLimitPolicies.js +203 -0
  101. package/lib/tools/auth0/handlers/resourceServers.d.ts +48 -0
  102. package/lib/tools/auth0/handlers/resourceServers.js +56 -2
  103. package/lib/tools/auth0/handlers/riskAssessment.d.ts +1 -1
  104. package/lib/tools/auth0/handlers/riskAssessment.js +19 -1
  105. package/lib/tools/auth0/handlers/roles.d.ts +4 -0
  106. package/lib/tools/auth0/handlers/roles.js +27 -9
  107. package/lib/tools/auth0/handlers/rules.js +19 -7
  108. package/lib/tools/auth0/handlers/scimHandler.js +8 -3
  109. package/lib/tools/auth0/handlers/tenant.d.ts +45 -0
  110. package/lib/tools/auth0/handlers/tenant.js +48 -0
  111. package/lib/tools/auth0/handlers/themes.d.ts +37 -1
  112. package/lib/tools/auth0/handlers/themes.js +64 -0
  113. package/lib/tools/auth0/handlers/tokenExchangeProfiles.js +3 -1
  114. package/lib/tools/auth0/index.js +12 -6
  115. package/lib/tools/calculateDryRunChanges.js +12 -8
  116. package/lib/tools/constants.d.ts +3 -0
  117. package/lib/tools/constants.js +8 -0
  118. package/lib/tools/utils.d.ts +3 -0
  119. package/lib/tools/utils.js +41 -2
  120. package/lib/types.d.ts +10 -1
  121. package/lib/utils.d.ts +6 -0
  122. package/lib/utils.js +17 -2
  123. package/package.json +2 -2
  124. package/references/code-style.md +133 -0
  125. package/references/commands.md +98 -0
  126. package/references/docs-update.md +34 -0
  127. package/references/git-workflow.md +135 -0
  128. package/references/pitfalls.md +62 -0
  129. package/references/testing.md +118 -0
@@ -0,0 +1,5 @@
1
+ import { YAMLHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianPhoneFactorSettings = ParsedAsset<'guardianPhoneFactorSettings', Asset>;
4
+ declare const guardianPhoneFactorSettingsHandler: YAMLHandler<ParsedGuardianPhoneFactorSettings>;
5
+ export default guardianPhoneFactorSettingsHandler;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parseAndDump(context) {
4
+ const { guardianPhoneFactorSettings } = context.assets;
5
+ if (!guardianPhoneFactorSettings)
6
+ return { guardianPhoneFactorSettings: null };
7
+ return {
8
+ guardianPhoneFactorSettings,
9
+ };
10
+ }
11
+ const guardianPhoneFactorSettingsHandler = {
12
+ parse: parseAndDump,
13
+ dump: parseAndDump,
14
+ };
15
+ exports.default = guardianPhoneFactorSettingsHandler;
@@ -0,0 +1,5 @@
1
+ import { YAMLHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianSettings = ParsedAsset<'guardianSettings', Asset>;
4
+ declare const guardianSettingsHandler: YAMLHandler<ParsedGuardianSettings>;
5
+ export default guardianSettingsHandler;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parseAndDump(context) {
4
+ const { guardianSettings } = context.assets;
5
+ if (!guardianSettings)
6
+ return { guardianSettings: null };
7
+ return {
8
+ guardianSettings,
9
+ };
10
+ }
11
+ const guardianSettingsHandler = {
12
+ parse: parseAndDump,
13
+ dump: parseAndDump,
14
+ };
15
+ exports.default = guardianSettingsHandler;
@@ -17,6 +17,9 @@ const guardianFactorProviders_1 = __importDefault(require("./guardianFactorProvi
17
17
  const guardianFactorTemplates_1 = __importDefault(require("./guardianFactorTemplates"));
18
18
  const guardianPhoneFactorMessageTypes_1 = __importDefault(require("./guardianPhoneFactorMessageTypes"));
19
19
  const guardianPhoneFactorSelectedProvider_1 = __importDefault(require("./guardianPhoneFactorSelectedProvider"));
20
+ const guardianPhoneFactorSettings_1 = __importDefault(require("./guardianPhoneFactorSettings"));
21
+ const guardianEmailFactorSettings_1 = __importDefault(require("./guardianEmailFactorSettings"));
22
+ const guardianSettings_1 = __importDefault(require("./guardianSettings"));
20
23
  const guardianPolicies_1 = __importDefault(require("./guardianPolicies"));
21
24
  const roles_1 = __importDefault(require("./roles"));
22
25
  const organizations_1 = __importDefault(require("./organizations"));
@@ -38,12 +41,15 @@ const hooks_1 = __importDefault(require("./hooks"));
38
41
  const forms_1 = __importDefault(require("./forms"));
39
42
  const flows_1 = __importDefault(require("./flows"));
40
43
  const flowVaultConnections_1 = __importDefault(require("./flowVaultConnections"));
44
+ const networkACLKeys_1 = __importDefault(require("./networkACLKeys"));
41
45
  const networkACLs_1 = __importDefault(require("./networkACLs"));
42
46
  const userAttributeProfiles_1 = __importDefault(require("./userAttributeProfiles"));
43
47
  const connectionProfiles_1 = __importDefault(require("./connectionProfiles"));
44
48
  const tokenExchangeProfiles_1 = __importDefault(require("./tokenExchangeProfiles"));
45
49
  const supplementalSignals_1 = __importDefault(require("./supplementalSignals"));
50
+ const rateLimitPolicies_1 = __importDefault(require("./rateLimitPolicies"));
46
51
  const eventStreams_1 = __importDefault(require("./eventStreams"));
52
+ const clientAuthCredentials_1 = __importDefault(require("./clientAuthCredentials"));
47
53
  const selfServiceProfiles_1 = __importDefault(require("./selfServiceProfiles"));
48
54
  const yamlHandlers = {
49
55
  rules: rules_1.default,
@@ -64,6 +70,9 @@ const yamlHandlers = {
64
70
  roles: roles_1.default,
65
71
  guardianPhoneFactorMessageTypes: guardianPhoneFactorMessageTypes_1.default,
66
72
  guardianPhoneFactorSelectedProvider: guardianPhoneFactorSelectedProvider_1.default,
73
+ guardianPhoneFactorSettings: guardianPhoneFactorSettings_1.default,
74
+ guardianEmailFactorSettings: guardianEmailFactorSettings_1.default,
75
+ guardianSettings: guardianSettings_1.default,
67
76
  guardianPolicies: guardianPolicies_1.default,
68
77
  actions: actions_1.default,
69
78
  actionModules: actionModules_1.default,
@@ -82,11 +91,14 @@ const yamlHandlers = {
82
91
  flows: flows_1.default,
83
92
  flowVaultConnections: flowVaultConnections_1.default,
84
93
  selfServiceProfiles: selfServiceProfiles_1.default,
94
+ networkACLKeys: networkACLKeys_1.default,
85
95
  networkACLs: networkACLs_1.default,
86
96
  userAttributeProfiles: userAttributeProfiles_1.default,
87
97
  connectionProfiles: connectionProfiles_1.default,
88
98
  tokenExchangeProfiles: tokenExchangeProfiles_1.default,
89
99
  supplementalSignals: supplementalSignals_1.default,
100
+ rateLimitPolicies: rateLimitPolicies_1.default,
90
101
  eventStreams: eventStreams_1.default,
102
+ clientAuthCredentials: clientAuthCredentials_1.default,
91
103
  };
92
104
  exports.default = yamlHandlers;
@@ -0,0 +1,6 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { NetworkAclKey } from '../../../tools/auth0/handlers/networkACLKeys';
4
+ type ParsedNetworkACLKeys = ParsedAsset<'networkACLKeys', NetworkAclKey[]>;
5
+ declare const networkACLKeysHandler: YAMLHandler<ParsedNetworkACLKeys>;
6
+ export default networkACLKeysHandler;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const logger_1 = __importDefault(require("../../../logger"));
7
+ async function parse(context) {
8
+ const { networkACLKeys } = context.assets;
9
+ if (!networkACLKeys)
10
+ return { networkACLKeys: null };
11
+ return {
12
+ networkACLKeys,
13
+ };
14
+ }
15
+ async function dump(context) {
16
+ let { networkACLKeys } = context.assets;
17
+ if (!networkACLKeys)
18
+ return { networkACLKeys: null };
19
+ if (Array.isArray(networkACLKeys) && networkACLKeys.length === 0) {
20
+ logger_1.default.info('No network ACL keys available, skipping dump');
21
+ return { networkACLKeys: null };
22
+ }
23
+ // value is write-only — never returned by the API and must not be exported.
24
+ // created_at and updated_at are API-generated metadata; not needed in config.
25
+ const removeKeysFromOutput = ['value', 'created_at', 'updated_at'];
26
+ networkACLKeys = networkACLKeys.map((key) => {
27
+ const out = { ...key };
28
+ removeKeysFromOutput.forEach((k) => {
29
+ if (k in out)
30
+ delete out[k];
31
+ });
32
+ return out;
33
+ });
34
+ return {
35
+ networkACLKeys,
36
+ };
37
+ }
38
+ const networkACLKeysHandler = {
39
+ parse,
40
+ dump,
41
+ };
42
+ exports.default = networkACLKeysHandler;
@@ -18,8 +18,10 @@ const loadScreenRenderers = (context, screenRenderArray) => {
18
18
  const screens = promptEntry[prompt];
19
19
  Object.entries(screens).forEach(([, fileName]) => {
20
20
  const filePath = fileName;
21
+ const configRoot = path_1.default.resolve(context.basePath);
22
+ const rendererFile = path_1.default.resolve(context.basePath, filePath);
23
+ (0, utils_1.assertInsideConfigRoot)(filePath, rendererFile, configRoot);
21
24
  try {
22
- const rendererFile = path_1.default.join(context.basePath, filePath);
23
25
  const rendererData = (0, utils_1.loadJSON)(rendererFile, {
24
26
  mappings: context.mappings,
25
27
  disableKeywordReplacement: context.disableKeywordReplacement,
@@ -0,0 +1,6 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { RateLimitPolicy } from '../../../tools/auth0/handlers/rateLimitPolicies';
4
+ type ParsedRateLimitPolicies = ParsedAsset<'rateLimitPolicies', RateLimitPolicy[]>;
5
+ declare const rateLimitPoliciesHandler: YAMLHandler<ParsedRateLimitPolicies>;
6
+ export default rateLimitPoliciesHandler;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parse(context) {
4
+ const { rateLimitPolicies } = context.assets;
5
+ if (!rateLimitPolicies)
6
+ return { rateLimitPolicies: null };
7
+ return { rateLimitPolicies };
8
+ }
9
+ async function dump(context) {
10
+ const { rateLimitPolicies } = context.assets;
11
+ if (!rateLimitPolicies)
12
+ return { rateLimitPolicies: null };
13
+ const removeKeysFromOutput = ['id', 'created_at', 'updated_at'];
14
+ const cleaned = rateLimitPolicies.map((policy) => {
15
+ const policyToWrite = { ...policy };
16
+ removeKeysFromOutput.forEach((key) => {
17
+ delete policyToWrite[key];
18
+ });
19
+ return policyToWrite;
20
+ });
21
+ return { rateLimitPolicies: cleaned };
22
+ }
23
+ const rateLimitPoliciesHandler = {
24
+ parse,
25
+ dump,
26
+ };
27
+ exports.default = rateLimitPoliciesHandler;
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const fs_extra_1 = __importDefault(require("fs-extra"));
7
7
  const js_yaml_1 = __importDefault(require("js-yaml"));
8
8
  const path_1 = __importDefault(require("path"));
9
+ const lodash_1 = require("lodash");
9
10
  const tools_1 = require("../../tools");
10
11
  const client_1 = __importDefault(require("../../tools/auth0/client"));
11
12
  const logger_1 = __importDefault(require("../../logger"));
@@ -14,6 +15,83 @@ const handlers_1 = __importDefault(require("./handlers"));
14
15
  const readonly_1 = __importDefault(require("../../readonly"));
15
16
  const __1 = require("..");
16
17
  const keywordPreservation_1 = require("../../keywordPreservation");
18
+ // Symbol marker so a literal `__include` key in user YAML isn't read as a directive
19
+ const INCLUDE = Symbol('include');
20
+ // Custom YAML type for file includes
21
+ const includeType = new js_yaml_1.default.Type('!include', {
22
+ kind: 'scalar',
23
+ resolve: (data) => typeof data === 'string',
24
+ construct: (data) => {
25
+ // This will be handled during the actual loading process
26
+ return { [INCLUDE]: data };
27
+ },
28
+ });
29
+ const schema = js_yaml_1.default.DEFAULT_SCHEMA.extend([includeType]);
30
+ function prepareYamlContent(content, mappings, disableKeywordReplacement) {
31
+ return disableKeywordReplacement
32
+ ? (0, tools_1.wrapArrayReplaceMarkersInQuotes)(content, mappings)
33
+ : (0, tools_1.keywordReplace)(content, mappings);
34
+ }
35
+ function parseYaml(content) {
36
+ return js_yaml_1.default.load(content, { schema });
37
+ }
38
+ // Resolves !include directives. Keyword handling is applied by the caller before parse.
39
+ // configRoot is threaded unchanged so chained `../` includes can't escape it.
40
+ function resolveIncludes(obj, basePath, configRoot, loadIncludedYaml, visitedFiles = new Set()) {
41
+ if (Array.isArray(obj)) {
42
+ return obj.map((item) => resolveIncludes(item, basePath, configRoot, loadIncludedYaml, visitedFiles));
43
+ }
44
+ if (obj && typeof obj === 'object') {
45
+ const includePath = obj[INCLUDE];
46
+ if (includePath !== undefined) {
47
+ const filePath = path_1.default.resolve(basePath, includePath);
48
+ (0, utils_1.assertInsideConfigRoot)(includePath, filePath, configRoot);
49
+ if (visitedFiles.has(filePath)) {
50
+ throw new Error(`Circular include detected: ${filePath}`);
51
+ }
52
+ let stat;
53
+ try {
54
+ stat = fs_extra_1.default.statSync(filePath);
55
+ }
56
+ catch (err) {
57
+ if (err.code === 'ENOENT') {
58
+ throw new Error(`Include file not found: ${filePath}`);
59
+ }
60
+ throw err;
61
+ }
62
+ if (stat.isDirectory()) {
63
+ throw new Error(`Include path is a directory, expected a file: ${filePath}`);
64
+ }
65
+ // visitedFiles backtracks (add before, delete after), so one shared set is enough
66
+ visitedFiles.add(filePath);
67
+ const result = resolveIncludes(loadIncludedYaml(filePath), path_1.default.dirname(filePath), configRoot, loadIncludedYaml, visitedFiles);
68
+ visitedFiles.delete(filePath);
69
+ return result;
70
+ }
71
+ // Only rebuild plain objects; pass others (e.g. a Date from a YAML timestamp) through untouched
72
+ if (!(0, lodash_1.isPlainObject)(obj)) {
73
+ return obj;
74
+ }
75
+ const result = {};
76
+ for (const [key, value] of Object.entries(obj)) {
77
+ const resolved = resolveIncludes(value, basePath, configRoot, loadIncludedYaml, visitedFiles);
78
+ // Define `__proto__` as an own property so an included file can't pollute the prototype
79
+ if (key === '__proto__') {
80
+ Object.defineProperty(result, key, {
81
+ value: resolved,
82
+ enumerable: true,
83
+ writable: true,
84
+ configurable: true,
85
+ });
86
+ }
87
+ else {
88
+ result[key] = resolved;
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+ return obj;
94
+ }
17
95
  class YAMLContext {
18
96
  constructor(config, mgmtClient) {
19
97
  this.configFile = config.AUTH0_INPUT_FILE;
@@ -45,10 +123,7 @@ class YAMLContext {
45
123
  loadFile(f) {
46
124
  const configRoot = path_1.default.resolve(this.basePath);
47
125
  const toLoad = path_1.default.resolve(this.basePath, f.replace(/\\/g, '/'));
48
- if (!toLoad.startsWith(configRoot + path_1.default.sep)) {
49
- throw new Error(`Path "${f}" resolves to "${toLoad}" which is outside the config directory "${configRoot}". ` +
50
- `Move the file inside your config directory.`);
51
- }
126
+ (0, utils_1.assertInsideConfigRoot)(f, toLoad, configRoot);
52
127
  return (0, tools_1.loadFileAndReplaceKeywords)(toLoad, {
53
128
  mappings: this.mappings,
54
129
  disableKeywordReplacement: this.disableKeywordReplacement,
@@ -64,9 +139,12 @@ class YAMLContext {
64
139
  try {
65
140
  const fPath = path_1.default.resolve(this.configFile);
66
141
  logger_1.default.debug(`Loading YAML from ${fPath}`);
67
- Object.assign(this.assets, js_yaml_1.default.load(opts.disableKeywordReplacement
68
- ? (0, tools_1.wrapArrayReplaceMarkersInQuotes)(fs_extra_1.default.readFileSync(fPath, 'utf8'), this.mappings)
69
- : (0, tools_1.keywordReplace)(fs_extra_1.default.readFileSync(fPath, 'utf8'), this.mappings)) || {});
142
+ const prepareContent = (content) => prepareYamlContent(content, this.mappings, opts.disableKeywordReplacement);
143
+ const loadIncludedYaml = (filePath) => parseYaml(prepareContent(fs_extra_1.default.readFileSync(filePath, 'utf8')));
144
+ const parsed = parseYaml(prepareContent(fs_extra_1.default.readFileSync(fPath, 'utf8')));
145
+ // Bound includes by the same config root loadFile() enforces
146
+ const configRoot = path_1.default.resolve(this.basePath);
147
+ Object.assign(this.assets, resolveIncludes(parsed, path_1.default.dirname(fPath), configRoot, loadIncludedYaml) || {});
70
148
  }
71
149
  catch (err) {
72
150
  logger_1.default.debug(err.stack);
@@ -10,6 +10,6 @@ export declare const preserveKeywords: ({ localAssets, remoteAssets, keywordMapp
10
10
  remoteAssets: object;
11
11
  keywordMappings: KeywordMappings;
12
12
  auth0Handlers: (Pick<APIHandler, "id" | "type"> & {
13
- identifiers: (string | string[])[];
13
+ identifiers?: (string | string[])[];
14
14
  })[];
15
15
  }) => object;
@@ -164,7 +164,8 @@ const preserveKeywords = ({ localAssets, remoteAssets, keywordMappings, auth0Han
164
164
  if (Object.keys(keywordMappings).length === 0)
165
165
  return remoteAssets;
166
166
  const resourceSpecificIdentifiers = auth0Handlers.reduce((acc, handler) => {
167
- acc[handler.type] = handler.identifiers.flat();
167
+ // Standalone handlers (e.g. clientAuthCredentials) don't extend APIHandler and have no identifiers.
168
+ acc[handler.type] = (handler.identifiers ?? []).flat();
168
169
  return acc;
169
170
  }, {});
170
171
  const addresses = (0, exports.getPreservableFieldsFromAssets)(localAssets, keywordMappings, resourceSpecificIdentifiers, '');
package/lib/readonly.js CHANGED
@@ -28,6 +28,11 @@ const readOnlyFields = {
28
28
  'config_route',
29
29
  'owners',
30
30
  ],
31
+ attackProtection: [
32
+ // Returned by GET but rejected by PATCH with "Additional properties not allowed"
33
+ 'bruteForceProtection.form_submission_mode',
34
+ 'bruteForceProtection.form_submission_behavior',
35
+ ],
31
36
  };
32
37
  function getExcludedFields(config) {
33
38
  const strippedFields = { ...readOnlyFields };
@@ -165,6 +165,17 @@ export declare const schema: {
165
165
  suspiciousIpThrottling: {
166
166
  type: string;
167
167
  };
168
+ phoneProviderProtection: {
169
+ type: string;
170
+ properties: {
171
+ type: {
172
+ type: string;
173
+ enum: string[];
174
+ description: string;
175
+ };
176
+ };
177
+ required: string[];
178
+ };
168
179
  };
169
180
  additionalProperties: boolean;
170
181
  };
@@ -174,6 +185,7 @@ export type AttackProtection = {
174
185
  bruteForceProtection: Asset;
175
186
  captcha?: Asset | null;
176
187
  suspiciousIpThrottling: Asset;
188
+ phoneProviderProtection?: Asset | null;
177
189
  };
178
190
  export default class AttackProtectionHandler extends DefaultAPIHandler {
179
191
  existing: AttackProtection | null;
@@ -180,6 +180,17 @@ exports.schema = {
180
180
  suspiciousIpThrottling: {
181
181
  type: 'object',
182
182
  },
183
+ phoneProviderProtection: {
184
+ type: 'object',
185
+ properties: {
186
+ type: {
187
+ type: 'string',
188
+ enum: ['exponential', 'default'],
189
+ description: 'The backoff strategy applied to Send SMS during MFA enrollment. Gated by the sms_exponential_backoff feature flag; when the flag is disabled the API returns 403 and this setting is skipped on export.',
190
+ },
191
+ },
192
+ required: ['type'],
193
+ },
183
194
  },
184
195
  additionalProperties: false,
185
196
  };
@@ -227,6 +238,11 @@ class AttackProtectionHandler extends default_1.default {
227
238
  enabled: item.suspiciousIpThrottling.enabled,
228
239
  };
229
240
  }
241
+ if (item.phoneProviderProtection?.type) {
242
+ obj['phone-provider-protection'] = {
243
+ type: item.phoneProviderProtection.type,
244
+ };
245
+ }
230
246
  return obj;
231
247
  })();
232
248
  return super.objString(objectString);
@@ -242,15 +258,38 @@ class AttackProtectionHandler extends default_1.default {
242
258
  ]);
243
259
  let botDetection = null;
244
260
  let captcha = null;
261
+ let phoneProviderProtection = null;
262
+ try {
263
+ botDetection = await this.client.attackProtection.botDetection.get();
264
+ }
265
+ catch (err) {
266
+ if (err.statusCode === 403) {
267
+ logger_1.default.warn("Bot detection is not available on this tenant's current plan. Skipping bot detection settings.");
268
+ }
269
+ else {
270
+ throw err;
271
+ }
272
+ }
245
273
  try {
246
- [botDetection, captcha] = await Promise.all([
247
- this.client.attackProtection.botDetection.get(),
248
- this.client.attackProtection.captcha.get(),
249
- ]);
274
+ captcha = await this.client.attackProtection.captcha.get();
250
275
  }
251
276
  catch (err) {
252
277
  if (err.statusCode === 403) {
253
- logger_1.default.warn('Bot Detection API are not enabled for this tenant. Please verify `scope` or contact Auth0 support to enable this feature.');
278
+ logger_1.default.warn("Captcha is not available on this tenant's current plan. Skipping captcha settings.");
279
+ }
280
+ else {
281
+ throw err;
282
+ }
283
+ }
284
+ try {
285
+ phoneProviderProtection = await this.client.attackProtection.phoneProviderProtection.get();
286
+ }
287
+ catch (err) {
288
+ if (err.statusCode === 403) {
289
+ logger_1.default.warn('Phone provider protection is not enabled for this tenant (sms_exponential_backoff feature flag). Skipping phone provider protection settings.');
290
+ }
291
+ else {
292
+ throw err;
254
293
  }
255
294
  }
256
295
  const attackProtection = {
@@ -264,6 +303,9 @@ class AttackProtectionHandler extends default_1.default {
264
303
  if (captcha) {
265
304
  attackProtection.captcha = captcha;
266
305
  }
306
+ if (phoneProviderProtection) {
307
+ attackProtection.phoneProviderProtection = phoneProviderProtection;
308
+ }
267
309
  this.existing = attackProtection;
268
310
  return this.existing;
269
311
  }
@@ -303,11 +345,29 @@ class AttackProtectionHandler extends default_1.default {
303
345
  updates.push(this.client.attackProtection.captcha.update(attackProtection.captcha));
304
346
  }
305
347
  if (attackProtection.bruteForceProtection) {
306
- updates.push(this.client.attackProtection.bruteForceProtection.update(attackProtection.bruteForceProtection));
348
+ // Strip fields returned by GET but rejected by PATCH
349
+ const { form_submission_mode, form_submission_behavior, ...bruteForcePayload } = attackProtection.bruteForceProtection;
350
+ updates.push(this.client.attackProtection.bruteForceProtection.update(bruteForcePayload));
307
351
  }
308
352
  if (attackProtection.suspiciousIpThrottling) {
309
353
  updates.push(this.client.attackProtection.suspiciousIpThrottling.update(attackProtection.suspiciousIpThrottling));
310
354
  }
355
+ // Phone provider protection uses PATCH (not update) and requires `type` on every request.
356
+ // Guard the 403 (sms_exponential_backoff flag off) per-promise so a flag-off tenant does
357
+ // not fail the whole attackProtection stage — mirrors the 403-skip in getType().
358
+ if (attackProtection.phoneProviderProtection?.type) {
359
+ updates.push(this.client.attackProtection.phoneProviderProtection
360
+ .patch({
361
+ type: attackProtection.phoneProviderProtection.type,
362
+ })
363
+ .catch((err) => {
364
+ if (err.statusCode === 403) {
365
+ logger_1.default.warn('Phone provider protection is not enabled for this tenant (sms_exponential_backoff feature flag). Skipping phone provider protection update.');
366
+ return;
367
+ }
368
+ throw err;
369
+ }));
370
+ }
311
371
  if (!updates.length) {
312
372
  return;
313
373
  }
@@ -0,0 +1,27 @@
1
+ import { Assets, Auth0APIClient, CalculatedChanges } from '../../../types';
2
+ import { ConfigFunction } from '../../../configFactory';
3
+ export declare const schema: {
4
+ type: string;
5
+ items: {
6
+ type: string;
7
+ };
8
+ };
9
+ export default class ClientAuthCredentialsHandler {
10
+ client: Auth0APIClient;
11
+ config: ConfigFunction;
12
+ type: string;
13
+ existing: null;
14
+ constructor({ client, config }: {
15
+ client: Auth0APIClient;
16
+ config: ConfigFunction;
17
+ });
18
+ getType(): Promise<null>;
19
+ load(): Promise<{
20
+ [x: string]: null;
21
+ }>;
22
+ validate(): Promise<null>;
23
+ dryRunChanges(_assets: Assets): Promise<CalculatedChanges>;
24
+ processChanges(assets: Assets): Promise<void>;
25
+ private inferCredentialType;
26
+ private inferMethodFromType;
27
+ }