auth0-deploy-cli 9.0.0-beta.1 → 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.
Files changed (126) hide show
  1. package/AGENTS.md +2 -357
  2. package/CHANGELOG.md +162 -6
  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 +8 -5
  8. package/lib/context/directory/handlers/actions.js +8 -4
  9. package/lib/context/directory/handlers/attackProtection.js +1 -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 +2 -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 +8 -1
  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 +8 -1
  32. package/lib/context/directory/index.js +4 -7
  33. package/lib/context/index.js +31 -31
  34. package/lib/context/yaml/handlers/attackProtection.js +1 -1
  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 +3 -5
  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.js +19 -6
  59. package/lib/tools/auth0/handlers/clientAuthCredentials.d.ts +27 -0
  60. package/lib/tools/auth0/handlers/clientAuthCredentials.js +234 -0
  61. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.d.ts +38 -0
  62. package/lib/tools/auth0/handlers/clientAuthCredentialsPre.js +123 -0
  63. package/lib/tools/auth0/handlers/clientGrants.d.ts +1 -1
  64. package/lib/tools/auth0/handlers/clients.d.ts +106 -0
  65. package/lib/tools/auth0/handlers/clients.js +206 -2
  66. package/lib/tools/auth0/handlers/connectionProfiles.d.ts +27 -0
  67. package/lib/tools/auth0/handlers/connectionProfiles.js +30 -0
  68. package/lib/tools/auth0/handlers/connections.d.ts +32 -6
  69. package/lib/tools/auth0/handlers/connections.js +49 -7
  70. package/lib/tools/auth0/handlers/databases.d.ts +28 -0
  71. package/lib/tools/auth0/handlers/databases.js +58 -24
  72. package/lib/tools/auth0/handlers/default.d.ts +23 -0
  73. package/lib/tools/auth0/handlers/default.js +47 -29
  74. package/lib/tools/auth0/handlers/eventStreams.js +10 -2
  75. package/lib/tools/auth0/handlers/guardianEmailFactorSettings.d.ts +22 -0
  76. package/lib/tools/auth0/handlers/guardianEmailFactorSettings.js +77 -0
  77. package/lib/tools/auth0/handlers/guardianFactorTemplates.js +13 -4
  78. package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +11 -9
  79. package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +11 -9
  80. package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.d.ts +22 -0
  81. package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.js +77 -0
  82. package/lib/tools/auth0/handlers/guardianPolicies.js +11 -1
  83. package/lib/tools/auth0/handlers/guardianSettings.d.ts +30 -0
  84. package/lib/tools/auth0/handlers/guardianSettings.js +85 -0
  85. package/lib/tools/auth0/handlers/hooks.js +1 -1
  86. package/lib/tools/auth0/handlers/index.js +16 -0
  87. package/lib/tools/auth0/handlers/networkACLKeys.d.ts +45 -0
  88. package/lib/tools/auth0/handlers/networkACLKeys.js +177 -0
  89. package/lib/tools/auth0/handlers/networkACLs.d.ts +132 -2
  90. package/lib/tools/auth0/handlers/networkACLs.js +100 -16
  91. package/lib/tools/auth0/handlers/organizations.d.ts +33 -1
  92. package/lib/tools/auth0/handlers/organizations.js +177 -19
  93. package/lib/tools/auth0/handlers/phoneProvider.js +10 -2
  94. package/lib/tools/auth0/handlers/phoneTemplates.d.ts +4 -1
  95. package/lib/tools/auth0/handlers/phoneTemplates.js +67 -10
  96. package/lib/tools/auth0/handlers/prompts.js +1 -1
  97. package/lib/tools/auth0/handlers/rateLimitPolicies.d.ts +81 -0
  98. package/lib/tools/auth0/handlers/rateLimitPolicies.js +203 -0
  99. package/lib/tools/auth0/handlers/resourceServers.d.ts +44 -0
  100. package/lib/tools/auth0/handlers/resourceServers.js +44 -0
  101. package/lib/tools/auth0/handlers/riskAssessment.d.ts +1 -1
  102. package/lib/tools/auth0/handlers/riskAssessment.js +19 -1
  103. package/lib/tools/auth0/handlers/roles.d.ts +4 -0
  104. package/lib/tools/auth0/handlers/roles.js +10 -0
  105. package/lib/tools/auth0/handlers/rules.js +19 -7
  106. package/lib/tools/auth0/handlers/tenant.d.ts +45 -0
  107. package/lib/tools/auth0/handlers/tenant.js +48 -0
  108. package/lib/tools/auth0/handlers/themes.d.ts +37 -1
  109. package/lib/tools/auth0/handlers/themes.js +64 -0
  110. package/lib/tools/auth0/handlers/tokenExchangeProfiles.js +3 -1
  111. package/lib/tools/auth0/index.js +12 -6
  112. package/lib/tools/calculateDryRunChanges.js +12 -8
  113. package/lib/tools/constants.d.ts +2 -0
  114. package/lib/tools/constants.js +3 -0
  115. package/lib/tools/utils.d.ts +3 -0
  116. package/lib/tools/utils.js +41 -2
  117. package/lib/types.d.ts +9 -1
  118. package/lib/utils.d.ts +6 -0
  119. package/lib/utils.js +17 -2
  120. package/package.json +2 -2
  121. package/references/code-style.md +133 -0
  122. package/references/commands.md +98 -0
  123. package/references/docs-update.md +34 -0
  124. package/references/git-workflow.md +135 -0
  125. package/references/pitfalls.md +62 -0
  126. package/references/testing.md +118 -0
