uffizzi_core 0.1.3

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 (240) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +46 -0
  4. data/Rakefile +31 -0
  5. data/app/assets/config/uffizzi_core_manifest.js +1 -0
  6. data/app/assets/stylesheets/uffizzi_core/application.css +15 -0
  7. data/app/clients/uffizzi_core/amazon_registry_client.rb +18 -0
  8. data/app/clients/uffizzi_core/azure_registry_client/request_result.rb +5 -0
  9. data/app/clients/uffizzi_core/azure_registry_client.rb +42 -0
  10. data/app/clients/uffizzi_core/controller_client/request_result.rb +5 -0
  11. data/app/clients/uffizzi_core/controller_client.rb +106 -0
  12. data/app/clients/uffizzi_core/docker_hub_client/request_result.rb +7 -0
  13. data/app/clients/uffizzi_core/docker_hub_client.rb +139 -0
  14. data/app/clients/uffizzi_core/github/app_client.rb +19 -0
  15. data/app/clients/uffizzi_core/github/installation_client.rb +11 -0
  16. data/app/clients/uffizzi_core/github/user_client.rb +51 -0
  17. data/app/clients/uffizzi_core/google_registry_client/request_result.rb +5 -0
  18. data/app/clients/uffizzi_core/google_registry_client.rb +42 -0
  19. data/app/contexts/uffizzi_core/base_context.rb +12 -0
  20. data/app/contexts/uffizzi_core/project_context.rb +13 -0
  21. data/app/contexts/uffizzi_core/webhooks_context.rb +9 -0
  22. data/app/controllers/concerns/uffizzi_core/auth_management.rb +23 -0
  23. data/app/controllers/concerns/uffizzi_core/authorization_concern.rb +38 -0
  24. data/app/controllers/concerns/uffizzi_core/dependency_injection_concern.rb +19 -0
  25. data/app/controllers/uffizzi_core/api/cli/v1/account/application_controller.rb +7 -0
  26. data/app/controllers/uffizzi_core/api/cli/v1/account/credentials_controller.rb +55 -0
  27. data/app/controllers/uffizzi_core/api/cli/v1/application_controller.rb +5 -0
  28. data/app/controllers/uffizzi_core/api/cli/v1/projects/application_controller.rb +11 -0
  29. data/app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb +93 -0
  30. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/activity_items_controller.rb +36 -0
  31. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb +7 -0
  32. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/application_controller.rb +8 -0
  33. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers/logs_controller.rb +27 -0
  34. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/containers_controller.rb +24 -0
  35. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/events_controller.rb +29 -0
  36. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +148 -0
  37. data/app/controllers/uffizzi_core/api/cli/v1/projects/secrets_controller.rb +69 -0
  38. data/app/controllers/uffizzi_core/api/cli/v1/projects_controller.rb +19 -0
  39. data/app/controllers/uffizzi_core/api/cli/v1/sessions_controller.rb +43 -0
  40. data/app/controllers/uffizzi_core/application_controller.rb +51 -0
  41. data/app/errors/uffizzi_core/compose_file/build_error.rb +4 -0
  42. data/app/errors/uffizzi_core/compose_file/credential_error.rb +4 -0
  43. data/app/errors/uffizzi_core/compose_file/not_found_error.rb +4 -0
  44. data/app/errors/uffizzi_core/compose_file/parse_error.rb +4 -0
  45. data/app/errors/uffizzi_core/compose_file/secrets_error.rb +4 -0
  46. data/app/errors/uffizzi_core/deployment_not_found_error.rb +10 -0
  47. data/app/forms/uffizzi_core/api/cli/v1/account/credential/create_form.rb +26 -0
  48. data/app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb +21 -0
  49. data/app/forms/uffizzi_core/api/cli/v1/compose_file/cli_form.rb +39 -0
  50. data/app/forms/uffizzi_core/api/cli/v1/compose_file/create_form.rb +13 -0
  51. data/app/forms/uffizzi_core/api/cli/v1/compose_file/template_form.rb +44 -0
  52. data/app/forms/uffizzi_core/api/cli/v1/compose_file/update_form.rb +9 -0
  53. data/app/forms/uffizzi_core/api/cli/v1/config_file/create_form.rb +11 -0
  54. data/app/forms/uffizzi_core/api/cli/v1/deployment/create_form.rb +91 -0
  55. data/app/forms/uffizzi_core/api/cli/v1/project/delete_secret_form.rb +27 -0
  56. data/app/forms/uffizzi_core/api/cli/v1/project/update_form.rb +40 -0
  57. data/app/forms/uffizzi_core/api/cli/v1/session_create_form.rb +29 -0
  58. data/app/forms/uffizzi_core/api/cli/v1/template/create_form.rb +65 -0
  59. data/app/forms/uffizzi_core/application_form.rb +11 -0
  60. data/app/forms/uffizzi_core/application_form_without_active_record.rb +17 -0
  61. data/app/forms/uffizzi_core/mass_assignment_control_concern.rb +22 -0
  62. data/app/helpers/uffizzi_core/application_helper.rb +6 -0
  63. data/app/jobs/uffizzi_core/account/create_credential_job.rb +10 -0
  64. data/app/jobs/uffizzi_core/activity_item/docker/update_digest_job.rb +11 -0
  65. data/app/jobs/uffizzi_core/application_job.rb +7 -0
  66. data/app/jobs/uffizzi_core/config_file/apply_job.rb +31 -0
  67. data/app/jobs/uffizzi_core/credential/docker_hub/create_webhook_job.rb +15 -0
  68. data/app/jobs/uffizzi_core/deployment/create_credential_job.rb +32 -0
  69. data/app/jobs/uffizzi_core/deployment/create_credentials_job.rb +17 -0
  70. data/app/jobs/uffizzi_core/deployment/create_job.rb +15 -0
  71. data/app/jobs/uffizzi_core/deployment/create_webhooks_job.rb +13 -0
  72. data/app/jobs/uffizzi_core/deployment/delete_credential_job.rb +13 -0
  73. data/app/jobs/uffizzi_core/deployment/delete_job.rb +11 -0
  74. data/app/jobs/uffizzi_core/deployment/deploy_containers_job.rb +27 -0
  75. data/app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb +19 -0
  76. data/app/jobs/uffizzi_core/deployment/send_github_preview_message_job.rb +13 -0
  77. data/app/lib/uffizzi_core/rbac/user_access_service.rb +21 -0
  78. data/app/mailers/uffizzi_core/application_mailer.rb +8 -0
  79. data/app/models/concerns/uffizzi_core/hashid_concern.rb +25 -0
  80. data/app/models/concerns/uffizzi_core/state_machine_concern.rb +16 -0
  81. data/app/models/uffizzi_core/account.rb +101 -0
  82. data/app/models/uffizzi_core/activity_item/docker.rb +4 -0
  83. data/app/models/uffizzi_core/activity_item/github.rb +4 -0
  84. data/app/models/uffizzi_core/activity_item/memory_limit.rb +4 -0
  85. data/app/models/uffizzi_core/activity_item.rb +58 -0
  86. data/app/models/uffizzi_core/application_record.rb +7 -0
  87. data/app/models/uffizzi_core/build.rb +39 -0
  88. data/app/models/uffizzi_core/comment.rb +16 -0
  89. data/app/models/uffizzi_core/compose_file.rb +57 -0
  90. data/app/models/uffizzi_core/config_file.rb +24 -0
  91. data/app/models/uffizzi_core/container.rb +100 -0
  92. data/app/models/uffizzi_core/container_config_file.rb +8 -0
  93. data/app/models/uffizzi_core/continuous_preview.rb +4 -0
  94. data/app/models/uffizzi_core/coupon.rb +5 -0
  95. data/app/models/uffizzi_core/credential/amazon.rb +4 -0
  96. data/app/models/uffizzi_core/credential/azure.rb +4 -0
  97. data/app/models/uffizzi_core/credential/docker_hub.rb +4 -0
  98. data/app/models/uffizzi_core/credential/github.rb +4 -0
  99. data/app/models/uffizzi_core/credential/google.rb +4 -0
  100. data/app/models/uffizzi_core/credential.rb +64 -0
  101. data/app/models/uffizzi_core/database.rb +4 -0
  102. data/app/models/uffizzi_core/database_offering.rb +4 -0
  103. data/app/models/uffizzi_core/deployment.rb +77 -0
  104. data/app/models/uffizzi_core/event.rb +13 -0
  105. data/app/models/uffizzi_core/invitation.rb +27 -0
  106. data/app/models/uffizzi_core/membership.rb +16 -0
  107. data/app/models/uffizzi_core/payment.rb +11 -0
  108. data/app/models/uffizzi_core/price.rb +9 -0
  109. data/app/models/uffizzi_core/product.rb +11 -0
  110. data/app/models/uffizzi_core/project.rb +66 -0
  111. data/app/models/uffizzi_core/rating.rb +20 -0
  112. data/app/models/uffizzi_core/repo/amazon.rb +4 -0
  113. data/app/models/uffizzi_core/repo/azure.rb +4 -0
  114. data/app/models/uffizzi_core/repo/docker_hub.rb +4 -0
  115. data/app/models/uffizzi_core/repo/github.rb +4 -0
  116. data/app/models/uffizzi_core/repo/google.rb +4 -0
  117. data/app/models/uffizzi_core/repo.rb +39 -0
  118. data/app/models/uffizzi_core/role.rb +17 -0
  119. data/app/models/uffizzi_core/template.rb +19 -0
  120. data/app/models/uffizzi_core/user.rb +62 -0
  121. data/app/models/uffizzi_core/user_project.rb +14 -0
  122. data/app/policies/uffizzi_core/api/cli/v1/account/credentials_policy.rb +11 -0
  123. data/app/policies/uffizzi_core/api/cli/v1/projects/compose_files_policy.rb +15 -0
  124. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/activity_items_policy.rb +7 -0
  125. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/containers_policy.rb +7 -0
  126. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments/events_policy.rb +7 -0
  127. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments_policy.rb +23 -0
  128. data/app/policies/uffizzi_core/api/cli/v1/projects/secrets_policy.rb +15 -0
  129. data/app/policies/uffizzi_core/api/cli/v1/projects_policy.rb +7 -0
  130. data/app/policies/uffizzi_core/application_policy.rb +12 -0
  131. data/app/repositories/uffizzi_core/activity_item_repo.rb +9 -0
  132. data/app/repositories/uffizzi_core/basic_order_repo.rb +11 -0
  133. data/app/repositories/uffizzi_core/build_repo.rb +23 -0
  134. data/app/repositories/uffizzi_core/comment_repo.rb +11 -0
  135. data/app/repositories/uffizzi_core/compose_file_repo.rb +11 -0
  136. data/app/repositories/uffizzi_core/config_file_repo.rb +40 -0
  137. data/app/repositories/uffizzi_core/container_repo.rb +25 -0
  138. data/app/repositories/uffizzi_core/credential_repo.rb +36 -0
  139. data/app/repositories/uffizzi_core/deployment_repo.rb +23 -0
  140. data/app/repositories/uffizzi_core/event_repo.rb +9 -0
  141. data/app/repositories/uffizzi_core/membership_repo.rb +10 -0
  142. data/app/repositories/uffizzi_core/price_repo.rb +11 -0
  143. data/app/repositories/uffizzi_core/product_repo.rb +11 -0
  144. data/app/repositories/uffizzi_core/project_repo.rb +10 -0
  145. data/app/repositories/uffizzi_core/repo_repo.rb +10 -0
  146. data/app/repositories/uffizzi_core/template_repo.rb +87 -0
  147. data/app/repositories/uffizzi_core/usage_repo.rb +9 -0
  148. data/app/repositories/uffizzi_core/user_repo.rb +11 -0
  149. data/app/responders/uffizzi_core/json_responder.rb +13 -0
  150. data/app/serializers/uffizzi_core/api/cli/v1/account/credential_serializer.rb +9 -0
  151. data/app/serializers/uffizzi_core/api/cli/v1/project_serializer.rb +7 -0
  152. data/app/serializers/uffizzi_core/api/cli/v1/projects/compose_file_serializer.rb +7 -0
  153. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +23 -0
  154. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/user_serializer.rb +11 -0
  155. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer.rb +74 -0
  156. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/activity_item_serializer.rb +24 -0
  157. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer/config_file_serializer.rb +6 -0
  158. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer/container_config_file_serializer.rb +7 -0
  159. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployments/container_serializer.rb +30 -0
  160. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer/account_serializer.rb +5 -0
  161. data/app/serializers/uffizzi_core/api/cli/v1/user_serializer.rb +7 -0
  162. data/app/serializers/uffizzi_core/base_serializer.rb +7 -0
  163. data/app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb +17 -0
  164. data/app/serializers/uffizzi_core/controller/create_deployment/deployment_serializer.rb +5 -0
  165. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +53 -0
  166. data/app/serializers/uffizzi_core/controller/deploy_containers/credential_serializer.rb +5 -0
  167. data/app/services/uffizzi_core/account_service.rb +21 -0
  168. data/app/services/uffizzi_core/activity_item_service.rb +98 -0
  169. data/app/services/uffizzi_core/amazon/credential_service.rb +31 -0
  170. data/app/services/uffizzi_core/amazon_service.rb +45 -0
  171. data/app/services/uffizzi_core/azure/credential_service.rb +18 -0
  172. data/app/services/uffizzi_core/cli/compose_file_service.rb +203 -0
  173. data/app/services/uffizzi_core/compose_file/builders/config_files_builder_service.rb +31 -0
  174. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +225 -0
  175. data/app/services/uffizzi_core/compose_file/builders/docker_repo_builder_service.rb +25 -0
  176. data/app/services/uffizzi_core/compose_file/builders/github_repo_builder_service.rb +59 -0
  177. data/app/services/uffizzi_core/compose_file/builders/template_builder_service.rb +45 -0
  178. data/app/services/uffizzi_core/compose_file/builders/variables_builder_service.rb +58 -0
  179. data/app/services/uffizzi_core/compose_file/config_files_service.rb +52 -0
  180. data/app/services/uffizzi_core/compose_file/config_option_service.rb +37 -0
  181. data/app/services/uffizzi_core/compose_file/configs_options_service.rb +26 -0
  182. data/app/services/uffizzi_core/compose_file/container_service.rb +64 -0
  183. data/app/services/uffizzi_core/compose_file/continuous_preview_options_service.rb +57 -0
  184. data/app/services/uffizzi_core/compose_file/dependencies_service.rb +55 -0
  185. data/app/services/uffizzi_core/compose_file/errors_service.rb +46 -0
  186. data/app/services/uffizzi_core/compose_file/github_dependencies_service.rb +38 -0
  187. data/app/services/uffizzi_core/compose_file/ingress_options_service.rb +49 -0
  188. data/app/services/uffizzi_core/compose_file/secrets_options_service.rb +28 -0
  189. data/app/services/uffizzi_core/compose_file/services_options/build_service.rb +93 -0
  190. data/app/services/uffizzi_core/compose_file/services_options/command_service.rb +18 -0
  191. data/app/services/uffizzi_core/compose_file/services_options/configs_service.rb +51 -0
  192. data/app/services/uffizzi_core/compose_file/services_options/deploy_service.rb +44 -0
  193. data/app/services/uffizzi_core/compose_file/services_options/entrypoint_service.rb +18 -0
  194. data/app/services/uffizzi_core/compose_file/services_options/env_file_service.rb +34 -0
  195. data/app/services/uffizzi_core/compose_file/services_options/environment_service.rb +20 -0
  196. data/app/services/uffizzi_core/compose_file/services_options/image_service.rb +89 -0
  197. data/app/services/uffizzi_core/compose_file/services_options/secrets_service.rb +35 -0
  198. data/app/services/uffizzi_core/compose_file/services_options_service.rb +55 -0
  199. data/app/services/uffizzi_core/compose_file/template_service.rb +55 -0
  200. data/app/services/uffizzi_core/compose_file/update_service.rb +29 -0
  201. data/app/services/uffizzi_core/compose_file/variables_service.rb +25 -0
  202. data/app/services/uffizzi_core/compose_file_service.rb +33 -0
  203. data/app/services/uffizzi_core/container_service.rb +57 -0
  204. data/app/services/uffizzi_core/controller_service.rb +80 -0
  205. data/app/services/uffizzi_core/credential_service.rb +44 -0
  206. data/app/services/uffizzi_core/deployment_service.rb +274 -0
  207. data/app/services/uffizzi_core/docker_hub/credential_service.rb +15 -0
  208. data/app/services/uffizzi_core/docker_hub_service.rb +77 -0
  209. data/app/services/uffizzi_core/github/app_service.rb +51 -0
  210. data/app/services/uffizzi_core/github/credential_service.rb +124 -0
  211. data/app/services/uffizzi_core/github/message_service.rb +20 -0
  212. data/app/services/uffizzi_core/github_service.rb +28 -0
  213. data/app/services/uffizzi_core/google/credential_service.rb +18 -0
  214. data/app/services/uffizzi_core/logs_service.rb +33 -0
  215. data/app/services/uffizzi_core/manage_activity_items_service.rb +166 -0
  216. data/app/services/uffizzi_core/project_service.rb +38 -0
  217. data/app/services/uffizzi_core/repo_service.rb +178 -0
  218. data/app/services/uffizzi_core/response_service.rb +13 -0
  219. data/app/services/uffizzi_core/template_service.rb +21 -0
  220. data/app/services/uffizzi_core/token_service.rb +19 -0
  221. data/app/services/uffizzi_core/user_access_service.rb +14 -0
  222. data/app/utils/uffizzi_core/converters.rb +33 -0
  223. data/app/validators/uffizzi_core/email_validator.rb +9 -0
  224. data/app/validators/uffizzi_core/environment_variable_list_validator.rb +15 -0
  225. data/app/validators/uffizzi_core/image_command_args_validator.rb +21 -0
  226. data/config/initializers/rswag_api.rb +15 -0
  227. data/config/initializers/rswag_ui.rb +15 -0
  228. data/config/initializers/swagger_yard.rb +17 -0
  229. data/config/locales/en.activerecord.yml +18 -0
  230. data/config/locales/en.yml +61 -0
  231. data/config/routes.rb +55 -0
  232. data/db/migrate/20220218121438_create_uffizzi_core_tables.rb +375 -0
  233. data/db/migrate/20220325113342_add_name_to_uffizzi_containers.rb +7 -0
  234. data/db/seeds.rb +16 -0
  235. data/lib/tasks/uffizzi_core_tasks.rake +14 -0
  236. data/lib/uffizzi_core/engine.rb +15 -0
  237. data/lib/uffizzi_core/version.rb +5 -0
  238. data/lib/uffizzi_core.rb +60 -0
  239. data/swagger/v1/swagger.json +1278 -0
  240. metadata +935 -0
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @resource Project/Secrets
4
+ class UffizziCore::Api::Cli::V1::Projects::SecretsController < UffizziCore::Api::Cli::V1::Projects::ApplicationController
5
+ before_action :authorize_uffizzi_core_api_cli_v1_projects_secrets
6
+
7
+ # Get secrets for the project
8
+ #
9
+ # @path [GET] /api/cli/v1/projects/{project_slug}/secrets
10
+ # @parameter project_slug(required,path) [string]
11
+ # @response [object<secrets: Array<object<name: string>> >] 200 OK
12
+ # @response 401 Not authorized
13
+ def index
14
+ project_secrets = resource_project.secrets.present? ? resource_project.secrets : []
15
+ secrets = project_secrets.map { |secret| { name: secret['name'] } }
16
+
17
+ render json: { secrets: secrets }, status: :ok
18
+ end
19
+
20
+ # Add secret to project
21
+ #
22
+ # @path [POST] /api/cli/v1/projects/{project_slug}/secrets/bulk_create
23
+ # @parameter project_slug(required,path) [string]
24
+ # @parameter secrets(required,body) [object<secrets: Array<object <name: string, value: string>>>]
25
+ # @response [object<secrets: Array<object<name: string>>>] 201 Created
26
+ # @response 422 A compose file already exists for this project
27
+ # @response 401 Not authorized
28
+ def bulk_create
29
+ project_form = resource_project.becomes(UffizziCore::Api::Cli::V1::Project::UpdateForm)
30
+ project_form.assign_secrets!(secrets_params)
31
+ return render json: { errors: project_form.errors }, status: :unprocessable_entity unless project_form.save
32
+
33
+ UffizziCore::ProjectService.update_compose_secrets(project_form)
34
+ secrets = project_form.secrets.map { |secret| { name: secret['name'] } }
35
+
36
+ render json: { secrets: secrets }, status: :created
37
+ end
38
+
39
+ # Delete a secret from project by secret id
40
+ #
41
+ # @path [DELETE] /api/cli/v1/projects/{project_slug}/secrets/{id}
42
+ # @parameter project_slug(required,path) [string]
43
+ # @response [Project] 200 OK
44
+ # @response 422
45
+ # @response 401 Not authorized
46
+ def destroy
47
+ secret_name = CGI.unescape(params[:id])
48
+ secret = OpenStruct.new(name: secret_name)
49
+ project_form = resource_project.becomes(UffizziCore::Api::Cli::V1::Project::DeleteSecretForm)
50
+ project_form.secret = secret
51
+
52
+ if project_form.invalid?
53
+ return respond_with project_form
54
+ end
55
+
56
+ project_form.delete_secret!
57
+ if project_form.save!(validate: false)
58
+ UffizziCore::ProjectService.update_compose_secret_errors(project_form, secret)
59
+ end
60
+
61
+ respond_with project_form
62
+ end
63
+
64
+ private
65
+
66
+ def secrets_params
67
+ params.require(:secrets)
68
+ end
69
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @resource Project
4
+
5
+ class UffizziCore::Api::Cli::V1::ProjectsController < UffizziCore::Api::Cli::V1::ApplicationController
6
+ before_action :authorize_uffizzi_core_api_cli_v1_projects
7
+
8
+ # Get projects of current user
9
+ #
10
+ # @path [GET] /api/cli/v1/projects
11
+ #
12
+ # @response [object<projects: Array<object<slug: string>> >] 200 OK
13
+ # @response 401 Not authorized
14
+ def index
15
+ projects = current_user.projects.active.order(updated_at: :desc)
16
+
17
+ respond_with projects
18
+ end
19
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @resource Uffizzi
4
+
5
+ class UffizziCore::Api::Cli::V1::SessionsController < UffizziCore::Api::Cli::V1::ApplicationController
6
+ skip_before_action :authenticate_request!, only: [:create]
7
+
8
+ # Create session
9
+ #
10
+ # @path [POST] /api/cli/v1/session
11
+ #
12
+ # @parameter user(required,body) [object<email: string, password: string >]
13
+ # @response [object<user: object<accounts: Array<object<id: integer, state: string>> >>] 201 Created successfully
14
+ # @response [object<errors: object<password: string >>] 422 Unprocessable entity
15
+ def create
16
+ session_form = UffizziCore::Api::Cli::V1::SessionCreateForm.new(session_params)
17
+
18
+ if session_form.valid?
19
+ sign_in(session_form.user)
20
+
21
+ return respond_with session_form.user
22
+ end
23
+
24
+ respond_with session_form
25
+ end
26
+
27
+ # Destroy session
28
+ #
29
+ # @path [DELETE] /api/cli/v1/session
30
+ #
31
+ # @response 204 No Content
32
+ def destroy
33
+ sign_out
34
+
35
+ head :no_content
36
+ end
37
+
38
+ private
39
+
40
+ def session_params
41
+ params.require(:user).permit(:email, :password)
42
+ end
43
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ApplicationController < ActionController::Base
4
+ include Pundit
5
+ include UffizziCore::ResponseService
6
+ include UffizziCore::AuthManagement
7
+ include UffizziCore::AuthorizationConcern
8
+ include UffizziCore::DependencyInjectionConcern
9
+
10
+ DEFAULT_PAGE = 1
11
+ DEFAULT_PER_PAGE = 20
12
+
13
+ protect_from_forgery with: :exception
14
+ rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
15
+
16
+ before_action :authenticate_request!
17
+ skip_before_action :verify_authenticity_token
18
+ rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
19
+
20
+ respond_to :json
21
+
22
+ def policy_context
23
+ UffizziCore::BaseContext.new(current_user, user_access_module, params)
24
+ end
25
+
26
+ def self.responder
27
+ UffizziCore::JsonResponder
28
+ end
29
+
30
+ def render_not_found
31
+ render json: { errors: { title: ['Resource Not Found'] } }, status: :not_found
32
+ end
33
+
34
+ def render_errors(errors)
35
+ json = { errors: errors }
36
+
37
+ render json: json, status: :unprocessable_entity
38
+ end
39
+
40
+ def q_param
41
+ params[:q] || ActionController::Parameters.new
42
+ end
43
+
44
+ def page
45
+ params[:page] || DEFAULT_PAGE
46
+ end
47
+
48
+ def per_page
49
+ params[:per_page] || DEFAULT_PER_PAGE
50
+ end
51
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::BuildError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::CredentialError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::NotFoundError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::ParseError < StandardError
4
+ end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::ComposeFile::SecretsError < StandardError
4
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::DeploymentNotFoundError < StandardError
4
+ attr_reader :deployment_id
5
+
6
+ def initialize(deployment_id)
7
+ super
8
+ @deployment_id = deployment_id
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Account::Credential::CreateForm < UffizziCore::Credential
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :type, :registry_url, :username, :password
7
+
8
+ validates :password, presence: { message: :password_blank }
9
+ validate :check_registry_url, if: -> { errors[:password].empty? }
10
+ validate :check_credential_correctness, if: -> { errors[:password].empty? }
11
+ validate :credential_exists?, if: -> { errors[:password].empty? }
12
+
13
+ private
14
+
15
+ def check_registry_url
16
+ errors.add(:registry_url, :invalid_scheme) if URI.parse(registry_url).scheme.nil?
17
+ end
18
+
19
+ def check_credential_correctness
20
+ errors.add(:username, :incorrect) unless UffizziCore::CredentialService.correct_credentials?(self)
21
+ end
22
+
23
+ def credential_exists?
24
+ errors.add(:type, :exist) if account.credentials.where(type: type).exists?
25
+ end
26
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+
6
+ attribute :compose_file
7
+ attribute :credentials
8
+
9
+ validate :check_containers_credentials
10
+
11
+ private
12
+
13
+ def check_containers_credentials
14
+ compose_content = Base64.decode64(compose_file.content)
15
+ compose_data = UffizziCore::Cli::ComposeFileService.parse(compose_content)
16
+
17
+ UffizziCore::Cli::ComposeFileService.containers_credentials(compose_data, credentials)
18
+ rescue UffizziCore::ComposeFile::CredentialError => e
19
+ errors.add(:credentials, e.message)
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ComposeFile::CliForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+
6
+ attribute :credential, UffizziCore::Credential
7
+ attribute :compose_content_data, Hash
8
+ attribute :compose_data, Hash
9
+ attribute :compose_dependencies, Array
10
+ attribute :compose_repositories, Array
11
+ attribute :content, String
12
+
13
+ validates :content, presence: true
14
+
15
+ validate :check_compose_parsed_data, if: -> { errors[:content].empty? }
16
+ validate :check_repositories, if: -> { credential.present? && errors[:content].empty? }
17
+ validate :check_branches, if: -> { credential.present? && errors[:content].empty? }
18
+
19
+ def check_compose_parsed_data
20
+ compose_content = Base64.decode64(content)
21
+ self.compose_data = UffizziCore::Cli::ComposeFileService.parse(compose_content)
22
+ rescue UffizziCore::ComposeFile::ParseError => e
23
+ errors.add(:content, e.message)
24
+ end
25
+
26
+ def check_repositories
27
+ self.compose_repositories = UffizziCore::Cli::ComposeFileService.load_repositories(compose_data, credential)
28
+ rescue UffizziCore::ComposeFile::NotFoundError => e
29
+ errors.add(:content, e.message)
30
+ end
31
+
32
+ def check_branches
33
+ return if compose_repositories.blank?
34
+
35
+ UffizziCore::Cli::ComposeFileService.check_github_branches(compose_data, compose_repositories, credential)
36
+ rescue UffizziCore::ComposeFile::NotFoundError => e
37
+ errors.add(:content, e.message)
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ComposeFile::CreateForm < UffizziCore::ComposeFile
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :source, :path, :content
7
+
8
+ validates :source, presence: true
9
+ validates :source, uniqueness: { scope: :project_id, message: 'A compose file with the same source already exists for this project' },
10
+ if: -> { kind.main? }
11
+ validates :path, presence: true
12
+ validates :content, presence: true
13
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ComposeFile::TemplateForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+
6
+ SECRETS_ERROR_KEY = 'secret_variables'
7
+ TEMPLATE_BUILD_ERROR_KEY = 'template_build_error'
8
+
9
+ attribute :credentials
10
+ attribute :project, UffizziCore::Project
11
+ attribute :user, UffizziCore::User
12
+ attribute :compose_data, Hash
13
+ attribute :source, String
14
+ attribute :template_attributes, Hash
15
+ attribute :template_build_error, String
16
+ attribute :compose_dependencies, Array
17
+ attribute :compose_repositories, Array
18
+
19
+ validate :check_template_attributes
20
+
21
+ def assign_template_attributes!
22
+ self.template_attributes = UffizziCore::Cli::ComposeFileService.build_template_attributes(
23
+ compose_data,
24
+ source,
25
+ credentials,
26
+ project,
27
+ compose_dependencies,
28
+ compose_repositories,
29
+ )
30
+ rescue StandardError => e
31
+ self.template_build_error = e
32
+ end
33
+
34
+ private
35
+
36
+ def check_template_attributes
37
+ case template_build_error
38
+ when UffizziCore::ComposeFile::SecretsError
39
+ errors.add(SECRETS_ERROR_KEY, template_build_error.message)
40
+ when UffizziCore::ComposeFile::BuildError
41
+ errors.add(TEMPLATE_BUILD_ERROR_KEY, template_build_error.message)
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ComposeFile::UpdateForm < UffizziCore::ComposeFile
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :content, :source, :path
7
+
8
+ validates :content, presence: true
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::ConfigFile::CreateForm < UffizziCore::ConfigFile
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :filename, :kind, :payload
7
+
8
+ validates :filename, presence: true
9
+ validates :kind, presence: true
10
+ validates :payload, presence: true
11
+ end
@@ -0,0 +1,91 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Deployment::CreateForm < UffizziCore::Deployment
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :creation_source,
7
+ containers_attributes: [
8
+ :image,
9
+ :name,
10
+ :tag,
11
+ :port,
12
+ :public,
13
+ :memory_limit,
14
+ :memory_request,
15
+ :entrypoint,
16
+ :command,
17
+ :receive_incoming_requests,
18
+ :continuously_deploy,
19
+ { variables: [:name, :value],
20
+ secret_variables: [:name, :value],
21
+ repo_attributes: [
22
+ :namespace,
23
+ :name,
24
+ :slug,
25
+ :type,
26
+ :description,
27
+ :is_private,
28
+ :repository_id,
29
+ :branch,
30
+ :kind,
31
+ :dockerfile_path,
32
+ :dockerfile_context_path,
33
+ :deploy_preview_when_pull_request_is_opened,
34
+ :delete_preview_when_pull_request_is_closed,
35
+ :deploy_preview_when_image_tag_is_created,
36
+ :delete_preview_when_image_tag_is_updated,
37
+ :share_to_github,
38
+ :delete_preview_after,
39
+ { args: [:name, :value] },
40
+ ],
41
+ container_config_files_attributes: [
42
+ :config_file_id,
43
+ :mount_path,
44
+ ] },
45
+ ]
46
+
47
+ validate :check_all_containers_have_unique_ports
48
+ validate :check_exists_ingress_container
49
+ validate :check_max_memory_limit
50
+ validate :check_max_memory_request
51
+
52
+ def assign_dependences!(project, user)
53
+ self.project = project
54
+
55
+ self.containers = containers.map do |container|
56
+ container.repo.project = project if !container.repo.nil?
57
+
58
+ container
59
+ end
60
+
61
+ self.deployed_by = user
62
+
63
+ self
64
+ end
65
+
66
+ private
67
+
68
+ def check_all_containers_have_unique_ports
69
+ active_containers = containers.select(&:active?)
70
+
71
+ errors.add(:containers, :duplicate_ports) unless UffizziCore::DeploymentService.all_containers_have_unique_ports?(active_containers)
72
+ end
73
+
74
+ def check_exists_ingress_container
75
+ active_containers = containers.select(&:active?)
76
+
77
+ errors.add(:containers, :incorrect_ingress_container) unless UffizziCore::DeploymentService.ingress_container?(active_containers)
78
+ end
79
+
80
+ def check_max_memory_limit
81
+ return if UffizziCore::DeploymentService.valid_containers_memory_limit?(self)
82
+
83
+ errors.add(:containers, :max_memory_limit_error, max: project.account.container_memory_limit)
84
+ end
85
+
86
+ def check_max_memory_request
87
+ return if UffizziCore::DeploymentService.valid_containers_memory_request?(self)
88
+
89
+ errors.add(:containers, :max_memory_request_error, max: project.account.container_memory_limit)
90
+ end
91
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Project::DeleteSecretForm < UffizziCore::Project
4
+ include UffizziCore::ApplicationForm
5
+
6
+ attr_accessor :secret
7
+
8
+ permit secrets: [:name, :value]
9
+
10
+ validate :check_existence
11
+
12
+ def delete_secret!
13
+ existing_secrets = secrets.presence || []
14
+
15
+ self.secrets = existing_secrets.reject { |existing_secret| existing_secret['name'] == secret.name }
16
+ end
17
+
18
+ private
19
+
20
+ def check_existence
21
+ existing_secrets = secrets.presence || []
22
+
23
+ detected_secret = existing_secrets.detect { |existing_secret| existing_secret['name'] == secret.name }
24
+
25
+ errors.add(:secret, :not_found, name: secret.name) if detected_secret.nil?
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Project::UpdateForm < UffizziCore::Project
4
+ include UffizziCore::ApplicationForm
5
+ MAX_SECRET_KEY_LENGTH = 256
6
+
7
+ permit :name, :slug, :description, secrets: [:name, :value]
8
+
9
+ validates :name, presence: true, uniqueness: { scope: :account }
10
+ validates :slug, presence: true, uniqueness: true
11
+
12
+ validate :check_duplicates
13
+ validate :check_length
14
+
15
+ def assign_secrets!(new_secrets)
16
+ existing_secrets = secrets.presence || []
17
+
18
+ self.secrets = existing_secrets.union(new_secrets)
19
+ end
20
+
21
+ private
22
+
23
+ def check_duplicates
24
+ duplicates = []
25
+ groupped_secrets = secrets.group_by { |secret| secret['name'] }
26
+ groupped_secrets.each_pair do |key, value|
27
+ duplicates << key if value.size > 1
28
+ end
29
+
30
+ error_message = I18n.t('secrets.duplicates_exists', secrets: duplicates.join(', '))
31
+ errors.add(:secrets, error_message) if duplicates.present?
32
+ end
33
+
34
+ def check_length
35
+ secrets_with_invalid_key_length = secrets.select { |secret| secret['name'].length > MAX_SECRET_KEY_LENGTH }
36
+
37
+ error_message = I18n.t('secrets.invalid_key_length')
38
+ errors.add(:secrets, error_message) if secrets_with_invalid_key_length.present?
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::SessionCreateForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+
6
+ attribute :email, String
7
+ attribute :password, String
8
+
9
+ validates :email, :password, presence: true
10
+ validate :check_authenticate, if: :email
11
+
12
+ def user
13
+ @user ||= UffizziCore::User.active.by_email(email).first
14
+ end
15
+
16
+ def check_authenticate
17
+ return unless wrong_email_or_password?
18
+
19
+ errors.add(:password, 'Email or password is incorrect.')
20
+ end
21
+
22
+ private
23
+
24
+ def wrong_email_or_password?
25
+ return true if user.nil?
26
+
27
+ !user.authenticate(password)
28
+ end
29
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Template::CreateForm < UffizziCore::Template
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit :name,
7
+ payload: {
8
+ containers_attributes: [
9
+ :image,
10
+ :tag,
11
+ :port,
12
+ :public,
13
+ :memory_limit,
14
+ :memory_request,
15
+ :entrypoint,
16
+ :command,
17
+ :receive_incoming_requests,
18
+ :continuously_deploy,
19
+ :name,
20
+ { variables: [:name, :value],
21
+ secret_variables: [:name, :value],
22
+ repo_attributes: [
23
+ :namespace,
24
+ :name,
25
+ :slug,
26
+ :type,
27
+ :description,
28
+ :repository_id,
29
+ :is_private,
30
+ :branch,
31
+ :kind,
32
+ :dockerfile_path,
33
+ :dockerfile_context_path,
34
+ :deploy_preview_when_pull_request_is_opened,
35
+ :delete_preview_when_pull_request_is_closed,
36
+ :deploy_preview_when_image_tag_is_created,
37
+ :delete_preview_when_image_tag_is_updated,
38
+ :share_to_github,
39
+ :delete_preview_after,
40
+ { args: [:name, :value] },
41
+ ],
42
+ container_config_files_attributes: [
43
+ :config_file_id,
44
+ :mount_path,
45
+ ] },
46
+ ],
47
+ }
48
+
49
+ validate :check_max_memory_limit
50
+ validate :check_max_memory_request
51
+
52
+ private
53
+
54
+ def check_max_memory_limit
55
+ return if UffizziCore::TemplateService.valid_containers_memory_limit?(self)
56
+
57
+ errors.add(:payload, :max_memory_limit_error, max: project.account.container_memory_limit)
58
+ end
59
+
60
+ def check_max_memory_request
61
+ return if UffizziCore::TemplateService.valid_containers_memory_request?(self)
62
+
63
+ errors.add(:payload, :max_memory_request_error, max: project.account.container_memory_limit)
64
+ end
65
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ApplicationForm
4
+ extend ActiveSupport::Concern
5
+
6
+ include UffizziCore::MassAssignmentControlConcern
7
+
8
+ class_methods do
9
+ delegate :model_name, :name, to: :superclass
10
+ end
11
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module UffizziCore::ApplicationFormWithoutActiveRecord
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include ActiveModel::Validations
8
+ include ActiveModel::Conversion
9
+ include ActiveModel::Serialization
10
+ include ActiveModel::Validations::Callbacks
11
+ include ::Virtus.model
12
+ end
13
+
14
+ def persisted?
15
+ false
16
+ end
17
+ end