auth0-deploy-cli 7.12.3 → 7.14.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 (38) hide show
  1. package/.circleci/config.yml +2 -0
  2. package/.github/dependabot.yml +3 -0
  3. package/CHANGELOG.md +37 -1
  4. package/README.md +121 -65
  5. package/docs/available-resource-config-formats.md +19 -0
  6. package/docs/configuring-the-deploy-cli.md +140 -0
  7. package/docs/excluding-from-management.md +81 -0
  8. package/docs/how-to-contribute.md +49 -0
  9. package/docs/keyword-replacement.md +45 -0
  10. package/docs/multi-environment-workflow.md +98 -0
  11. package/docs/terraform-provider.md +20 -0
  12. package/docs/using-as-cli.md +89 -0
  13. package/docs/using-as-node-module.md +114 -0
  14. package/lib/commands/import.d.ts +2 -0
  15. package/lib/commands/import.js +36 -1
  16. package/lib/context/directory/handlers/index.js +2 -0
  17. package/lib/context/directory/handlers/themes.d.ts +6 -0
  18. package/lib/context/directory/handlers/themes.js +48 -0
  19. package/lib/context/yaml/handlers/index.js +2 -0
  20. package/lib/context/yaml/handlers/pages.js +1 -1
  21. package/lib/context/yaml/handlers/themes.d.ts +6 -0
  22. package/lib/context/yaml/handlers/themes.js +26 -0
  23. package/lib/index.d.ts +1 -0
  24. package/lib/tools/auth0/handlers/index.d.ts +5 -0
  25. package/lib/tools/auth0/handlers/index.js +2 -0
  26. package/lib/tools/auth0/handlers/prompts.js +5 -2
  27. package/lib/tools/auth0/handlers/tenant.d.ts +12 -1
  28. package/lib/tools/auth0/handlers/tenant.js +39 -4
  29. package/lib/tools/auth0/handlers/themes.d.ts +455 -0
  30. package/lib/tools/auth0/handlers/themes.js +500 -0
  31. package/lib/tools/constants.d.ts +1 -0
  32. package/lib/tools/constants.js +1 -0
  33. package/lib/tools/index.d.ts +1 -0
  34. package/lib/tools/utils.d.ts +1 -1
  35. package/lib/tools/utils.js +2 -0
  36. package/lib/types.d.ts +15 -6
  37. package/lib/utils.d.ts +2 -1
  38. package/package.json +4 -4