@@ -34,6 +34,11 @@ function parse(context) {
34
34
  logger_1.default.warn(`Skipping email template file ${meta.body} as missing the corresponding '.json' file`);
35
35
  return [];
36
36
  }
37
+ if (meta.body !== undefined) {
38
+ const configRoot = path_1.default.resolve(context.filePath);
39
+ const resolvedTemplatePath = path_1.default.resolve(templateFilePath);
40
+ (0, utils_1.assertInsideConfigRoot)(meta.body, resolvedTemplatePath, configRoot);
41
+ }
37
42
  return {
38
43
  ...meta,
39
44
  body: (0, tools_1.loadFileAndReplaceKeywords)(templateFilePath, {
@@ -0,0 +1,5 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianEmailFactorSettings = ParsedAsset<'guardianEmailFactorSettings', Asset>;
4
+ declare const guardianEmailFactorSettingsHandler: DirectoryHandler<ParsedGuardianEmailFactorSettings>;
5
+ export default guardianEmailFactorSettingsHandler;
@@ -0,0 +1,38 @@
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 path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ function parse(context) {
11
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
12
+ if (!(0, utils_1.existsMustBeDir)(guardianFolder))
13
+ return { guardianEmailFactorSettings: null }; // Skip
14
+ const file = path_1.default.join(guardianFolder, 'emailFactorSettings.json');
15
+ if (!(0, utils_1.isFile)(file)) {
16
+ return { guardianEmailFactorSettings: null };
17
+ }
18
+ return {
19
+ guardianEmailFactorSettings: (0, utils_1.loadJSON)(file, {
20
+ mappings: context.mappings,
21
+ disableKeywordReplacement: context.disableKeywordReplacement,
22
+ }),
23
+ };
24
+ }
25
+ async function dump(context) {
26
+ const { guardianEmailFactorSettings } = context.assets;
27
+ if (!guardianEmailFactorSettings)
28
+ return; // Skip, nothing to dump
29
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
30
+ fs_extra_1.default.ensureDirSync(guardianFolder);
31
+ const file = path_1.default.join(guardianFolder, 'emailFactorSettings.json');
32
+ (0, utils_1.dumpJSON)(file, guardianEmailFactorSettings);
33
+ }
34
+ const guardianEmailFactorSettingsHandler = {
35
+ parse,
36
+ dump,
37
+ };
38
+ exports.default = guardianEmailFactorSettingsHandler;
@@ -0,0 +1,5 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianPhoneFactorSettings = ParsedAsset<'guardianPhoneFactorSettings', Asset>;
4
+ declare const guardianPhoneFactorSettingsHandler: DirectoryHandler<ParsedGuardianPhoneFactorSettings>;
5
+ export default guardianPhoneFactorSettingsHandler;
@@ -0,0 +1,38 @@
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 path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ function parse(context) {
11
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
12
+ if (!(0, utils_1.existsMustBeDir)(guardianFolder))
13
+ return { guardianPhoneFactorSettings: null }; // Skip
14
+ const file = path_1.default.join(guardianFolder, 'phoneFactorSettings.json');
15
+ if (!(0, utils_1.isFile)(file)) {
16
+ return { guardianPhoneFactorSettings: null };
17
+ }
18
+ return {
19
+ guardianPhoneFactorSettings: (0, utils_1.loadJSON)(file, {
20
+ mappings: context.mappings,
21
+ disableKeywordReplacement: context.disableKeywordReplacement,
22
+ }),
23
+ };
24
+ }
25
+ async function dump(context) {
26
+ const { guardianPhoneFactorSettings } = context.assets;
27
+ if (!guardianPhoneFactorSettings)
28
+ return; // Skip, nothing to dump
29
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
30
+ fs_extra_1.default.ensureDirSync(guardianFolder);
31
+ const file = path_1.default.join(guardianFolder, 'phoneFactorSettings.json');
32
+ (0, utils_1.dumpJSON)(file, guardianPhoneFactorSettings);
33
+ }
34
+ const guardianPhoneFactorSettingsHandler = {
35
+ parse,
36
+ dump,
37
+ };
38
+ exports.default = guardianPhoneFactorSettingsHandler;
@@ -0,0 +1,5 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianSettings = ParsedAsset<'guardianSettings', Asset>;
4
+ declare const guardianSettingsHandler: DirectoryHandler<ParsedGuardianSettings>;
5
+ export default guardianSettingsHandler;
@@ -0,0 +1,38 @@
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 path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ function parse(context) {
11
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
12
+ if (!(0, utils_1.existsMustBeDir)(guardianFolder))
13
+ return { guardianSettings: null }; // Skip
14
+ const file = path_1.default.join(guardianFolder, 'settings.json');
15
+ if (!(0, utils_1.isFile)(file)) {
16
+ return { guardianSettings: null };
17
+ }
18
+ return {
19
+ guardianSettings: (0, utils_1.loadJSON)(file, {
20
+ mappings: context.mappings,
21
+ disableKeywordReplacement: context.disableKeywordReplacement,
22
+ }),
23
+ };
24
+ }
25
+ async function dump(context) {
26
+ const { guardianSettings } = context.assets;
27
+ if (!guardianSettings)
28
+ return; // Skip, nothing to dump
29
+ const guardianFolder = path_1.default.join(context.filePath, tools_1.constants.GUARDIAN_DIRECTORY);
30
+ fs_extra_1.default.ensureDirSync(guardianFolder);
31
+ const file = path_1.default.join(guardianFolder, 'settings.json');
32
+ (0, utils_1.dumpJSON)(file, guardianSettings);
33
+ }
34
+ const guardianSettingsHandler = {
35
+ parse,
36
+ dump,
37
+ };
38
+ exports.default = guardianSettingsHandler;
@@ -21,7 +21,14 @@ function parse(context) {
21
21
  }),
22
22
  };
23
23
  if (hook.script) {
24
- hook.script = context.loadFile(hook.script, tools_1.constants.HOOKS_DIRECTORY);
24
+ const normalizedScript = hook.script.replace(/\\/g, '/');
25
+ const configRoot = path_1.default.resolve(context.filePath);
26
+ const resolvedPath = path_1.default.resolve(context.filePath, tools_1.constants.HOOKS_DIRECTORY, normalizedScript);
27
+ (0, utils_1.assertInsideConfigRoot)(hook.script, resolvedPath, configRoot);
28
+ hook.script = (0, tools_1.loadFileAndReplaceKeywords)(resolvedPath, {
29
+ mappings: context.mappings,
30
+ disableKeywordReplacement: context.disableKeywordReplacement,
31
+ });
25
32
  }
26
33
  hook.name = hook.name.toLowerCase().replace(/\s/g, '-');
27
34
  return hook;
@@ -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 actions_1 = __importDefault(require("./actions"));
@@ -38,12 +41,15 @@ const rulesConfigs_1 = __importDefault(require("./rulesConfigs"));
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 directoryHandlers = {
49
55
  rules: rules_1.default,
@@ -63,6 +69,9 @@ const directoryHandlers = {
63
69
  guardianFactorTemplates: guardianFactorTemplates_1.default,
64
70
  guardianPhoneFactorMessageTypes: guardianPhoneFactorMessageTypes_1.default,
65
71
  guardianPhoneFactorSelectedProvider: guardianPhoneFactorSelectedProvider_1.default,
72
+ guardianPhoneFactorSettings: guardianPhoneFactorSettings_1.default,
73
+ guardianEmailFactorSettings: guardianEmailFactorSettings_1.default,
74
+ guardianSettings: guardianSettings_1.default,
66
75
  guardianPolicies: guardianPolicies_1.default,
67
76
  roles: roles_1.default,
68
77
  actions: actions_1.default,
@@ -82,11 +91,14 @@ const directoryHandlers = {
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 = directoryHandlers;
@@ -0,0 +1,6 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { NetworkAclKey } from '../../../tools/auth0/handlers/networkACLKeys';
4
+ type ParsedNetworkACLKeys = ParsedAsset<'networkACLKeys', NetworkAclKey[]>;
5
+ declare const networkACLKeysHandler: DirectoryHandler<ParsedNetworkACLKeys>;
6
+ export default networkACLKeysHandler;
@@ -0,0 +1,54 @@
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 path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ const logger_1 = __importDefault(require("../../../logger"));
11
+ function parse(context) {
12
+ const networkACLKeysDirectory = path_1.default.join(context.filePath, tools_1.constants.NETWORK_ACL_KEYS_DIRECTORY);
13
+ if (!(0, utils_1.existsMustBeDir)(networkACLKeysDirectory))
14
+ return { networkACLKeys: null }; // Skip
15
+ const foundFiles = (0, utils_1.getFiles)(networkACLKeysDirectory, ['.json']);
16
+ const networkACLKeys = foundFiles
17
+ .map((f) => (0, utils_1.loadJSON)(f, {
18
+ mappings: context.mappings,
19
+ disableKeywordReplacement: context.disableKeywordReplacement,
20
+ }))
21
+ .filter((p) => Object.keys(p).length > 0); // Filter out empty configs
22
+ return {
23
+ networkACLKeys,
24
+ };
25
+ }
26
+ async function dump(context) {
27
+ const { networkACLKeys } = context.assets;
28
+ if (!networkACLKeys)
29
+ return; // Skip, nothing to dump
30
+ if (Array.isArray(networkACLKeys) && networkACLKeys.length === 0) {
31
+ logger_1.default.info('No network ACL keys available, skipping dump');
32
+ return;
33
+ }
34
+ const networkACLKeysDirectory = path_1.default.join(context.filePath, tools_1.constants.NETWORK_ACL_KEYS_DIRECTORY);
35
+ fs_extra_1.default.ensureDirSync(networkACLKeysDirectory);
36
+ // value is write-only — never returned by the API and must not be exported.
37
+ // created_at and updated_at are API-generated metadata; not needed in config.
38
+ const removeKeysFromOutput = ['value', 'created_at', 'updated_at'];
39
+ networkACLKeys.forEach((networkACLKey) => {
40
+ const out = { ...networkACLKey };
41
+ removeKeysFromOutput.forEach((key) => {
42
+ if (key in out)
43
+ delete out[key];
44
+ });
45
+ const fileName = (0, utils_1.sanitize)(networkACLKey.name);
46
+ const filePath = path_1.default.join(networkACLKeysDirectory, `${fileName}.json`);
47
+ (0, utils_1.dumpJSON)(filePath, out);
48
+ });
49
+ }
50
+ const networkACLKeysHandler = {
51
+ parse,
52
+ dump,
53
+ };
54
+ exports.default = networkACLKeysHandler;
@@ -46,9 +46,13 @@ function parse(context) {
46
46
  const screensObject = screensArray[0];
47
47
  acc[promptName] = Object.entries(screensObject).reduce((screenAcc, [screenName, items]) => {
48
48
  screenAcc[screenName] = items.reduce((insertionAcc, { name, template }) => {
49
- const templateFilePath = path_1.default.join(promptsDirectory, template);
50
- insertionAcc[name] = (0, utils_1.isFile)(templateFilePath)
51
- ? (0, tools_1.loadFileAndReplaceKeywords)(templateFilePath, {
49
+ const configRoot = path_1.default.resolve(context.filePath);
50
+ const resolvedTemplatePath = path_1.default.resolve(promptsDirectory, template);
51
+ if ((0, utils_1.isFile)(resolvedTemplatePath)) {
52
+ (0, utils_1.assertInsideConfigRoot)(template, resolvedTemplatePath, configRoot);
53
+ }
54
+ insertionAcc[name] = (0, utils_1.isFile)(resolvedTemplatePath)
55
+ ? (0, tools_1.loadFileAndReplaceKeywords)(resolvedTemplatePath, {
52
56
  mappings: context.mappings,
53
57
  disableKeywordReplacement: context.disableKeywordReplacement,
54
58
  }).trim()
@@ -0,0 +1,6 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { RateLimitPolicy } from '../../../tools/auth0/handlers/rateLimitPolicies';
4
+ type ParsedRateLimitPolicies = ParsedAsset<'rateLimitPolicies', RateLimitPolicy[]>;
5
+ declare const rateLimitPoliciesHandler: DirectoryHandler<ParsedRateLimitPolicies>;
6
+ export default rateLimitPoliciesHandler;
@@ -0,0 +1,53 @@
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 path_1 = __importDefault(require("path"));
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const tools_1 = require("../../../tools");
9
+ const utils_1 = require("../../../utils");
10
+ function parse(context) {
11
+ const rateLimitPoliciesDirectory = path_1.default.join(context.filePath, tools_1.constants.RATE_LIMIT_POLICIES_DIRECTORY);
12
+ if (!(0, utils_1.existsMustBeDir)(rateLimitPoliciesDirectory))
13
+ return { rateLimitPolicies: null }; // Skip
14
+ const foundFiles = (0, utils_1.getFiles)(rateLimitPoliciesDirectory, ['.json']);
15
+ const rateLimitPolicies = foundFiles
16
+ .map((f) => (0, utils_1.loadJSON)(f, {
17
+ mappings: context.mappings,
18
+ disableKeywordReplacement: context.disableKeywordReplacement,
19
+ }))
20
+ .filter((p) => Object.keys(p).length > 0);
21
+ return { rateLimitPolicies };
22
+ }
23
+ async function dump(context) {
24
+ const { rateLimitPolicies } = context.assets;
25
+ if (!rateLimitPolicies)
26
+ return; // Skip, nothing to dump
27
+ const rateLimitPoliciesDirectory = path_1.default.join(context.filePath, tools_1.constants.RATE_LIMIT_POLICIES_DIRECTORY);
28
+ fs_extra_1.default.ensureDirSync(rateLimitPoliciesDirectory);
29
+ const removeKeysFromOutput = ['id', 'created_at', 'updated_at'];
30
+ const expectedFiles = new Set();
31
+ rateLimitPolicies.forEach((policy) => {
32
+ const policyToWrite = { ...policy };
33
+ removeKeysFromOutput.forEach((key) => {
34
+ delete policyToWrite[key];
35
+ });
36
+ const fileName = (0, utils_1.sanitize)(policy.consumer_selector);
37
+ const filePath = path_1.default.join(rateLimitPoliciesDirectory, `${fileName}.json`);
38
+ expectedFiles.add(`${fileName}.json`);
39
+ (0, utils_1.dumpJSON)(filePath, policyToWrite);
40
+ });
41
+ // Remove files for policies that no longer exist in the tenant
42
+ for (const existing of fs_extra_1.default.readdirSync(rateLimitPoliciesDirectory)) {
43
+ const fullPath = path_1.default.join(rateLimitPoliciesDirectory, existing);
44
+ if (fs_extra_1.default.statSync(fullPath).isFile() && !expectedFiles.has(existing)) {
45
+ fs_extra_1.default.removeSync(fullPath);
46
+ }
47
+ }
48
+ }
49
+ const rateLimitPoliciesHandler = {
50
+ parse,
51
+ dump,
52
+ };
53
+ exports.default = rateLimitPoliciesHandler;
@@ -21,7 +21,14 @@ function parse(context) {
21
21
  }),
22
22
  };
23
23
  if (rule.script) {
24
- rule.script = context.loadFile(rule.script, tools_1.constants.RULES_DIRECTORY);
24
+ const normalizedScript = rule.script.replace(/\\/g, '/');
25
+ const configRoot = path_1.default.resolve(context.filePath);
26
+ const resolvedPath = path_1.default.resolve(context.filePath, tools_1.constants.RULES_DIRECTORY, normalizedScript);
27
+ (0, utils_1.assertInsideConfigRoot)(rule.script, resolvedPath, configRoot);
28
+ rule.script = (0, tools_1.loadFileAndReplaceKeywords)(resolvedPath, {
29
+ mappings: context.mappings,
30
+ disableKeywordReplacement: context.disableKeywordReplacement,
31
+ });
25
32
  }
26
33
  return rule;
27
34
  });
@@ -68,13 +68,10 @@ class DirectoryContext {
68
68
  };
69
69
  }
70
70
  loadFile(f, folder) {
71
- const resolvedBase = path.resolve(this.filePath);
72
- const inSubfolder = path.resolve(this.filePath, folder, f);
73
- const inRoot = path.resolve(this.filePath, f);
74
- const toLoad = (0, utils_1.isFile)(inSubfolder) ? inSubfolder : inRoot;
75
- if (!toLoad.startsWith(resolvedBase + path.sep)) {
76
- throw new Error(`File reference "${f}" must be relative to the config directory. Absolute paths and paths outside the config root are not supported.`);
77
- }
71
+ const configRoot = path.resolve(this.filePath);
72
+ const basePath = path.resolve(this.filePath, folder);
73
+ const toLoad = path.resolve(basePath, f.replace(/\\/g, '/'));
74
+ (0, utils_1.assertInsideConfigRoot)(f, toLoad, configRoot);
78
75
  return (0, tools_1.loadFileAndReplaceKeywords)(toLoad, {
79
76
  mappings: this.mappings,
80
77
  disableKeywordReplacement: this.disableKeywordReplacement,
@@ -118,44 +118,44 @@ const setupContext = async (config, command) => {
118
118
  logger_1.default.info('To enable experimental early access features use --experimental_ea flag or set AUTH0_EXPERIMENTAL_EA=true in configuration JSON.');
119
119
  }
120
120
  })(config);
121
- const accessToken = await (async () => {
122
- const { AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_ACCESS_TOKEN, AUTH0_CLIENT_SECRET, AUTH0_CLIENT_SIGNING_KEY_PATH, AUTH0_CLIENT_SIGNING_ALGORITHM, } = config;
121
+ const { AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_ACCESS_TOKEN, AUTH0_CLIENT_SECRET, AUTH0_CLIENT_SIGNING_KEY_PATH, AUTH0_CLIENT_SIGNING_ALGORITHM, } = config;
122
+ if (!AUTH0_ACCESS_TOKEN && !AUTH0_CLIENT_SECRET && !AUTH0_CLIENT_SIGNING_KEY_PATH) {
123
+ throw new Error('need to supply either `AUTH0_ACCESS_TOKEN`, `AUTH0_CLIENT_SECRET` or `AUTH0_CLIENT_SIGNING_KEY_PATH`');
124
+ }
125
+ // node-auth0 v7 removed the AuthenticationClient. `createManagementAuth`
126
+ // performs the client-credentials grant on our behalf and caches/refreshes
127
+ // the resulting token. We resolve a token supplier here so the
128
+ // ManagementClient auto-refreshes during long-running operations, and eagerly
129
+ // call it once below to preserve the previous fail-fast behaviour (a bad
130
+ // secret/signing key surfaces at startup, not mid-operation).
131
+ const tokenSupplier = await (async () => {
123
132
  if (!!AUTH0_ACCESS_TOKEN)
124
133
  return AUTH0_ACCESS_TOKEN;
125
- if (!AUTH0_CLIENT_SECRET && !AUTH0_CLIENT_SIGNING_KEY_PATH) {
126
- throw new Error('need to supply either `AUTH0_ACCESS_TOKEN`, `AUTH0_CLIENT_SECRET` or `AUTH0_CLIENT_SIGNING_KEY_PATH`');
127
- }
128
- const authClient = (() => {
129
- if (!!AUTH0_CLIENT_SECRET) {
130
- return new auth0_1.AuthenticationClient({
131
- domain: AUTH0_DOMAIN,
132
- clientId: AUTH0_CLIENT_ID,
133
- clientSecret: AUTH0_CLIENT_SECRET,
134
- });
134
+ const audience = config.AUTH0_AUDIENCE
135
+ ? config.AUTH0_AUDIENCE
136
+ : `https://${AUTH0_DOMAIN}/api/v2/`;
137
+ const credentials = !!AUTH0_CLIENT_SECRET
138
+ ? {
139
+ clientId: AUTH0_CLIENT_ID,
140
+ clientSecret: AUTH0_CLIENT_SECRET,
141
+ audience,
135
142
  }
136
- return new auth0_1.AuthenticationClient({
137
- domain: AUTH0_DOMAIN,
143
+ : {
138
144
  clientId: AUTH0_CLIENT_ID,
139
145
  clientAssertionSigningKey: (0, fs_1.readFileSync)(AUTH0_CLIENT_SIGNING_KEY_PATH, 'utf8'),
140
- clientAssertionSigningAlg: !!AUTH0_CLIENT_SIGNING_ALGORITHM
141
- ? AUTH0_CLIENT_SIGNING_ALGORITHM
142
- : undefined,
143
- });
144
- })();
145
- const clientCredentials = await authClient.oauth.clientCredentialsGrant({
146
- audience: config.AUTH0_AUDIENCE
147
- ? config.AUTH0_AUDIENCE
148
- : `https://${config.AUTH0_DOMAIN}/api/v2/`,
149
- });
150
- const clientAccessToken = clientCredentials.data?.access_token;
151
- if (!clientAccessToken) {
152
- throw new Error('Failed to retrieve access token.');
153
- }
154
- return clientAccessToken;
146
+ ...(!!AUTH0_CLIENT_SIGNING_ALGORITHM
147
+ ? { clientAssertionSigningAlg: AUTH0_CLIENT_SIGNING_ALGORITHM }
148
+ : {}),
149
+ audience,
150
+ };
151
+ const auth = (0, auth0_1.createManagementAuth)({ domain: AUTH0_DOMAIN, ...credentials });
152
+ // Fail fast: validates credentials (and the signing key) up-front.
153
+ await auth.getToken();
154
+ return () => auth.getToken();
155
155
  })();
156
156
  const mgmtClient = new auth0_1.ManagementClient({
157
- domain: config.AUTH0_DOMAIN,
158
- token: accessToken,
157
+ domain: AUTH0_DOMAIN,
158
+ token: tokenSupplier,
159
159
  headers: {
160
160
  'User-agent': `deploy-cli/${packageVersion} (node.js/${process.version.replace('v', '')})`,
161
161
  ...((0, utils_1.isTruthy)(config.AUTH0_DRY_RUN)
@@ -27,7 +27,7 @@ async function dump(context) {
27
27
  }
28
28
  const maskedAttackProtection = (0, defaults_1.attackProtectionDefaults)(attackProtectionConfig, context.config);
29
29
  return {
30
- attackProtection: maskedAttackProtection,
30
+ attackProtection: (0, defaults_1.sortAttackProtectionArrays)(maskedAttackProtection),
31
31
  };
32
32
  }
33
33
  const attackProtectionHandler = {
@@ -18,9 +18,12 @@ async function parse(context) {
18
18
  const parsedTemplates = templates.map((templateDefinition) => {
19
19
  const normalizedPathArray = (0, utils_1.nomalizedYAMLPath)(templateDefinition.body);
20
20
  const markupFile = path_1.default.join(context.basePath, ...normalizedPathArray);
21
+ const configRoot = path_1.default.resolve(context.basePath);
22
+ const resolvedMarkupFile = path_1.default.resolve(markupFile);
23
+ (0, utils_1.assertInsideConfigRoot)(templateDefinition.body, resolvedMarkupFile, configRoot);
21
24
  return {
22
25
  template: templateDefinition.template,
23
- body: (0, tools_1.loadFileAndReplaceKeywords)(markupFile, {
26
+ body: (0, tools_1.loadFileAndReplaceKeywords)(resolvedMarkupFile, {
24
27
  mappings: context.mappings,
25
28
  disableKeywordReplacement: context.disableKeywordReplacement,
26
29
  }),
@@ -0,0 +1,5 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ type ParsedClientAuthCredentials = ParsedAsset<'clientAuthCredentials', null>;
4
+ declare const clientAuthCredentialsHandler: YAMLHandler<ParsedClientAuthCredentials>;
5
+ export default clientAuthCredentialsHandler;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parse(_context) {
4
+ return { clientAuthCredentials: null };
5
+ }
6
+ async function dump(_context) {
7
+ return { clientAuthCredentials: null };
8
+ }
9
+ const clientAuthCredentialsHandler = {
10
+ parse,
11
+ dump,
12
+ };
13
+ exports.default = clientAuthCredentialsHandler;
@@ -21,7 +21,10 @@ async function parse(context) {
21
21
  if (client.custom_login_page) {
22
22
  const htmlFileName = path_1.default.join(clientsFolder, client.custom_login_page);
23
23
  if ((0, utils_1.isFile)(htmlFileName)) {
24
- client.custom_login_page = context.loadFile(htmlFileName);
24
+ // Pass a path relative to basePath so context.loadFile() resolves it correctly.
25
+ // Passing htmlFileName (which already includes basePath) would cause double resolution
26
+ // when basePath is a relative path (e.g. when AUTH0_INPUT_FILE is a relative path).
27
+ client.custom_login_page = context.loadFile(path_1.default.join(tools_1.constants.CLIENTS_DIRECTORY, client.custom_login_page));
25
28
  }
26
29
  }
27
30
  return client;
@@ -99,6 +102,21 @@ async function dump(context) {
99
102
  organization_require_behavior: client.organization_require_behavior,
100
103
  };
101
104
  }
105
+ else {
106
+ // strip id-only credentials and remove client_authentication_methods entirely
107
+ // if no named credentials remain — an absent field is treated as deletion on deploy
108
+ if (client.client_authentication_methods) {
109
+ Object.values(client.client_authentication_methods).forEach((method) => {
110
+ if (method?.credentials) {
111
+ method.credentials = method.credentials.filter((c) => c.name);
112
+ }
113
+ });
114
+ const hasAnyCredentials = Object.values(client.client_authentication_methods).some((method) => method?.credentials?.length > 0);
115
+ if (!hasAnyCredentials) {
116
+ delete client.client_authentication_methods;
117
+ }
118
+ }
119
+ }
102
120
  return (0, utils_1.clearClientArrays)(client);
103
121
  }),
104
122
  ],
@@ -26,7 +26,9 @@ async function parse(context) {
26
26
  logger_1.default.error(missingTemplateErrorMessage);
27
27
  throw new Error(missingTemplateErrorMessage);
28
28
  }
29
- connection.options.email.body = context.loadFile(htmlFileName);
29
+ // Pass a path relative to basePath so context.loadFile() resolves it correctly.
30
+ // Passing htmlFileName (which already includes basePath) would cause double resolution.
31
+ connection.options.email.body = context.loadFile(path_1.default.join(tools_1.constants.CONNECTIONS_DIRECTORY, connection.options.email.body));
30
32
  }
31
33
  return connection;
32
34
  }),
@@ -43,6 +45,11 @@ async function dump(context) {
43
45
  if (excludedConnections.length) {
44
46
  connections = connections.filter((connection) => !excludedConnections.includes(connection.name));
45
47
  }
48
+ // Filter to included connections
49
+ const includedConnections = (context.assets.include && context.assets.include.connections) || [];
50
+ if (includedConnections.length) {
51
+ connections = connections.filter((connection) => includedConnections.includes(connection.name));
52
+ }
46
53
  return {
47
54
  connections: connections.map((connection) => {
48
55
  let dumpedConnection = {
@@ -14,6 +14,9 @@ async function parse(context) {
14
14
  return { flows: null };
15
15
  const parsedFlows = flows.map((flow) => {
16
16
  const flowFile = path_1.default.join(context.basePath, flow.body);
17
+ const configRoot = path_1.default.resolve(context.basePath);
18
+ const resolvedFlowFile = path_1.default.resolve(flowFile);
19
+ (0, utils_1.assertInsideConfigRoot)(flow.body, resolvedFlowFile, configRoot);
17
20
  const parsedFlowBody = (0, utils_1.loadJSON)(flowFile, {
18
21
  mappings: context.mappings,
19
22
  disableKeywordReplacement: context.disableKeywordReplacement,
@@ -14,6 +14,9 @@ async function parse(context) {
14
14
  return { forms: null };
15
15
  const parsedForms = forms.map((form) => {
16
16
  const formFile = path_1.default.join(context.basePath, form.body);
17
+ const configRoot = path_1.default.resolve(context.basePath);
18
+ const resolvedFormFile = path_1.default.resolve(formFile);
19
+ (0, utils_1.assertInsideConfigRoot)(form.body, resolvedFormFile, configRoot);
17
20
  const parsedFormBody = (0, utils_1.loadJSON)(formFile, {
18
21
  mappings: context.mappings,
19
22
  disableKeywordReplacement: context.disableKeywordReplacement,
@@ -0,0 +1,5 @@
1
+ import { YAMLHandler } from '.';
2
+ import { Asset, ParsedAsset } from '../../../types';
3
+ type ParsedGuardianEmailFactorSettings = ParsedAsset<'guardianEmailFactorSettings', Asset>;
4
+ declare const guardianEmailFactorSettingsHandler: YAMLHandler<ParsedGuardianEmailFactorSettings>;
5
+ export default guardianEmailFactorSettingsHandler;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ async function parseAndDump(context) {
4
+ const { guardianEmailFactorSettings } = context.assets;
5
+ if (!guardianEmailFactorSettings)
6
+ return { guardianEmailFactorSettings: null };
7
+ return {
8
+ guardianEmailFactorSettings,
9
+ };
10
+ }
11
+ const guardianEmailFactorSettingsHandler = {
12
+ parse: parseAndDump,
13
+ dump: parseAndDump,
14
+ };
15
+ exports.default = guardianEmailFactorSettingsHandler;
@@ -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;