octopize.deploy_tool 2.3.1__tar.gz → 2.4.0__tar.gz

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 (253) hide show
  1. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/PKG-INFO +1 -1
  2. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/pyproject.toml +1 -1
  3. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/__init__.py +1 -1
  4. octopize_deploy_tool-2.4.0/src/octopize_avatar_deploy/steps/email.py +264 -0
  5. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/input.yaml +1 -0
  6. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/input.yaml +1 -0
  7. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/input.yaml +1 -0
  8. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/input.yaml +1 -0
  9. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/prompt_help/input.yaml +1 -0
  10. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/resume_interrupted/input_first_run.yaml +1 -0
  11. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/save_config_with_existing/input.yaml +1 -0
  12. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/integration/test_cli_integration.py +40 -0
  13. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_email.py +152 -3
  14. octopize_deploy_tool-2.3.1/src/octopize_avatar_deploy/steps/email.py +0 -178
  15. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/.gitignore +0 -0
  16. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/README.md +0 -0
  17. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/authentik_migration.py +0 -0
  18. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/cli.py +0 -0
  19. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/cli_test_harness.py +0 -0
  20. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/components.py +0 -0
  21. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/configure.py +0 -0
  22. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/defaults.yaml +0 -0
  23. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/deployment_mode.py +0 -0
  24. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/download_templates.py +0 -0
  25. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/generate_env.py +0 -0
  26. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/generate_env_paths.py +0 -0
  27. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/input_gatherer.py +0 -0
  28. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/output_spec.py +0 -0
  29. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/printer.py +0 -0
  30. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/public_url.py +0 -0
  31. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/state_manager.py +0 -0
  32. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/__init__.py +0 -0
  33. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/api_local_source.py +0 -0
  34. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/authentik.py +0 -0
  35. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/authentik_blueprint.py +0 -0
  36. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/base.py +0 -0
  37. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/component_selection.py +0 -0
  38. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/database.py +0 -0
  39. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/local_source.py +0 -0
  40. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/logging.py +0 -0
  41. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/nginx.py +0 -0
  42. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/required.py +0 -0
  43. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/service_urls.py +0 -0
  44. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/storage.py +0 -0
  45. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/target_environment.py +0 -0
  46. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/telemetry.py +0 -0
  47. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/steps/user.py +0 -0
  48. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/template_provisioning.py +0 -0
  49. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/.env.template +0 -0
  50. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/.template-version +0 -0
  51. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/_env_fragment_api.template +0 -0
  52. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/_env_fragment_infra.template +0 -0
  53. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/_env_fragment_web.template +0 -0
  54. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/api.env.template +0 -0
  55. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/branding/favicon.ico +0 -0
  56. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/branding/logo.png +0 -0
  57. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_account_confirmation.html +0 -0
  58. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_account_exists.html +0 -0
  59. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_account_invitation.html +0 -0
  60. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_forgotten_password.html +0 -0
  61. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_password_changed.html +0 -0
  62. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/custom-templates/email_password_reset.html +0 -0
  63. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/octopize-avatar-blueprint.yaml +0 -0
  64. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/authentik/translations.json +0 -0
  65. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/compose.override.yaml.template +0 -0
  66. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/docker-compose.yml.template +0 -0
  67. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/nginx.conf.template +0 -0
  68. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/python_client.env.template +0 -0
  69. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/templates/web.env.template +0 -0
  70. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/topology_urls.py +0 -0
  71. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/url_contract.py +0 -0
  72. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/src/octopize_avatar_deploy/version_compat.py +0 -0
  73. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/TESTING.md +0 -0
  74. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/__init__.py +0 -0
  75. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/conftest.py +0 -0
  76. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/__init__.py +0 -0
  77. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/authentik_migration/licenses.csv +0 -0
  78. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/authentik_migration/organizations.csv +0 -0
  79. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/authentik_migration/users.csv +0 -0
  80. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/.deployment-state.yaml +0 -0
  81. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/.env +0 -0
  82. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/branding/favicon.ico +0 -0
  83. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/branding/logo.png +0 -0
  84. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  85. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_account_exists.html +0 -0
  86. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  87. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  88. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_password_changed.html +0 -0
  89. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/custom-templates/email_password_reset.html +0 -0
  90. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  91. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/authentik/translations.json +0 -0
  92. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/docker-compose.yml +0 -0
  93. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/expected/nginx/nginx.conf +0 -0
  94. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/basic_deployment/output.txt +0 -0
  95. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/.deployment-state.yaml +0 -0
  96. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/.env +0 -0
  97. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/branding/favicon.ico +0 -0
  98. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/branding/logo.png +0 -0
  99. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  100. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_account_exists.html +0 -0
  101. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  102. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  103. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_password_changed.html +0 -0
  104. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/custom-templates/email_password_reset.html +0 -0
  105. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  106. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/authentik/translations.json +0 -0
  107. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/docker-compose.yml +0 -0
  108. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/expected/nginx/nginx.conf +0 -0
  109. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/cloud_storage/output.txt +0 -0
  110. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_not_found/output.txt +0 -0
  111. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/.deployment-state.yaml +0 -0
  112. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/.env +0 -0
  113. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/branding/favicon.ico +0 -0
  114. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/branding/logo.png +0 -0
  115. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  116. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_account_exists.html +0 -0
  117. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  118. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  119. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_password_changed.html +0 -0
  120. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/custom-templates/email_password_reset.html +0 -0
  121. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  122. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/authentik/translations.json +0 -0
  123. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/deployment-config.yaml +0 -0
  124. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/docker-compose.yml +0 -0
  125. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_first/expected/nginx/nginx.conf +0 -0
  126. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/.deployment-state.yaml +0 -0
  127. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/.env +0 -0
  128. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/branding/favicon.ico +0 -0
  129. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/branding/logo.png +0 -0
  130. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  131. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_account_exists.html +0 -0
  132. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  133. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  134. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_password_changed.html +0 -0
  135. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/custom-templates/email_password_reset.html +0 -0
  136. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  137. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/authentik/translations.json +0 -0
  138. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/docker-compose.yml +0 -0
  139. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/config_round_trip_second/expected/nginx/nginx.conf +0 -0
  140. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/deploy_help/output.txt +0 -0
  141. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/.deployment-state.yaml +0 -0
  142. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/.env +0 -0
  143. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/branding/favicon.ico +0 -0
  144. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/branding/logo.png +0 -0
  145. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  146. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_account_exists.html +0 -0
  147. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  148. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  149. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_password_changed.html +0 -0
  150. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/custom-templates/email_password_reset.html +0 -0
  151. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  152. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/authentik/translations.json +0 -0
  153. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/compose.override.yaml +0 -0
  154. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/docker-compose.yml +0 -0
  155. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/nginx/nginx.conf +0 -0
  156. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/test-.npmrc +0 -0
  157. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/test-avatar-repo/services/api/main.py +0 -0
  158. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/expected/test-avatar-website/package.json +0 -0
  159. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/dev_mode_deployment/output.txt +0 -0
  160. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/generate_env_help/output.txt +0 -0
  161. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/generate_env_output_dir_error/output.txt +0 -0
  162. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/help/output.txt +0 -0
  163. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/invalid_port_config/config.yaml +0 -0
  164. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/invalid_port_config/output.txt +0 -0
  165. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/invalid_url_config/config.yaml +0 -0
  166. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/invalid_url_config/output.txt +0 -0
  167. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/malformed_yaml/config.yaml +0 -0
  168. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/malformed_yaml/output.txt +0 -0
  169. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/missing_subcommand/output.txt +0 -0
  170. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/.deployment-state.yaml +0 -0
  171. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/.env +0 -0
  172. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/branding/favicon.ico +0 -0
  173. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/branding/logo.png +0 -0
  174. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  175. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_account_exists.html +0 -0
  176. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  177. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  178. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_password_changed.html +0 -0
  179. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/custom-templates/email_password_reset.html +0 -0
  180. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  181. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/authentik/translations.json +0 -0
  182. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/docker-compose.yml +0 -0
  183. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/expected/nginx/nginx.conf +0 -0
  184. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/no_telemetry/output.txt +0 -0
  185. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/config.yaml +0 -0
  186. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/.deployment-state.yaml +0 -0
  187. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/.env +0 -0
  188. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/branding/favicon.ico +0 -0
  189. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/branding/logo.png +0 -0
  190. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_account_confirmation.html +0 -0
  191. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_account_exists.html +0 -0
  192. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_account_invitation.html +0 -0
  193. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_forgotten_password.html +0 -0
  194. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_password_changed.html +0 -0
  195. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/custom-templates/email_password_reset.html +0 -0
  196. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/octopize-avatar-blueprint.yaml +0 -0
  197. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/authentik/translations.json +0 -0
  198. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/docker-compose.yml +0 -0
  199. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/expected/nginx/nginx.conf +0 -0
  200. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_complete/output.txt +0 -0
  201. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_incomplete_config/config.yaml +0 -0
  202. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_incomplete_config/output.txt +0 -0
  203. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_no_config/output.txt +0 -0
  204. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_partial_config/config.yaml +0 -0
  205. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/non_interactive_partial_config/output.txt +0 -0
  206. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/output_dir_nested/output.txt +0 -0
  207. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/output_dir_permission_denied/output.txt +0 -0
  208. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/prompt_help/output.txt +0 -0
  209. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/resume_interrupted/first_run/output.txt +0 -0
  210. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/resume_interrupted/input_resume.yaml +0 -0
  211. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/resume_interrupted/resume/output.txt +0 -0
  212. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/save_config_interactive/output.txt +0 -0
  213. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/save_config_with_existing/config.yaml +0 -0
  214. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/save_config_with_existing/output.txt +0 -0
  215. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/template_from_local_verbose/output.txt +0 -0
  216. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/type_mismatch_config/config.yaml +0 -0
  217. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/fixtures/type_mismatch_config/output.txt +0 -0
  218. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/integration/__init__.py +0 -0
  219. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/integration/test_generate_env.py +0 -0
  220. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_api_local_source.py +0 -0
  221. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_authentik.py +0 -0
  222. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_authentik_blueprint.py +0 -0
  223. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_base.py +0 -0
  224. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_component_selection.py +0 -0
  225. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_database.py +0 -0
  226. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_local_source.py +0 -0
  227. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_logging.py +0 -0
  228. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_nginx.py +0 -0
  229. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_required.py +0 -0
  230. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_service_urls.py +0 -0
  231. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_state_manager.py +0 -0
  232. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_storage.py +0 -0
  233. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_target_environment.py +0 -0
  234. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_telemetry.py +0 -0
  235. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_user.py +0 -0
  236. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/steps/test_user_validation.py +0 -0
  237. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/test_cli_harness.py +0 -0
  238. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_authentik_client.py +0 -0
  239. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_authentik_migration.py +0 -0
  240. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_compare_helpers.py +0 -0
  241. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_components.py +0 -0
  242. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_deployment_configurator.py +0 -0
  243. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_deployment_runner.py +0 -0
  244. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_generate_env_cli.py +0 -0
  245. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_generic_prompt.py +0 -0
  246. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_input_gatherer.py +0 -0
  247. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_output_spec.py +0 -0
  248. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_printer.py +0 -0
  249. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_public_url.py +0 -0
  250. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_rich_implementations.py +0 -0
  251. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_step_filtering.py +0 -0
  252. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_topology_urls.py +0 -0
  253. {octopize_deploy_tool-2.3.1 → octopize_deploy_tool-2.4.0}/tests/unit/test_version_validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: octopize.deploy_tool