@@ -0,0 +1,98 @@
1
+ # Incorporating Into Multi-environment Workflows
2
+
3
+ The Deploy CLI supports working within a multi-tenant, multi-environment context. When integrated into your CI/CD development workflows, can be used to propagate Auth0 changes from feature development all the way through production.
4
+
5
+ In general, the advised workflow is as follows:
6
+
7
+ - Create a separate Auth0 tenant for each environment (ex: dev, staging, prod)
8
+ - Create a single repository of resource configuration files for all environments
9
+ - Add a step in your CI/CD pipeline when deploying to environments that applies the Auth0 resource configurations to the appropriate Auth0 tenant
10
+
11
+ ## Tenant to Environment
12
+
13
+ It is recommended to have a separate Auth0 tenant/account for each environment you have. For example:
14
+
15
+ | Environment | Tenant |
16
+ | ----------- | ------------- |
17
+ | Development | travel0-dev |
18
+ | Testing | travel0-uat |
19
+ | Staging | travel0-stage |
20
+ | Production | travel0-prod |
21
+
22
+ ## Resource configuration repository
23
+
24
+ When exported, your Auth0 tenant state will be represented as a set of resource configuration files, either in a [YAML or JSON format](./available-resource-config-formats.md). In a multi-environment context it is expected to have a single repository of resource configurations that is applied to all environments. In practice, this may exist as a directory in your project’s codebase or in a separate codebase altogether.
25
+
26
+ You should have at least one branch for each tenant in your repository, which allows you to make changes without deploying them (the changes would only deploy when you merged your branch into the master, or primary, branch). With this setup, you can have a continuous integration task for each environment that automatically deploys changes to the targeted environment whenever the master branch receives updates.
27
+
28
+ Your workflow could potentially look something like this:
29
+
30
+ 1. Make changes to development.
31
+ 2. Merge changes to testing (or `uat`).
32
+ 3. Test changes to `uat`. When ready, move and merge the changes to `staging`.
33
+ 4. Test `staging`. When ready, move and merge the changes to `production`.
34
+
35
+ You may want to set your production environment to deploy only when triggered manually.
36
+
37
+ ## Uni-directional Flow
38
+
39
+ The multi-environment workflow works best when changes are propagated “up” in a single direction. Changes to the resource configuration files should first be applied to the lowest level environment (ex: dev) and then incrementally applied up through all other environments until applied to production. This uni-directional practice ensures sufficient testing and approval for changes to your tenant. Once set, it is recommended to not apply configurations directly to production through other means such as the Auth0 Dashboard or Management API unless those changes are captured by a subsequent Deploy CLI export. Otherwise, those changes are subject to overwrite.
40
+
41
+ ## Environment-specific values
42
+
43
+ While it is expected that all environments will share the same set of resource configuration files, environment-specific values can be expressed through separate tool configuration files and dynamic [keyword replacement](keyword-replacement.md).
44
+
45
+ ### Separate Config Files
46
+
47
+ Specifying a separate tool configuration file per environment can be used to keep the resource configuration files agnostic of environment but still cater for the needs of each environment. At a minimum, you will need to provide separate credentials for each environment, but it is also possible to exclude certain resources, enable deletion and perform dynamic keyword replacement on a per-environment basis.
48
+
49
+ ### Example file structure
50
+
51
+ ```
52
+ project-root
53
+
54
+ └───auth0
55
+ │ │ config-dev.json # Dev env config file
56
+ │ │ config-test.json # Test env config file
57
+ │ │ config-prod.json # Prod env config file
58
+ │ │ ... all other resource configuration files
59
+
60
+ └───src
61
+ │ ... your project code
62
+ ```
63
+
64
+ ### Dynamic Values via Keyword Replacement
65
+
66
+ Once separate configurations files are adopted for each environment, keyword replacement via the `AUTH0_KEYWORD_REPLACE_MAPPINGS` configuration property can be used to express the dynamic replacement values depending on the environment. For example, you may find it necessary to have a separate set of allowed origins for your clients (see below). To learn more, see [Keyword Replacement](keyword-replacement.md).
67
+
68
+ #### Example `config-dev.json`
69
+
70
+ ```json
71
+ {
72
+ "AUTH0_DOMAIN": "travel0-dev.us.auth0.com",
73
+ "AUTH0_CLIENT_ID": "PdwQpGy62sHcsV6ufZNEVrV4GDlDhm74",
74
+ "AUTH0_ALLOW_DELETE": true,
75
+ "AUTH0_KEYWORD_REPLACE_MAPPINGS": {
76
+ "ENV": "dev",
77
+ "ALLOWED_ORIGINS": ["http://localhost:3000", "http://dev.travel0.com"]
78
+ }
79
+ }
80
+ ```
81
+
82
+ #### Example `config-prod.json`
83
+
84
+ ```json
85
+ {
86
+ "AUTH0_DOMAIN": "travel0.us.auth0.com",
87
+ "AUTH0_CLIENT_ID": "vZCEFsDYzXc1x9IomB8dF185e4cdVah5",
88
+ "AUTH0_ALLOW_DELETE": false,
89
+ "AUTH0_KEYWORD_REPLACE_MAPPINGS": {
90
+ "ENV": "prod",
91
+ "ALLOWED_ORIGINS": ["http://travel0.com"]
92
+ }
93
+ }
94
+ ```
95
+
96
+ ---
97
+
98
+ [[table of contents]](../README.md#documentation)
@@ -0,0 +1,20 @@
1
+ # Auth0 Terraform Provider
2
+
3
+ The Deploy CLI is not the only tool available for managing your Auth0 tenant configuration, there is also an [officially supported Terraform Provider](https://github.com/auth0/terraform-provider-auth0). [Terraform](https://terraform.io/) is a third-party tool for representing your cloud resources’s configurations as code. It has an established plug-in framework that supports a wide array of cloud providers, including Auth0.
4
+
5
+ Both the Deploy CLI and Terraform Provider exist to help you manage your Auth0 tenant configurations, but each has their own set of pros and cons.
6
+
7
+ You may want to consider the Auth0 Terraform Provider if:
8
+
9
+ - Your development workflows already leverages Terraform
10
+ - Your tenant management needs are granular or only pertain to a few specific resources
11
+
12
+ You may **not** want to consider the Auth0 Terraform Provider if:
13
+
14
+ - Your development workflow does not use Terraform, requiring extra setup upfront
15
+ - Your development workflows are primarily concerned with managing your tenants in bulk
16
+ - Your tenant has lots of existing resources, may require significant effort to “import”
17
+
18
+ ---
19
+
20
+ [[table of contents]](../README.md#documentation)
@@ -0,0 +1,89 @@
1
+ # Using as a CLI
2
+
3
+ The Deploy CLI can be used as a standalone command line utility. Doing so provides a simple way to manage your Auth0 tenant configuration in CI/CD workflows.
4
+
5
+ ## `export` command
6
+
7
+ Fetching configurations from Auth0 tenant to the local machine.
8
+
9
+ ### `--output_folder`, `-o`
10
+
11
+ Path. Specifies the target directory for configuration files to be written to.
12
+
13
+ ### `--config_file`, `-c`
14
+
15
+ Path. Specifies the user-defined configuration file (`config.json`). Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
16
+
17
+ ### `--format`, `-f`
18
+
19
+ Options: yaml or directory. Determines the file format of the exported resource configuration files. See: [Available Resource Config Formats](available-resource-config-formats).
20
+
21
+ ### `--export_ids`, `-e`
22
+
23
+ Boolean. When enabled, will export the identifier fields for each resource. Default: `false`.
24
+
25
+ ### `--env`
26
+
27
+ Boolean. Indicates if the tool should ingest environment variables or not. Default: `true`.
28
+
29
+ ### `--debug`
30
+
31
+ Boolean. Enables more verbose error logging; useful during troubleshooting. Default: `false`.
32
+
33
+ ### `--proxy_url`, `-p`
34
+
35
+ A url for proxying requests. Only set this if you are behind a proxy.
36
+
37
+ ### Examples
38
+
39
+ ```shell
40
+ # Fetching Auth0 tenant configuration in the YAML format
41
+ a0deploy export -c=config.json --format=yaml --output_folder=local
42
+
43
+ # Fetching Auth0 tenant configuration in directory (JSON) format
44
+ a0deploy export -c=config.json --format=directory --output_folder=local
45
+
46
+ # Fetching Auth0 tenant configurations with IDs of all assets
47
+ a0deploy export -c=config.json --format=yaml --output_folder=local --export_ids=true
48
+ ```
49
+
50
+ ## `import` command
51
+
52
+ Applying configurations from local machine to Auth0 tenant.
53
+
54
+ ### `--input_file`, `-i`
55
+
56
+ Path. Specifies the location of the resource configuration files. For YAML formats, this will point to the `tenant.yaml` file, for directory formats, this will point to the resource configuration directory.
57
+
58
+ ### `--config_file`, `-c`
59
+
60
+ Path. Specifies the user-defined configuration file (config.json). Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
61
+
62
+ ### `--env`
63
+
64
+ Boolean. Indicates if the tool should ingest environment variables or not. Default: `true`.
65
+
66
+ ### `--proxy_url`, `-p`
67
+
68
+ A url for proxying requests. Only set this if you are behind a proxy.
69
+
70
+ ### `--debug`
71
+
72
+ Boolean. Enables more verbose error logging; useful during troubleshooting. Default: `false`.
73
+
74
+ ### Examples
75
+
76
+ ```shell
77
+ # Deploying configuration for YAML formats
78
+ a0deploy import -c=config.json --input_file=local/tenant.yaml
79
+
80
+ # Deploying configuration for directory format
81
+ a0deploy import -c=config.json --input_file=local
82
+
83
+ # Deploying configuration with environment variables ignored
84
+ a0deploy import -c=config.json --input_file=local/tenant.yaml --env=false
85
+ ```
86
+
87
+ ---
88
+
89
+ [[table of contents]](../README.md#documentation)
@@ -0,0 +1,114 @@
1
+ # Using as a Node Module
2
+
3
+ The Deploy CLI can not only be used as a standalone CLI, but as a node module. Doing so allows you to manage Auth0 resources within expressive node scripts.
4
+
5
+ ## `dump` function
6
+
7
+ Fetches configurations from Auth0 tenant to the local machine.
8
+
9
+ ### Example
10
+
11
+ ```ts
12
+ import { dump } from 'auth0-deploy-cli';
13
+
14
+ dump({
15
+ output_folder: './local',
16
+ format: 'yaml',
17
+ config: {
18
+ AUTH0_DOMAIN: '<YOUR_AUTH0_TENANT_DOMAIN>',
19
+ AUTH0_CLIENT_ID: '<YOUR_AUTH0_CLIENT_ID>',
20
+ AUTH0_CLIENT_SECRET: '<YOUR_AUTH0_CLIENT_SECRET>',
21
+ },
22
+ })
23
+ .then(() => {
24
+ console.log('Auth0 configuration export successful');
25
+ })
26
+ .catch((err) => {
27
+ console.log('Error during Auth0 configuration export:', err);
28
+ });
29
+ ```
30
+
31
+ ## Argument parameters
32
+
33
+ #### `format`
34
+
35
+ Options: `yaml` or `directory`. Determines the file format of the exported resource configuration files. See: [Available Resource Configuration Formats](available-resource-config-formats).
36
+
37
+ #### `output_folder`
38
+
39
+ Path. Specifies the target directory for configuration files to be written to.
40
+
41
+ #### `config`
42
+
43
+ Object. Configures behavior of utility. Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
44
+
45
+ #### `config_file`
46
+
47
+ Path. Specifies the user-defined configuration file (config.json). Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
48
+
49
+ #### `export_ids`
50
+
51
+ Boolean: When enabled, will export the identifier fields for each resource. Default: false.
52
+
53
+ #### `env`
54
+
55
+ Boolean. Indicates if the tool should ingest environment variables or not. Default: `false`.
56
+
57
+ #### `proxy_url`
58
+
59
+ A url for proxying requests. Only set this if you are behind a proxy.
60
+
61
+ ## `deploy` function
62
+
63
+ Applies configurations from local machine to Auth0 tenant.
64
+
65
+ ### Argument parameters
66
+
67
+ #### `input_file`
68
+
69
+ Path. Specifies the location of the resource configuration files. For YAML formats, this will point to the tenant.yaml file. For directory formats, this will point to the resource configuration directory.
70
+
71
+ #### `config`
72
+
73
+ Object. Configures behavior of utility. Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
74
+
75
+ #### `config_file`
76
+
77
+ Path. Specifies the user-defined configuration file (config.json). Refer to the list of [all configurable properties](./configuring-the-deploy-cli.md).
78
+
79
+ #### `export_ids`
80
+
81
+ Boolean: When enabled, will export the identifier fields for each resource. Default: `false`.
82
+
83
+ #### `env`
84
+
85
+ Boolean. Indicates if the tool should ingest environment variables or not. Default: `false`.
86
+
87
+ #### `proxy_url`
88
+
89
+ A url for proxying requests. Only set this if you are behind a proxy.
90
+
91
+ ### Example
92
+
93
+ ```ts
94
+ import { deploy } from 'auth0-deploy-cli';
95
+
96
+ deploy({
97
+ input_file: './local/tenant.yaml',
98
+ config: {
99
+ AUTH0_DOMAIN: '<YOUR_AUTH0_TENANT_DOMAIN>',
100
+ AUTH0_CLIENT_ID: '<YOUR_AUTH0_CLIENT_ID>',
101
+ AUTH0_CLIENT_SECRET: '<YOUR_AUTH0_CLIENT_SECRET>',
102
+ },
103
+ })
104
+ .then(() => {
105
+ console.log('Auth0 configuration applied to tenant successful');
106
+ })
107
+ .catch((err) => {
108
+ console.log('Error when applying configuration to Auth0 tenant:', err);
109
+ });
110
+ ```
111
+
112
+ ---
113
+
114
+ [[table of contents]](../README.md#documentation)
@@ -1,2 +1,4 @@
1
1
  import { ImportParams } from '../args';
2
+ import { Assets } from '../types';
2
3
  export default function importCMD(params: ImportParams): Promise<void>;
4
+ export declare const findUnreplacedKeywords: (assets: Assets) => void;
@@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.findUnreplacedKeywords = void 0;
15
16
  const nconf_1 = __importDefault(require("nconf"));
16
17
  const configFactory_1 = require("../configFactory");
17
18
  const tools_1 = require("../tools");
@@ -40,9 +41,43 @@ function importCMD(params) {
40
41
  yield context.load();
41
42
  const config = (0, configFactory_1.configFactory)();
42
43
  config.setProvider((key) => nconf_1.default.get(key));
43
- //@ts-ignore because context and assets still need to be typed TODO: type assets and type context
44
+ (0, exports.findUnreplacedKeywords)(context.assets);
44
45
  yield (0, tools_1.deploy)(context.assets, context.mgmtClient, config);
45
46
  logger_1.default.info('Import Successful');
46
47
  });
47
48
  }
48
49
  exports.default = importCMD;
50
+ const findUnreplacedKeywords = (assets) => {
51
+ const recursiveFindUnreplacedKeywords = (target) => {
52
+ let unreplaced = [];
53
+ if (target === undefined || target === null)
54
+ return [];
55
+ if (Array.isArray(target)) {
56
+ target.forEach((child) => {
57
+ unreplaced.push(...recursiveFindUnreplacedKeywords(child));
58
+ });
59
+ }
60
+ else if (typeof target === 'object') {
61
+ Object.values(target).forEach((child) => {
62
+ unreplaced.push(...recursiveFindUnreplacedKeywords(child));
63
+ });
64
+ }
65
+ if (typeof target === 'string') {
66
+ const arrayMatches = target.match(/(?<=@@).*(?=@@)/g);
67
+ if (arrayMatches !== null) {
68
+ return arrayMatches;
69
+ }
70
+ const keywordMatches = target.match(/(?<=##).*(?=##)/g);
71
+ if (keywordMatches !== null) {
72
+ return keywordMatches;
73
+ }
74
+ }
75
+ return unreplaced;
76
+ };
77
+ const unreplacedKeywords = recursiveFindUnreplacedKeywords(assets);
78
+ if (unreplacedKeywords.length > 0) {
79
+ throw `Unreplaced keywords found: ${unreplacedKeywords.join(', ')}. Either correct these values or add to AUTH0_KEYWORD_REPLACE_MAPPINGS configuration.`;
80
+ }
81
+ return;
82
+ };
83
+ exports.findUnreplacedKeywords = findUnreplacedKeywords;
@@ -31,6 +31,7 @@ const branding_1 = __importDefault(require("./branding"));
31
31
  const logStreams_1 = __importDefault(require("./logStreams"));
32
32
  const prompts_1 = __importDefault(require("./prompts"));
33
33
  const customDomains_1 = __importDefault(require("./customDomains"));
34
+ const themes_1 = __importDefault(require("./themes"));
34
35
  const directoryHandlers = {
35
36
  rules: rules_1.default,
36
37
  rulesConfigs: rulesConfigs_1.default,
@@ -60,5 +61,6 @@ const directoryHandlers = {
60
61
  logStreams: logStreams_1.default,
61
62
  prompts: prompts_1.default,
62
63
  customDomains: customDomains_1.default,
64
+ themes: themes_1.default,
63
65
  };
64
66
  exports.default = directoryHandlers;
@@ -0,0 +1,6 @@
1
+ import { DirectoryHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { Theme } from '../../../tools/auth0/handlers/themes';
4
+ declare type ParsedThemes = ParsedAsset<'themes', Theme[]>;
5
+ declare const themesHandler: DirectoryHandler<ParsedThemes>;
6
+ export default themesHandler;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const path_1 = __importDefault(require("path"));
16
+ const fs_extra_1 = require("fs-extra");
17
+ const utils_1 = require("../../../utils");
18
+ const tools_1 = require("../../../tools");
19
+ function parse(context) {
20
+ const baseFolder = path_1.default.join(context.filePath, tools_1.constants.THEMES_DIRECTORY);
21
+ if (!(0, utils_1.existsMustBeDir)(baseFolder)) {
22
+ return { themes: null };
23
+ }
24
+ const themeDefinitionsFiles = (0, utils_1.getFiles)(baseFolder, ['.json']);
25
+ if (!themeDefinitionsFiles.length) {
26
+ return { themes: [] };
27
+ }
28
+ const themes = themeDefinitionsFiles.map((themeDefinitionsFile) => (0, utils_1.loadJSON)(themeDefinitionsFile, context.mappings));
29
+ return { themes };
30
+ }
31
+ function dump(context) {
32
+ return __awaiter(this, void 0, void 0, function* () {
33
+ const { themes } = context.assets;
34
+ if (!themes) {
35
+ return;
36
+ }
37
+ const baseFolder = path_1.default.join(context.filePath, tools_1.constants.THEMES_DIRECTORY);
38
+ (0, fs_extra_1.ensureDirSync)(baseFolder);
39
+ themes.forEach((themeDefinition, i) => {
40
+ (0, utils_1.dumpJSON)(path_1.default.join(baseFolder, `theme${i ? i : ''}.json`), themeDefinition);
41
+ });
42
+ });
43
+ }
44
+ const themesHandler = {
45
+ parse,
46
+ dump,
47
+ };
48
+ exports.default = themesHandler;
@@ -31,6 +31,7 @@ const branding_1 = __importDefault(require("./branding"));
31
31
  const logStreams_1 = __importDefault(require("./logStreams"));
32
32
  const prompts_1 = __importDefault(require("./prompts"));
33
33
  const customDomains_1 = __importDefault(require("./customDomains"));
34
+ const themes_1 = __importDefault(require("./themes"));
34
35
  const yamlHandlers = {
35
36
  rules: rules_1.default,
36
37
  hooks: hooks_1.default,
@@ -60,5 +61,6 @@ const yamlHandlers = {
60
61
  logStreams: logStreams_1.default,
61
62
  prompts: prompts_1.default,
62
63
  customDomains: customDomains_1.default,
64
+ themes: themes_1.default,
63
65
  };
64
66
  exports.default = yamlHandlers;
@@ -44,7 +44,7 @@ function dump(context) {
44
44
  // Dump html to file
45
45
  const htmlFile = path_1.default.join(pagesFolder, `${page.name}.html`);
46
46
  logger_1.default.info(`Writing ${htmlFile}`);
47
- fs_extra_1.default.writeFileSync(htmlFile, page.html);
47
+ fs_extra_1.default.writeFileSync(htmlFile, page.html || '');
48
48
  return Object.assign(Object.assign({}, page), { html: `./pages/${page.name}.html` });
49
49
  });
50
50
  return { pages };
@@ -0,0 +1,6 @@
1
+ import { YAMLHandler } from '.';
2
+ import { ParsedAsset } from '../../../types';
3
+ import { Theme } from '../../../tools/auth0/handlers/themes';
4
+ declare type ParsedThemes = ParsedAsset<'themes', Theme[]>;
5
+ declare const themesHandler: YAMLHandler<ParsedThemes>;
6
+ export default themesHandler;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ function parseAndDump(context) {
13
+ return __awaiter(this, void 0, void 0, function* () {
14
+ const { themes } = context.assets;
15
+ if (!themes)
16
+ return { themes: null };
17
+ return {
18
+ themes,
19
+ };
20
+ });
21
+ }
22
+ const themesHandler = {
23
+ parse: parseAndDump,
24
+ dump: parseAndDump,
25
+ };
26
+ exports.default = themesHandler;
package/lib/index.d.ts CHANGED
@@ -79,6 +79,7 @@ declare const _default: {
79
79
  LOG_STREAMS_DIRECTORY: string;
80
80
  PROMPTS_DIRECTORY: string;
81
81
  CUSTOM_DOMAINS_DIRECTORY: string;
82
+ THEMES_DIRECTORY: string;
82
83
  };
83
84
  deploy: typeof import("./tools").deploy;
84
85
  keywordReplace: typeof import("./tools").keywordReplace;
@@ -55,6 +55,11 @@ declare const _default: {
55
55
  excludeSchema?: any;
56
56
  schema: any;
57
57
  };
58
+ themes: {
59
+ default: typeof APIHandler;
60
+ excludeSchema?: any;
61
+ schema: any;
62
+ };
58
63
  attackProtection: {
59
64
  default: typeof APIHandler;
60
65
  excludeSchema?: any;
@@ -52,6 +52,7 @@ const organizations = __importStar(require("./organizations"));
52
52
  const attackProtection = __importStar(require("./attackProtection"));
53
53
  const logStreams = __importStar(require("./logStreams"));
54
54
  const customDomains = __importStar(require("./customDomains"));
55
+ const themes = __importStar(require("./themes"));
55
56
  const auth0ApiHandlers = {
56
57
  rules,
57
58
  rulesConfigs,
@@ -82,5 +83,6 @@ const auth0ApiHandlers = {
82
83
  attackProtection,
83
84
  logStreams,
84
85
  customDomains,
86
+ themes,
85
87
  };
86
88
  exports.default = auth0ApiHandlers; // TODO: apply stronger types to schema properties
@@ -164,7 +164,8 @@ class PromptsHandler extends default_1.default {
164
164
  const supportedLanguages = yield this.client.tenant
165
165
  .getSettings()
166
166
  .then(({ enabled_locales }) => enabled_locales);
167
- const data = yield Promise.all(supportedLanguages.flatMap((language) => {
167
+ const data = yield Promise.all(supportedLanguages
168
+ .map((language) => {
168
169
  return promptTypes.map((promptType) => {
169
170
  return this.client.prompts
170
171
  .getCustomTextByLanguage({
@@ -180,7 +181,9 @@ class PromptsHandler extends default_1.default {
180
181
  };
181
182
  });
182
183
  });
183
- })).then((customTextData) => {
184
+ })
185
+ .reduce((acc, val) => acc.concat(val), []) // TODO: replace .map().reduce() with .flatMap() once we officially eliminate Node v10 support
186
+ ).then((customTextData) => {
184
187
  return customTextData
185
188
  .filter((customTextData) => {
186
189
  return customTextData !== null;
@@ -1,11 +1,22 @@
1
1
  import DefaultHandler from './default';
2
- import { Asset, Assets } from '../../../types';
2
+ import { Asset, Assets, Language } from '../../../types';
3
3
  export declare const schema: {
4
4
  type: string;
5
5
  };
6
+ export declare type Tenant = Asset & {
7
+ enabled_locales: Language[];
8
+ flags: {
9
+ [key: string]: boolean;
10
+ };
11
+ };
6
12
  export default class TenantHandler extends DefaultHandler {
13
+ existing: Tenant;
7
14
  constructor(options: DefaultHandler);
8
15
  getType(): Promise<Asset>;
9
16
  validate(assets: Assets): Promise<void>;
10
17
  processChanges(assets: Assets): Promise<void>;
11
18
  }
19
+ export declare const sanitizeMigrationFlags: ({ existingFlags, proposedFlags, }: {
20
+ existingFlags: Tenant['flags'];
21
+ proposedFlags: Tenant['flags'];
22
+ }) => Tenant['flags'];
@@ -41,7 +41,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
41
41
  return (mod && mod.__esModule) ? mod : { "default": mod };
42
42
  };
43
43
  Object.defineProperty(exports, "__esModule", { value: true });
44
- exports.schema = void 0;
44
+ exports.sanitizeMigrationFlags = exports.schema = void 0;
45
45
  const validationError_1 = __importDefault(require("../../validationError"));
46
46
  const default_1 = __importStar(require("./default"));
47
47
  const pages_1 = require("./pages");
@@ -61,6 +61,7 @@ class TenantHandler extends default_1.default {
61
61
  getType() {
62
62
  return __awaiter(this, void 0, void 0, function* () {
63
63
  const tenant = yield this.client.tenant.getSettings();
64
+ this.existing = tenant;
64
65
  blockPageKeys.forEach((key) => {
65
66
  if (tenant[key])
66
67
  delete tenant[key];
@@ -84,10 +85,18 @@ class TenantHandler extends default_1.default {
84
85
  processChanges(assets) {
85
86
  return __awaiter(this, void 0, void 0, function* () {
86
87
  const { tenant } = assets;
87
- if (tenant && Object.keys(tenant).length > 0) {
88
- yield this.client.tenant.updateSettings(tenant);
88
+ // Do nothing if not set
89
+ if (!tenant)
90
+ return;
91
+ const existingTenant = this.existing || (yield this.getType());
92
+ const updatedTenant = Object.assign(Object.assign({}, tenant), { flags: (0, exports.sanitizeMigrationFlags)({
93
+ existingFlags: existingTenant.flags,
94
+ proposedFlags: tenant.flags,
95
+ }) });
96
+ if (updatedTenant && Object.keys(updatedTenant).length > 0) {
97
+ yield this.client.tenant.updateSettings(updatedTenant);
89
98
  this.updated += 1;
90
- this.didUpdate(tenant);
99
+ this.didUpdate(updatedTenant);
91
100
  }
92
101
  });
93
102
  }
@@ -96,3 +105,29 @@ __decorate([
96
105
  (0, default_1.order)('100')
97
106
  ], TenantHandler.prototype, "processChanges", null);
98
107
  exports.default = TenantHandler;
108
+ const sanitizeMigrationFlags = ({ existingFlags = {}, proposedFlags = {}, }) => {
109
+ /*
110
+ Tenants can only update migration flags that are already configured.
111
+ If moving configuration from one tenant to another, there may be instances
112
+ where different migration flags exist and cause an error on update. This
113
+ function removes any migration flags that aren't already present on the target
114
+ tenant. See: https://github.com/auth0/auth0-deploy-cli/issues/374
115
+ */
116
+ const tenantMigrationFlags = [
117
+ 'disable_clickjack_protection_headers',
118
+ 'enable_mgmt_api_v1',
119
+ 'trust_azure_adfs_email_verified_connection_property',
120
+ 'include_email_in_reset_pwd_redirect',
121
+ 'include_email_in_verify_email_redirect',
122
+ ];
123
+ return Object.keys(proposedFlags).reduce((acc, proposedKey) => {
124
+ const isMigrationFlag = tenantMigrationFlags.includes(proposedKey);
125
+ if (!isMigrationFlag)
126
+ return Object.assign(Object.assign({}, acc), { [proposedKey]: proposedFlags[proposedKey] });
127
+ const keyCurrentlyExists = existingFlags[proposedKey] !== undefined;
128
+ if (keyCurrentlyExists)
129
+ return Object.assign(Object.assign({}, acc), { [proposedKey]: proposedFlags[proposedKey] });
130
+ return acc;
131
+ }, {});
132
+ };
133
+ exports.sanitizeMigrationFlags = sanitizeMigrationFlags;