auth0-deploy-cli 9.0.0-beta.2 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/AGENTS.md +2 -357
  2. package/CHANGELOG.md +158 -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 +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 +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 +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 +1 -4
  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
@@ -0,0 +1,98 @@
1
+ # Commands Reference — auth0-deploy-cli
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ # Install dependencies (first-time setup)
7
+ npm install
8
+ ```
9
+
10
+ ## Build
11
+
12
+ ```bash
13
+ # Compile TypeScript → lib/ (cleans lib/ first via rimraf)
14
+ npm run build
15
+
16
+ # Compile and watch (development)
17
+ npm run dev
18
+
19
+ # Type check only (no output)
20
+ npx tsc --noEmit
21
+ ```
22
+
23
+ ## Unit Tests
24
+
25
+ ```bash
26
+ # Run all unit tests (safe — no credentials required)
27
+ npm test
28
+
29
+ # Run a specific test file
30
+ npx ts-mocha -p tsconfig.json test/tools/auth0/handlers/clients.test.js
31
+
32
+ # Run tests matching a pattern
33
+ npm test -- --grep "should create client"
34
+
35
+ # Run with coverage
36
+ npm run test:coverage
37
+ ```
38
+
39
+ ## Lint
40
+
41
+ ```bash
42
+ # ESLint + kacl changelog lint
43
+ npm run lint
44
+
45
+ # Auto-fix ESLint issues
46
+ npm run lint:fix
47
+ ```
48
+
49
+ ## E2E Tests
50
+
51
+ > ⚠️ These tests hit a real Auth0 tenant. Ask before running — see [Boundaries](../CLAUDE.md#boundaries).
52
+
53
+ ```bash
54
+ # E2E as Node module (uses HTTP recordings)
55
+ AUTH0_HTTP_RECORDINGS=lockdown npm run test:e2e:node-module
56
+
57
+ # E2E as CLI (requires real tenant credentials)
58
+ npm run test:e2e:cli
59
+ ```
60
+
61
+ Required environment variables for E2E:
62
+
63
+ - `AUTH0_DOMAIN`
64
+ - `AUTH0_CLIENT_ID`
65
+ - `AUTH0_CLIENT_SECRET`
66
+ - `AUTH0_HTTP_RECORDINGS=lockdown` (for node-module recording replay)
67
+
68
+ ## Running the CLI Directly
69
+
70
+ ```bash
71
+ # Always build first
72
+ npm run build
73
+
74
+ # Export tenant configuration
75
+ node lib/index.js export -c config.json -f directory -o ./local/
76
+ node lib/index.js export -c config.json -f yaml -o ./local-yaml/
77
+
78
+ # Import (deploy) configuration
79
+ node lib/index.js import -c config.json -i ./local/tenant.json
80
+ node lib/index.js import -c config.json -i ./local-yaml/tenant.yaml
81
+
82
+ # Enable debug logging
83
+ AUTH0_DEBUG=true node lib/index.js import -c config.json -i ./local/tenant.json
84
+ ```
85
+
86
+ ## Environment Variables Reference
87
+
88
+ ```bash
89
+ AUTH0_DOMAIN # Tenant domain (e.g. my-tenant.auth0.com)
90
+ AUTH0_CLIENT_ID # Client ID for M2M application
91
+ AUTH0_CLIENT_SECRET # Client secret
92
+ AUTH0_ALLOW_DELETE=true # Enable delete operations (default: false)
93
+ AUTH0_KEYWORD_REPLACE_MAPPINGS # JSON object for @@KEY@@/##KEY## substitution
94
+ AUTH0_EXCLUDED # JSON array of resource types to skip
95
+ AUTH0_EXCLUDED_<TYPE> # Exclude specific resources by name, e.g. AUTH0_EXCLUDED_CLIENTS
96
+ AUTH0_DEBUG=true # Enable verbose debug logging
97
+ AUTH0_HTTP_RECORDINGS=lockdown # Replay HTTP recordings in E2E node-module tests
98
+ ```
@@ -0,0 +1,34 @@
1
+ # Docs Update Rules — auth0-deploy-cli
2
+
3
+ ## Tracked Docs Inventory
4
+
5
+ | Doc | Status | Covers |
6
+ | --------------------- | ---------- | --------------------------------------------------------------------------------------------------------------- |
7
+ | `README.md` | present | Installation, quick-start, prerequisites, CLI usage, configuration options, environment variables, contributing |
8
+ | `EXAMPLES.md` | ❌ missing | Create when adding a new integration pattern or command example |
9
+ | `examples/yaml/` | present | Sample YAML-format tenant configuration |
10
+ | `examples/directory/` | present | Sample directory-format tenant configuration |
11
+
12
+ ## Code-to-Docs Mapping (CLI tool)
13
+
14
+ This is a CLI tool. The public surface is **commands, subcommands, and flags** — not exported functions.
15
+
16
+ | When this changes | Update these docs |
17
+ | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
18
+ | A command or subcommand added, removed, or renamed | `README.md` (command reference / usage) |
19
+ | A flag or argument added, removed, renamed, or its default changed | `README.md` (command reference), `examples/` (affected invocations) |
20
+ | Output format or exit-code behavior changed | `README.md` (usage), `examples/` |
21
+ | A new resource type added or removed | `README.md` (supported resources section), `examples/yaml/` and `examples/directory/` (add sample config) |
22
+ | A new config field or env var added | `README.md` (configuration / environment variables section) |
23
+ | A new keyword replacement pattern or behavior | `README.md` (keyword replacement section) |
24
+
25
+ > When you touch code that maps to a doc above, update that doc **in the same PR** — do not defer.
26
+
27
+ > `CHANGELOG.md` is maintained as part of the release flow — do not add changelog entries during feature development; they are cut at release time via the release process.
28
+
29
+ ## Additional Reference Docs
30
+
31
+ - `docs/` — extended documentation including resource-specific docs; update `docs/resource-specific-documentation.md` when adding a new handler
32
+ - `docs/v8_MIGRATION_GUIDE.md` — v8 migration context; when making a breaking change, consult this pattern to author a versioned migration guide (filename inferred from the target major at the time of the change)
33
+ - `CONTRIBUTING.md` — contribution guidelines
34
+ - `.github/ISSUE_TEMPLATE/` — issue templates for bug reports and feature requests
@@ -0,0 +1,135 @@
1
+ # Git Workflow Reference — auth0-deploy-cli
2
+
3
+ ## Branch Naming
4
+
5
+ `DXCDT-XXXX` (Jira ticket number) for feature and fix branches.
6
+
7
+ Examples: `DXCDT-2268`, `SDK-10176`
8
+
9
+ ## Commit Messages
10
+
11
+ Conventional Commits format:
12
+
13
+ - `feat: add support for new resource type`
14
+ - `fix: resolve table formatting issue`
15
+ - `docs: update handler implementation guide`
16
+ - `test: add coverage for keyword replacement`
17
+ - `refactor: simplify change calculation logic`
18
+
19
+ ## Pull Request Conventions
20
+
21
+ PR template is at `.github/PULL_REQUEST_TEMPLATE.md`. Sections:
22
+
23
+ - **Changes** — what was changed and why
24
+ - **References** — linked Jira ticket or GitHub issue
25
+ - **Testing** — what was tested, and any scenarios that could not be tested (EA / entitlement-gated)
26
+ - **Checklist** — tests pass, lint passes, docs updated, backward compatibility checked
27
+
28
+ ## PR Review Checklist
29
+
30
+ > This is a living document. Add a new section, checklist item, or Lesson Learned whenever a real review surfaces a pattern worth capturing.
31
+
32
+ Work through every section in order. Do not skip sections because they seem irrelevant. Give a structured summary after all areas: issues found (grouped by severity), items that look good, and questions for the author.
33
+
34
+ ### 1. Context & Purpose
35
+
36
+ - Does the PR description explain **why** this change is needed, not just what it does?
37
+ - Is there a linked issue? Does the PR actually close it?
38
+ - Is the scope reasonable — one thing, not many things?
39
+
40
+ ### 2. Correctness
41
+
42
+ - Does the logic do what the description claims?
43
+ - Are early exits and guard clauses correct — not too broad, not too narrow?
44
+ - Are error paths handled? Does a failure in one step leave state inconsistent?
45
+ - Are there silent failures (swallowed errors, empty catch blocks)?
46
+ - Does the ordering of operations matter? Is it correct? (e.g. create before delete)
47
+
48
+ ### 3. Edge Cases
49
+
50
+ - What happens with empty input / null / undefined?
51
+ - What happens when the resource already exists (idempotency)?
52
+ - What happens when a partial failure occurs mid-operation?
53
+ - Are there race conditions or ordering dependencies across handlers?
54
+
55
+ ### 4. Backward Compatibility
56
+
57
+ - Does this break any existing config formats or file structures?
58
+ - Will existing users' export → deploy workflows still work unchanged?
59
+ - Are old config shapes (from before this PR) still handled gracefully?
60
+ - Does any new export format, when re-deployed unchanged, produce unintended side effects?
61
+
62
+ ### 5. Safety & Destructive Operations
63
+
64
+ - Are destructive operations (delete, overwrite) gated by `ALLOW_DELETE`?
65
+ - Is the safety contract enforced in code on **all** paths — not just the obvious ones?
66
+ - Could a no-op deploy (nothing changed) still cause mutations?
67
+
68
+ ### 6. Tests
69
+
70
+ - Are unit tests present for new logic?
71
+ - Do tests actually test what their names claim? Verify the mock matches the test name.
72
+ - Are critical/risky paths covered — not just the happy path?
73
+ - Are E2E tests present or updated? If not, is there a documented reason?
74
+ - Is there a regression test for the exact failure scenario the PR is fixing?
75
+ - Are there idempotency tests — running the same operation twice produces no extra changes?
76
+
77
+ ### 7. Docs & Examples
78
+
79
+ - Is there a new config shape or feature? Are examples updated?
80
+ - Are example files (`examples/`, `tenant.yaml`) updated to demonstrate new functionality?
81
+ - Is the README or relevant documentation updated?
82
+ - Are new config fields, env vars, or flags documented?
83
+
84
+ ### 8. Code Quality
85
+
86
+ - Is the code readable and does it follow existing patterns?
87
+ - Are there unnecessary type casts (`as any`, `as Function`) that bypass type safety?
88
+ - Is there dead code, unused imports, or leftover debug statements?
89
+ - Is mutation of shared state (e.g. assets objects) clearly intentional and safe?
90
+
91
+ ### 9. Performance
92
+
93
+ - Are there N+1 patterns (API calls inside loops)?
94
+ - Could this cause rate limiting for large tenants?
95
+
96
+ ### 10. Security
97
+
98
+ - Are sensitive values (secrets, PEM keys, tokens) ever logged or exported?
99
+ - Is user-controlled input validated before use?
100
+
101
+ ### 11. deploy-cli Specific — verify all of these
102
+
103
+ - Does the change work in **both** YAML and directory formats?
104
+ - Is the dry-run path correct? Dry-run must never mutate state on any affected path.
105
+ - Is keyword replacement (`@@KEY@@` / `##KEY##`) preserved correctly for new fields?
106
+ - Are write-only fields (secrets, key material) stripped on export and never written to disk?
107
+ - Are read-only/API-generated fields (`created_at`, `updated_at`, `id`, `fingerprint`) stripped on export and excluded from create/update payloads?
108
+ - Does a new handler implement all required methods: `getType`, `calcChanges`, `processChanges`, `validate`?
109
+ - Does the `identifiers` array include `name` (or a stable name-like field) as the primary key — not solely an auto-generated UUID `id`?
110
+ - Is handler `@order()` placed correctly relative to its dependencies?
111
+ - Is the JSON schema complete and accurate without being so permissive it passes invalid configs?
112
+ - Is sorted-key output stable? No unintended order changes introduced in exported configs.
113
+
114
+ ### 12. EA / Entitlement-Gated (apply if feature requires a flag or entitlement to test)
115
+
116
+ - Which scenarios could not be tested? Are they explicitly listed in the PR description?
117
+ - For each untested scenario, are the API assumptions spelled out — not buried under "code path confirmed correct"?
118
+ - If a field is read from `this.existing` (populated via list) and used in a guard: has the list endpoint been verified to return that field?
119
+ - If schema uses `additionalProperties: false` on an EA object: has the full read shape been confirmed from a real API response?
120
+ - Is there a follow-up ticket to re-verify untested scenarios once entitlement is available?
121
+
122
+ ### Final Gate — answer all four before approving
123
+
124
+ 1. If I export and immediately re-deploy with no changes, is anything mutated?
125
+ 2. If a mid-operation step fails, is the system left in a recoverable state?
126
+ 3. Has the safety contract been verified in code for every path — not just described in the PR?
127
+ 4. Are docs and examples updated so another engineer can use this feature without reading the code?
128
+
129
+ ### Lessons Learned
130
+
131
+ - **Safety claim ≠ safety in code.** "Deletes are gated" in a PR description doesn't mean the code gates deletes on every path. Verify line by line.
132
+ - **Early-exit logic is subtle.** `A && B` vs `A` in a guard clause can be the difference between a no-op and data loss.
133
+ - **Mocks can lie.** A test named "should not delete when flag is off" may pass for the wrong reason. Always verify the stub is called (or not called) with `sinon.assert`.
134
+ - **Export format drift breaks imports.** A richer export shape can silently break the import path if the importer doesn't handle it. Check both sides.
135
+ - **"Code path confirmed correct" ≠ tested end-to-end.** If an entitlement blocked a scenario, say so explicitly and enumerate the unverified assumptions.
@@ -0,0 +1,62 @@
1
+ # Common Pitfalls — auth0-deploy-cli
2
+
3
+ ## 1. Dry-run must never mutate
4
+
5
+ `processChanges()` is called in both live and dry-run mode. The dry-run guard lives higher up the call stack — any code path that bypasses it (e.g. a direct API call outside `processChanges`) silently mutates tenant state. Always verify the full call graph, not just the handler method.
6
+
7
+ ## 2. Both YAML and directory formats must work
8
+
9
+ New fields, handlers, and schema changes must work in both context formats. The YAML context uses a single `tenant.yaml`; the directory context uses nested JSON files. Test with both. Failing one format is a silent breakage users hit in production.
10
+
11
+ ## 3. @@KEY@@ vs ##KEY## — use the right pattern
12
+
13
+ - `@@KEY@@` — JSON-stringified. Use for arrays, objects, booleans, numbers. If the replacement is a JSON array, `@@KEY@@` produces valid YAML/JSON inline.
14
+ - `##KEY##` — literal string substitution. Use only for plain string values.
15
+
16
+ Mixing them up causes silent corruption: a `##KEY##` wrapping a JSON array produces invalid YAML.
17
+
18
+ ## 4. "Code path confirmed correct" ≠ "tested end-to-end"
19
+
20
+ For EA / entitlement-gated features, code review cannot substitute for a real API call. The API may return fields the code doesn't expect, or omit fields the code reads from `this.existing`. Always document what you could not test and create a follow-up ticket.
21
+
22
+ ## 5. additionalProperties: false on EA objects
23
+
24
+ If a schema uses `additionalProperties: false` and the API later returns a new field on that object, every deploy will fail schema validation. Only use `additionalProperties: false` after confirming the exact API response shape from a real tenant response — not API docs alone.
25
+
26
+ ## 6. identifiers must include name
27
+
28
+ `identifiers = ['id']` uses the auto-generated API ID for cross-tenant matching. This breaks portability — the ID is tenant-specific. Always include `name` (or a stable name-like field) as the primary matching key.
29
+
30
+ ## 7. Export → re-deploy roundtrip must be idempotent
31
+
32
+ After an export, re-deploying the same config with no manual changes must produce zero diffs. Any field that gets transformed on export and then looks different on the next import/export cycle is a bug. Test this explicitly for new fields.
33
+
34
+ ## 8. @order() placement
35
+
36
+ Handlers run in dependency order defined by `@order()`. A handler that creates resources another depends on (e.g. Connections before Clients) must have a lower order number. Wrong order → 404s or constraint errors during deploy.
37
+
38
+ ---
39
+
40
+ ## Debugging
41
+
42
+ ### Enable verbose logging
43
+
44
+ ```bash
45
+ AUTH0_DEBUG=true node lib/index.js import -c config.json -i ./local/tenant.json
46
+ ```
47
+
48
+ ### Common issues
49
+
50
+ | Symptom | Likely cause | Fix |
51
+ | ---------------------------------------------------- | ----------------------------------- | --------------------------------------------------------------------------------- |
52
+ | Build errors / import not found | `tsconfig.json` path mismatch | Check `tsconfig.json` and ensure all imports resolve |
53
+ | "Handler not found" / resource skipped silently | Resource type not registered | Verify it's added to `src/tools/constants.ts` |
54
+ | Schema validation fails on deploy | Schema too strict or missing fields | Check schema definition in the handler file; confirm against a real API response |
55
+ | Keyword replacement produces raw `@@KEY@@` in output | Mapping missing or wrong pattern | Verify `AUTH0_KEYWORD_REPLACE_MAPPINGS` config and confirm `@@KEY@@` vs `##KEY##` |
56
+ | E2E fails with auth errors | Missing or wrong credentials | Check `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET` |
57
+
58
+ ### Key files for debugging
59
+
60
+ - `src/tools/deploy.ts` — deployment orchestration; check here first if a resource is silently skipped
61
+ - `src/tools/calculateChanges.ts` — change detection; check here for unexpected create/update/delete
62
+ - `test/utils.js` — `mockPagedData()` and other test helpers
@@ -0,0 +1,118 @@
1
+ # Testing Reference — auth0-deploy-cli
2
+
3
+ ## Framework and Tools
4
+
5
+ - **Test runner**: Mocha 10.x (`ts-mocha` for TypeScript)
6
+ - **Stubs / spies**: sinon
7
+ - **Coverage**: nyc (Istanbul)
8
+ - **Test location**: `test/` (mirrors `src/` structure)
9
+ - **File pattern**: `test/**/*.test*` (excludes `test/e2e/`)
10
+ - **Timeout**: 20 000 ms per test
11
+
12
+ ## Running Tests
13
+
14
+ ```bash
15
+ # All unit tests (safe — no credentials)
16
+ npm test
17
+
18
+ # Single file
19
+ npx ts-mocha -p tsconfig.json test/tools/auth0/handlers/clients.test.js
20
+
21
+ # Pattern match
22
+ npm test -- --grep "should create client"
23
+
24
+ # With coverage report
25
+ npm run test:coverage
26
+ ```
27
+
28
+ ## Handler Test Scaffolding
29
+
30
+ ```javascript
31
+ const mockClient = {
32
+ clients: {
33
+ getAll: sinon.stub().returns(
34
+ mockPagedData([
35
+ /* existing resources */
36
+ ])
37
+ ),
38
+ create: sinon.stub().resolves({ client_id: 'abc', name: 'my-app' }),
39
+ update: sinon.stub().resolves({}),
40
+ delete: sinon.stub().resolves({}),
41
+ },
42
+ };
43
+
44
+ const mockConfig = (key) => {
45
+ const config = {
46
+ AUTH0_ALLOW_DELETE: false,
47
+ AUTH0_EXCLUDED_CLIENTS: [],
48
+ };
49
+ return config[key];
50
+ };
51
+ ```
52
+
53
+ ## Test Naming Convention
54
+
55
+ ```javascript
56
+ describe('ClientsHandler', () => {
57
+ it('should create a client when it does not exist', async () => { ... });
58
+ it('should update a client when it already exists', async () => { ... });
59
+ it('should not delete when AUTH0_ALLOW_DELETE is false', async () => { ... });
60
+ it('should delete when AUTH0_ALLOW_DELETE is true', async () => { ... });
61
+ });
62
+ ```
63
+
64
+ ## Key Test Utilities
65
+
66
+ - `test/utils.js` — `mockPagedData()`, `buildStateObject()`, and other shared helpers
67
+ - `sinon.stub().resolves(value)` — async stubs
68
+ - `sinon.stub().returns(value)` — synchronous stubs (e.g. paged data iterators)
69
+
70
+ ## What to Cover in Every Handler Test
71
+
72
+ - **Happy path**: normal create, update, delete with `AUTH0_ALLOW_DELETE=true`
73
+ - **No-delete guard**: `AUTH0_ALLOW_DELETE=false` produces zero deletes
74
+ - **Empty input**: empty asset arrays produce zero API calls
75
+ - **Idempotency**: deploy with unchanged config produces zero create/update/delete calls
76
+ - **Error path**: API call failure is surfaced (not swallowed)
77
+ - **Regression**: if fixing a bug, a test that would have caught the original bug
78
+
79
+ ## Verifying Mocks
80
+
81
+ Always confirm the stub shape matches what the real API returns. A test named "should not delete" can pass silently for the wrong reason if the mock is wrong — verify the `sinon.stub()` is actually being called (or not called) via `sinon.assert`.
82
+
83
+ ## E2E Test Requirements
84
+
85
+ > ⚠️ Ask before running — these mutate real tenant state.
86
+
87
+ ```bash
88
+ # Node module E2E (uses HTTP recordings)
89
+ AUTH0_HTTP_RECORDINGS=lockdown npm run test:e2e:node-module
90
+
91
+ # CLI E2E (requires real tenant)
92
+ AUTH0_DOMAIN=<tenant> AUTH0_CLIENT_ID=<id> AUTH0_CLIENT_SECRET=<secret> npm run test:e2e:cli
93
+ ```
94
+
95
+ Use a dedicated development tenant. Never run E2E against a production tenant.
96
+
97
+ ## Configuration Testing
98
+
99
+ When testing resource exclusion and property filtering:
100
+
101
+ ```javascript
102
+ const mockConfig = (key) => {
103
+ const config = {
104
+ AUTH0_ALLOW_DELETE: false,
105
+ AUTH0_EXCLUDED: [], // resource types excluded entirely
106
+ AUTH0_EXCLUDED_CLIENTS: ['my-app'], // named exclusion per resource type
107
+ EXCLUDED_PROPS: { clients: ['description'] }, // properties excluded from comparison
108
+ INCLUDED_PROPS: { clients: ['name', 'app_type'] }, // properties included in comparison
109
+ };
110
+ return config[key];
111
+ };
112
+ ```
113
+
114
+ - `AUTH0_EXCLUDED` — array of resource type strings to skip entirely
115
+ - `AUTH0_EXCLUDED_<TYPE>` — array of resource names to skip within a type
116
+ - `EXCLUDED_PROPS` — per-type list of properties to ignore during diff
117
+ - `INCLUDED_PROPS` — per-type allowlist; when set, only listed properties are compared
118
+ - Test keyword replacement by passing `AUTH0_KEYWORD_REPLACE_MAPPINGS` with a sample mapping and verifying the resolved value in the exported/imported asset