3
- Version: 2.3.1
3
+ Version: 2.4.0
4
4
  Summary: Deployment configuration tool for Octopize Avatar platform
5
5
  Project-URL: Homepage, https://octopize.io
6
6
  Project-URL: Documentation, https://docs.octopize.io/docs/deploying/self-hosted
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "octopize.deploy_tool"
7
- version = "2.3.1"
7
+ version = "2.4.0"
8
8
  description = "Deployment configuration tool for Octopize Avatar platform"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13"
@@ -11,7 +11,7 @@ from .version_compat import (
11
11
  validate_template_version,
12
12
  )
13
13
 
14
- __version__ = "2.3.1"
14
+ __version__ = "2.4.0"
15
15
  __all__ = [
16
16
  "main",
17
17
  "DeploymentRunner",
@@ -0,0 +1,264 @@
1
+ """Email configuration step."""
2
+
3
+ import ipaddress
4
+ from typing import Any
5
+
6
+ from .base import (
7
+ DefaultKey,
8
+ DeploymentStep,
9
+ PromptConfig,
10
+ ValidationError,
11
+ ValidationSuccess,
12
+ parse_str,
13
+ )
14
+
15
+ # AWS SES SMTP preset – connection settings provided by Octopize.
16
+ # Operators only need to supply the SMTP username and password.
17
+ AWS_SMTP_HOST = "email-smtp.eu-west-3.amazonaws.com"
18
+ AWS_SMTP_PORT = "587"
19
+ AWS_SMTP_USE_TLS = "false"
20
+ AWS_SMTP_START_TLS = "true"
21
+ AWS_SMTP_VERIFY = "true"
22
+ AWS_SMTP_SENDER_EMAIL = "noreply@octopize.io"
23
+
24
+ _AWS_SMTP_HELP = (
25
+ "Choose 'yes' if Octopize provided you with AWS SES SMTP credentials.\n"
26
+ "The tool will prefill the standard host, port, and TLS settings automatically;\n"
27
+ "you will only be asked for the SMTP username and password.\n"
28
+ "\n"
29
+ "Choose 'no' to enter all SMTP connection details manually (any provider)."
30
+ )
31
+
32
+
33
+ def validate_smtp_host(value: str) -> ValidationSuccess[str] | ValidationError:
34
+ """
35
+ Validate that the SMTP host is a hostname or domain name, not a raw IP address.
36
+
37
+ An empty value is allowed (it means SMTP is not yet configured).
38
+
39
+ Args:
40
+ value: The SMTP host value to validate
41
+
42
+ Returns:
43
+ ValidationSuccess with the host string, or ValidationError with a message
44
+ """
45
+ host = str(value).strip()
46
+
47
+ if not host:
48
+ # Empty is allowed — the operator can leave SMTP unconfigured
49
+ return ValidationSuccess(host)
50
+
51
+ # Reject raw IP addresses (both IPv4 and IPv6)
52
+ try:
53
+ ipaddress.ip_address(host)
54
+ return ValidationError(
55
+ f"'{host}' is a raw IP address. "
56
+ "SMTP_HOST must be a hostname or domain name, not an IP address. "
57
+ "Examples: 'smtp.example.com', 'smtp.sendgrid.net', 'mail.example.com'."
58
+ )
59
+ except ValueError:
60
+ pass
61
+
62
+ return ValidationSuccess(host)
63
+
64
+
65
+ class EmailStep(DeploymentStep):
66
+ """Handles email configuration and credentials."""
67
+
68
+ name = "email"
69
+ description = "Configure SMTP email settings and credentials"
70
+
71
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
72
+ super().__init__(*args, **kwargs)
73
+ # Initialised here so generate_secrets() can always reference the attribute
74
+ # without needing getattr(); updated by collect_config() once the operator answers.
75
+ self._use_aws_preset: bool = False
76
+
77
+ def collect_config(self) -> dict[str, Any]:
78
+ """Collect email configuration."""
79
+ config = {}
80
+
81
+ print("\n--- Email Configuration ---")
82
+ self.printer.print(
83
+ "This section configures how the deployment sends outbound emails, mainly "
84
+ "for Authentik account and password workflows.\n"
85
+ "\n"
86
+ "The deployment needs an SMTP server to send emails such as account setup, "
87
+ "password reset, and other authentication-related messages.\n"
88
+ "\n"
89
+ "You can use:\n"
90
+ " - your own SMTP provider or mail server\n"
91
+ " - an SMTP service provided by Octopize, based on AWS\n"
92
+ "\n"
93
+ "If Octopize provides the SMTP service, we will give you the SMTP "
94
+ "credentials. In that case, the tool could eventually prefill the standard "
95
+ "connection settings and only ask you for the username and password we "
96
+ "provide."
97
+ )
98
+
99
+ use_aws = self._resolve_use_aws_smtp()
100
+
101
+ # Store as instance variable so generate_secrets() can check it without
102
+ # persisting the flag to deployment-config.yaml.
103
+ self._use_aws_preset = use_aws
104
+
105
+ if use_aws:
106
+ config["SMTP_HOST"] = AWS_SMTP_HOST
107
+ config["SMTP_PORT"] = AWS_SMTP_PORT
108
+ config["SMTP_USE_TLS"] = AWS_SMTP_USE_TLS
109
+ config["SMTP_START_TLS"] = AWS_SMTP_START_TLS
110
+ config["SMTP_VERIFY"] = AWS_SMTP_VERIFY
111
+ config["SMTP_SENDER_EMAIL"] = AWS_SMTP_SENDER_EMAIL
112
+ else:
113
+ # Manual SMTP configuration
114
+ config["SMTP_HOST"] = self.get_config_or_prompt_generic(
115
+ PromptConfig(
116
+ config_key="SMTP_HOST",
117
+ prompt_message="SMTP host",
118
+ default_value=self.get_default_value("email.smtp.host"),
119
+ prompt_key="email.smtp_host",
120
+ parse_and_validate=validate_smtp_host,
121
+ help_text=(
122
+ "Hostname of the outbound SMTP server used to send emails from the "
123
+ "deployment.\n"
124
+ "\n"
125
+ "Use a mail server hostname or domain name, for example:\n"
126
+ " - smtp.gmail.com\n"
127
+ " - smtp.sendgrid.net\n"
128
+ " - mail.example.com\n"
129
+ "\n"
130
+ "Do not use an IP address here.\n"
131
+ "\n"
132
+ "This SMTP server is used by Authentik to send emails such as account "
133
+ "setup and password reset messages."
134
+ ),
135
+ )
136
+ )
137
+ config["SMTP_PORT"] = self.get_config_or_prompt_generic(
138
+ PromptConfig(
139
+ config_key="SMTP_PORT",
140
+ prompt_message="SMTP port",
141
+ default_value=self.get_default_value("email.smtp.port"),
142
+ prompt_key="email.smtp_port",
143
+ parse_and_validate=parse_str,
144
+ help_text=(
145
+ "TCP port for the SMTP connection.\n"
146
+ "Common values:\n"
147
+ " 587 — STARTTLS (recommended)\n"
148
+ " 465 — TLS/SSL\n"
149
+ " 25 — plain SMTP (often blocked by ISPs)"
150
+ ),
151
+ )
152
+ )
153
+ config["SMTP_USE_TLS"] = self.get_config(
154
+ "SMTP_USE_TLS", DefaultKey("email.smtp.use_tls")
155
+ )
156
+ config["SMTP_START_TLS"] = self.get_config(
157
+ "SMTP_START_TLS", DefaultKey("email.smtp.start_tls")
158
+ )
159
+ config["SMTP_VERIFY"] = self.get_config("SMTP_VERIFY", DefaultKey("email.smtp.verify"))
160
+ config["SMTP_SENDER_EMAIL"] = self.get_config_or_prompt_generic(
161
+ PromptConfig(
162
+ config_key="SMTP_SENDER_EMAIL",
163
+ prompt_message="SMTP sender email",
164
+ default_value=self.get_default_value("email.smtp.sender_email"),
165
+ prompt_key="email.smtp_sender_email",
166
+ help_text=(
167
+ "The From: address used for all outbound emails sent by the deployment.\n"
168
+ "\n"
169
+ "This address must be authorized to send through the configured SMTP "
170
+ "server.\n"
171
+ "\n"
172
+ "In most cases, you should keep the default or the value recommended for "
173
+ "your SMTP setup. Only change it if you have a specific need, for example "
174
+ "if your SMTP provider requires the sender address to be the same as the "
175
+ "SMTP username.\n"
176
+ "\n"
177
+ "Example:\n"
178
+ " - noreply@avatar.example.com"
179
+ ),
180
+ )
181
+ )
182
+
183
+ # Username prompt: required for AWS in interactive mode, optional otherwise.
184
+ if use_aws and self.interactive:
185
+ config["SMTP_USERNAME"] = self.prompt(
186
+ "SMTP username",
187
+ default=None, # Required — AWS SES credentials cannot have an empty username.
188
+ key="email.smtp_username",
189
+ help_text="Username provided by Octopize for AWS SES SMTP authentication.",
190
+ )
191
+ else:
192
+ config["SMTP_USERNAME"] = self.get_config_or_prompt_generic(
193
+ PromptConfig(
194
+ config_key="SMTP_USERNAME",
195
+ prompt_message="SMTP username",
196
+ default_value="",
197
+ prompt_key="email.smtp_username",
198
+ help_text=(
199
+ "Username provided by Octopize for AWS SES SMTP authentication."
200
+ if use_aws
201
+ else (
202
+ "Username for SMTP authentication. Leave blank if your server\n"
203
+ "does not require authentication."
204
+ )
205
+ ),
206
+ )
207
+ )
208
+
209
+ self.config.update(config)
210
+
211
+ return config
212
+
213
+ def _resolve_use_aws_smtp(self) -> bool:
214
+ """Determine whether to use the built-in AWS SMTP preset.
215
+
216
+ In interactive mode the operator is asked explicitly.
217
+ In non-interactive mode, the value is read from ``self.config``
218
+ (key ``USE_AWS_SMTP_PRESET``); it defaults to ``False`` so that
219
+ existing non-interactive deployments are unaffected.
220
+ """
221
+ if self.interactive:
222
+ return self.prompt_yes_no(
223
+ "Use built-in AWS SMTP configuration (provided by Octopize)?",
224
+ default=False,
225
+ key="email.use_aws_smtp",
226
+ help_text=_AWS_SMTP_HELP,
227
+ )
228
+
229
+ raw = self.config.get("USE_AWS_SMTP_PRESET", False)
230
+ if isinstance(raw, bool):
231
+ return raw
232
+ return str(raw).lower() in ("true", "yes", "1", "on", "enabled")
233
+
234
+ def generate_secrets(self) -> dict[str, str]:
235
+ """Generate email-related secrets."""
236
+ secrets_dict = {}
237
+
238
+ if self.interactive:
239
+ if self._use_aws_preset:
240
+ # Password is required for AWS SES — no skip option.
241
+ smtp_password = self.prompt(
242
+ "SMTP password",
243
+ default=None,
244
+ key="email.smtp_password",
245
+ help_text=(
246
+ "Password provided by Octopize for AWS SES SMTP authentication.\n"
247
+ "This value is stored as a generated secret, not in the main config file."
248
+ ),
249
+ )
250
+ else:
251
+ smtp_password = self.prompt(
252
+ "SMTP password (press Enter to skip)",
253
+ default="",
254
+ key="email.smtp_password",
255
+ help_text=(
256
+ "Password for SMTP authentication.\n"
257
+ "\n"
258
+ "Leave blank if your SMTP server does not require a password."
259
+ ),
260
+ )
261
+ if smtp_password:
262
+ secrets_dict["smtp_password"] = smtp_password
263
+
264
+ return secrets_dict
@@ -6,6 +6,7 @@ responses:
6
6
  nginx_tls.ssl_certificate_path: ''
7
7
  nginx_tls.ssl_certificate_key_path: ''
8
8
  authentik.bootstrap_email: admin@example.com
9
+ email.use_aws_smtp: false
9
10
  email.smtp_host: smtp.example.com
10
11
  email.smtp_port: '587'
11
12
  email.smtp_sender_email: noreply@example.com
@@ -6,6 +6,7 @@ responses:
6
6
  nginx_tls.ssl_certificate_path: ''
7
7
  nginx_tls.ssl_certificate_key_path: ''
8
8
  authentik.bootstrap_email: admin@cloud.example.com
9
+ email.use_aws_smtp: false
9
10
  email.smtp_host: smtp.cloud.com
10
11
  email.smtp_port: '587'
11
12
  email.smtp_sender_email: noreply@cloud.example.com
@@ -6,6 +6,7 @@ responses:
6
6
  nginx_tls.ssl_certificate_path: ''
7
7
  nginx_tls.ssl_certificate_key_path: ''
8
8
  authentik.bootstrap_email: dev@example.com
9
+ email.use_aws_smtp: false
9
10
  email.smtp_host: smtp.example.com
10
11
  email.smtp_port: '587'
11
12
  email.smtp_sender_email: dev@example.com
@@ -6,6 +6,7 @@ responses:
6
6
  nginx_tls.ssl_certificate_path: ''
7
7
  nginx_tls.ssl_certificate_key_path: ''
8
8
  authentik.bootstrap_email: admin@internal.com
9
+ email.use_aws_smtp: false
9
10
  email.smtp_host: smtp.internal.com
10
11
  email.smtp_port: '587'
11
12
  email.smtp_sender_email: noreply@internal.com
@@ -11,6 +11,7 @@ responses:
11
11
  nginx_tls.ssl_certificate_path: ''
12
12
  nginx_tls.ssl_certificate_key_path: ''
13
13
  authentik.bootstrap_email: admin@example.com
14
+ email.use_aws_smtp: false
14
15
  email.smtp_host:
15
16
  - '?'
16
17
  - smtp.example.com
@@ -6,6 +6,7 @@ responses:
6
6
  nginx_tls.ssl_certificate_path: smtp
7
7
  nginx_tls.ssl_certificate_key_path: smtp.example.com
8
8
  authentik.bootstrap_email: '587'
9
+ email.use_aws_smtp: false
9
10
  email.smtp_host: smtp.example.com
10
11
  email.smtp_port: '587'
11
12
  email.smtp_sender_email: noreply@example.com
@@ -3,6 +3,7 @@ responses:
3
3
  nginx_tls.ssl_certificate_path: ''
4
4
  nginx_tls.ssl_certificate_key_path: ''
5
5
  authentik.bootstrap_email: admin@existing.com
6
+ email.use_aws_smtp: false
6
7
  email.smtp_host: smtp.existing.com
7
8
  email.smtp_port: '587'
8
9
  email.smtp_sender_email: noreply@existing.com
@@ -373,6 +373,46 @@ class TestCLIDeploymentScenarios:
373
373
  # Verify no Jinja2 placeholders remain
374
374
  assert "{{ BLUEPRINT_" not in blueprint_content
375
375
 
376
+ def test_aws_smtp_preset_dialog_values(self, temp_deployment_dir, log_file):
377
+ """End-to-end test: AWS SMTP preset populates all connection fields from constants."""
378
+ responses = {
379
+ **fixture_manager.load_input_fixture("basic_deployment"),
380
+ # Override email section: select the AWS preset, supply credentials.
381
+ "email.use_aws_smtp": True,
382
+ "email.smtp_username": "AKIAIOSFODNN7EXAMPLE",
383
+ "email.smtp_password": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
384
+ }
385
+
386
+ harness = _create_deploy_harness(
387
+ responses=responses,
388
+ output_dir=temp_deployment_dir,
389
+ log_file=log_file,
390
+ )
391
+ exit_code = harness.run()
392
+
393
+ assert exit_code == 0
394
+
395
+ # Verify generated deployment state reflects AWS preset constants.
396
+ state_file = temp_deployment_dir / ".deployment-state.yaml"
397
+ assert state_file.exists()
398
+ with open(state_file) as f:
399
+ state = yaml.safe_load(f)
400
+
401
+ config = state["config"]
402
+ assert config["SMTP_HOST"] == "email-smtp.eu-west-3.amazonaws.com"
403
+ assert config["SMTP_PORT"] == "587"
404
+ assert config["SMTP_USE_TLS"] == "false"
405
+ assert config["SMTP_START_TLS"] == "true"
406
+ assert config["SMTP_VERIFY"] == "true"
407
+ assert config["SMTP_SENDER_EMAIL"] == "noreply@octopize.io"
408
+ assert config["SMTP_USERNAME"] == "AKIAIOSFODNN7EXAMPLE"
409
+
410
+ # Password should be stored as a secret, not in the main config.
411
+ assert "SMTP_PASSWORD" not in config
412
+ smtp_secret = temp_deployment_dir / ".secrets" / "smtp_password"
413
+ assert smtp_secret.exists()
414
+ assert smtp_secret.read_text().strip() == "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
415
+
376
416
 
377
417
  class TestCLINonInteractiveMode:
378
418
  """Test non-interactive mode."""
@@ -6,7 +6,15 @@ import pytest
6
6
  from octopize_avatar_deploy.input_gatherer import MockInputGatherer
7
7
  from octopize_avatar_deploy.steps import EmailStep
8
8
  from octopize_avatar_deploy.steps.base import ValidationError, ValidationSuccess
9
- from octopize_avatar_deploy.steps.email import validate_smtp_host
9
+ from octopize_avatar_deploy.steps.email import (
10
+ AWS_SMTP_HOST,
11
+ AWS_SMTP_PORT,
12
+ AWS_SMTP_SENDER_EMAIL,
13
+ AWS_SMTP_START_TLS,
14
+ AWS_SMTP_USE_TLS,
15
+ AWS_SMTP_VERIFY,
16
+ validate_smtp_host,
17
+ )
10
18
 
11
19
 
12
20
  class TestValidateSmtpHost:
@@ -147,6 +155,7 @@ class TestEmailStep:
147
155
  ):
148
156
  """Test SMTP username is prompted even when sender email uses its default."""
149
157
  responses = {
158
+ "email.use_aws_smtp": False,
150
159
  "email.smtp_host": "",
151
160
  "email.smtp_port": "",
152
161
  "email.smtp_sender_email": "",
@@ -168,6 +177,7 @@ class TestEmailStep:
168
177
  def test_collect_config_allows_empty_username(self, tmp_path, defaults_smtp):
169
178
  """Test SMTP username can be skipped when the provider does not require auth."""
170
179
  responses = {
180
+ "email.use_aws_smtp": False,
171
181
  "email.smtp_host": "",
172
182
  "email.smtp_port": "",
173
183
  "email.smtp_sender_email": "",
@@ -186,6 +196,144 @@ class TestEmailStep:
186
196
  assert config["SMTP_SENDER_EMAIL"] == "noreply@example.com"
187
197
  assert config["SMTP_USERNAME"] == ""
188
198
 
199
+ # --- AWS SMTP preset tests ---
200
+
201
+ def test_collect_config_aws_preset_interactive(self, tmp_path, defaults_smtp):
202
+ """Test built-in AWS SMTP preset prefills connection settings."""
203
+ responses = {
204
+ "email.use_aws_smtp": True,
205
+ "email.smtp_username": "AKIAIOSFODNN7EXAMPLE",
206
+ "email.smtp_password": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
207
+ }
208
+ step = EmailStep(
209
+ tmp_path,
210
+ defaults_smtp,
211
+ {},
212
+ interactive=True,
213
+ input_gatherer=MockInputGatherer(responses),
214
+ )
215
+
216
+ config = step.collect_config()
217
+ secrets = step.generate_secrets()
218
+
219
+ assert config["SMTP_HOST"] == AWS_SMTP_HOST
220
+ assert config["SMTP_PORT"] == AWS_SMTP_PORT
221
+ assert config["SMTP_USE_TLS"] == AWS_SMTP_USE_TLS
222
+ assert config["SMTP_START_TLS"] == AWS_SMTP_START_TLS
223
+ assert config["SMTP_VERIFY"] == AWS_SMTP_VERIFY
224
+ assert config["SMTP_SENDER_EMAIL"] == AWS_SMTP_SENDER_EMAIL
225
+ assert config["SMTP_USERNAME"] == "AKIAIOSFODNN7EXAMPLE"
226
+ assert secrets["smtp_password"] == "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
227
+
228
+ def test_collect_config_aws_preset_does_not_prompt_connection_fields(
229
+ self, tmp_path, defaults_smtp
230
+ ):
231
+ """Test AWS preset path skips prompts for host/port/sender/TLS settings."""
232
+ # Only use_aws_smtp, smtp_username, and smtp_password keys are consumed;
233
+ # any extra key would cause MockInputGatherer to raise if unexpectedly consumed.
234
+ responses = {
235
+ "email.use_aws_smtp": True,
236
+ "email.smtp_username": "AKIAIOSFODNN7EXAMPLE",
237
+ "email.smtp_password": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
238
+ }
239
+ step = EmailStep(
240
+ tmp_path,
241
+ defaults_smtp,
242
+ {},
243
+ interactive=True,
244
+ input_gatherer=MockInputGatherer(responses),
245
+ )
246
+
247
+ # Should complete without consuming host/port/sender_email keys
248
+ config = step.collect_config()
249
+ secrets = step.generate_secrets()
250
+
251
+ assert config["SMTP_HOST"] == AWS_SMTP_HOST
252
+ assert config["SMTP_SENDER_EMAIL"] == AWS_SMTP_SENDER_EMAIL
253
+ assert "smtp_password" in secrets
254
+
255
+ def test_collect_config_aws_preset_non_interactive(self, tmp_path, defaults_smtp):
256
+ """Test AWS preset is activated via USE_AWS_SMTP_PRESET config key."""
257
+ config = {"USE_AWS_SMTP_PRESET": True}
258
+ step = EmailStep(tmp_path, defaults_smtp, config, interactive=False)
259
+
260
+ result = step.collect_config()
261
+
262
+ assert result["SMTP_HOST"] == AWS_SMTP_HOST
263
+ assert result["SMTP_PORT"] == AWS_SMTP_PORT
264
+ assert result["SMTP_USE_TLS"] == AWS_SMTP_USE_TLS
265
+ assert result["SMTP_START_TLS"] == AWS_SMTP_START_TLS
266
+ assert result["SMTP_VERIFY"] == AWS_SMTP_VERIFY
267
+ assert result["SMTP_SENDER_EMAIL"] == AWS_SMTP_SENDER_EMAIL
268
+
269
+ def test_aws_preset_requires_password_non_skippable(self, tmp_path, defaults_smtp):
270
+ """Test that the AWS preset prompts password as required (no skip option)."""
271
+ responses = {
272
+ "email.use_aws_smtp": True,
273
+ "email.smtp_username": "AKIAIOSFODNN7EXAMPLE",
274
+ "email.smtp_password": "secret-password",
275
+ }
276
+ step = EmailStep(
277
+ tmp_path,
278
+ defaults_smtp,
279
+ {},
280
+ interactive=True,
281
+ input_gatherer=MockInputGatherer(responses),
282
+ )
283
+
284
+ step.collect_config()
285
+ secrets = step.generate_secrets()
286
+
287
+ # Password must always be present for AWS — not skippable.
288
+ assert "smtp_password" in secrets
289
+ assert secrets["smtp_password"] == "secret-password"
290
+
291
+ def test_manual_path_password_is_optional(self, tmp_path, defaults_smtp):
292
+ """Test that the manual SMTP path leaves password optional (skippable)."""
293
+ responses = {
294
+ "email.use_aws_smtp": False,
295
+ "email.smtp_host": "",
296
+ "email.smtp_port": "",
297
+ "email.smtp_sender_email": "",
298
+ "email.smtp_username": "",
299
+ "email.smtp_password": "", # Operator presses Enter to skip
300
+ }
301
+ step = EmailStep(
302
+ tmp_path,
303
+ defaults_smtp,
304
+ {},
305
+ interactive=True,
306
+ input_gatherer=MockInputGatherer(responses),
307
+ )
308
+
309
+ step.collect_config()
310
+ secrets = step.generate_secrets()
311
+
312
+ # No password stored when operator skips.
313
+ assert "smtp_password" not in secrets
314
+
315
+ def test_collect_config_aws_preset_false_non_interactive_uses_defaults(
316
+ self, tmp_path, defaults_smtp
317
+ ):
318
+ """Test that USE_AWS_SMTP_PRESET=False keeps the manual defaults path."""
319
+ config = {"USE_AWS_SMTP_PRESET": False}
320
+ step = EmailStep(tmp_path, defaults_smtp, config, interactive=False)
321
+
322
+ result = step.collect_config()
323
+
324
+ assert result["SMTP_HOST"] == "smtp.example.com"
325
+
326
+ def test_collect_config_aws_preset_accepts_truthy_strings_non_interactive(
327
+ self, tmp_path, defaults_smtp
328
+ ):
329
+ """Test USE_AWS_SMTP_PRESET accepts truthy string values."""
330
+ config = {"USE_AWS_SMTP_PRESET": "true"}
331
+ step = EmailStep(tmp_path, defaults_smtp, config, interactive=False)
332
+
333
+ result = step.collect_config()
334
+
335
+ assert result["SMTP_HOST"] == AWS_SMTP_HOST
336
+
189
337
  def test_generate_secrets_non_interactive(self, step_smtp):
190
338
  """Test secret generation in non-interactive mode."""
191
339
  step_smtp.collect_config()
@@ -232,8 +380,9 @@ class TestEmailStep:
232
380
  ):
233
381
  """Test that an IP address is rejected interactively and re-prompt accepts hostname."""
234
382
  responses = [
235
- "10.0.0.1", # First: invalid IP address - rejected
236
- "smtp.example.com", # Second: valid hostname - accepted
383
+ "n", # use_aws_smtp: choose manual path
384
+ "10.0.0.1", # smtp_host: invalid IP address - rejected
385
+ "smtp.example.com", # smtp_host: valid hostname - accepted
237
386
  "", # smtp_port (use default)
238
387
  "", # smtp_sender_email (use default)
239
388
  "", # smtp_username (use default)