uffizzi_core 0.1.3 → 0.1.5

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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/app/clients/uffizzi_core/docker_hub_client.rb +2 -0
  3. data/app/clients/uffizzi_core/github_container_registry_client/request_result.rb +7 -0
  4. data/app/clients/uffizzi_core/github_container_registry_client.rb +52 -0
  5. data/app/controllers/concerns/uffizzi_core/dependency_injection_concern.rb +2 -2
  6. data/app/controllers/uffizzi_core/api/cli/v1/account/credentials_controller.rb +45 -9
  7. data/app/controllers/uffizzi_core/api/cli/v1/projects/compose_files_controller.rb +2 -2
  8. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments/application_controller.rb +1 -1
  9. data/app/controllers/uffizzi_core/api/cli/v1/projects/deployments_controller.rb +41 -10
  10. data/app/controllers/uffizzi_core/api/cli/v1/projects/secrets_controller.rb +18 -26
  11. data/app/controllers/uffizzi_core/application_controller.rb +9 -3
  12. data/app/errors/uffizzi_core/deployment/image_pull_error.rb +10 -0
  13. data/app/forms/uffizzi_core/api/cli/v1/account/credential/check_credential_form.rb +16 -0
  14. data/app/forms/uffizzi_core/api/cli/v1/account/credential/create_form.rb +1 -1
  15. data/app/forms/uffizzi_core/api/cli/v1/compose_file/check_credentials_form.rb +2 -2
  16. data/app/forms/uffizzi_core/api/cli/v1/compose_file/cli_form.rb +1 -18
  17. data/app/forms/uffizzi_core/api/cli/v1/compose_file/template_form.rb +1 -1
  18. data/app/forms/uffizzi_core/api/cli/v1/deployment/update_form.rb +90 -0
  19. data/app/forms/uffizzi_core/api/cli/v1/project/update_form.rb +1 -31
  20. data/app/forms/uffizzi_core/api/cli/v1/secret/bulk_assign_form.rb +39 -0
  21. data/app/jobs/uffizzi_core/deployment/manage_deploy_activity_item_job.rb +22 -3
  22. data/app/lib/uffizzi_core/rbac/user_access_service.rb +12 -14
  23. data/app/models/uffizzi_core/account.rb +1 -19
  24. data/app/models/uffizzi_core/activity_item.rb +1 -6
  25. data/app/models/uffizzi_core/build.rb +1 -1
  26. data/app/models/uffizzi_core/comment.rb +1 -1
  27. data/app/models/uffizzi_core/compose_file.rb +1 -1
  28. data/app/models/uffizzi_core/config_file.rb +1 -1
  29. data/app/models/uffizzi_core/container.rb +1 -1
  30. data/app/models/uffizzi_core/container_config_file.rb +1 -1
  31. data/app/models/uffizzi_core/coupon.rb +1 -1
  32. data/app/models/uffizzi_core/credential/github_container_registry.rb +4 -0
  33. data/app/models/uffizzi_core/credential.rb +3 -6
  34. data/app/models/uffizzi_core/deployment.rb +11 -2
  35. data/app/models/uffizzi_core/event.rb +1 -1
  36. data/app/models/uffizzi_core/invitation.rb +1 -1
  37. data/app/models/uffizzi_core/membership.rb +1 -1
  38. data/app/models/uffizzi_core/payment.rb +1 -1
  39. data/app/models/uffizzi_core/price.rb +1 -1
  40. data/app/models/uffizzi_core/product.rb +1 -1
  41. data/app/models/uffizzi_core/project.rb +5 -11
  42. data/app/models/uffizzi_core/rating.rb +1 -1
  43. data/app/models/uffizzi_core/repo/github_container_registry.rb +4 -0
  44. data/app/models/uffizzi_core/repo.rb +1 -11
  45. data/app/models/uffizzi_core/role.rb +2 -2
  46. data/app/models/uffizzi_core/secret.rb +9 -0
  47. data/app/models/uffizzi_core/template.rb +1 -1
  48. data/app/models/uffizzi_core/user.rb +1 -1
  49. data/app/models/uffizzi_core/user_project.rb +1 -1
  50. data/app/policies/uffizzi_core/api/cli/v1/account/credentials_policy.rb +8 -0
  51. data/app/policies/uffizzi_core/api/cli/v1/projects/deployments_policy.rb +4 -0
  52. data/app/repositories/uffizzi_core/credential_repo.rb +17 -22
  53. data/app/repositories/uffizzi_core/deployment_repo.rb +1 -0
  54. data/app/serializers/uffizzi_core/api/cli/v1/projects/deployment_serializer/container_serializer.rb +8 -0
  55. data/app/serializers/uffizzi_core/api/cli/v1/projects/secret_serializer.rb +5 -0
  56. data/app/serializers/uffizzi_core/controller/apply_config_file/config_file_serializer.rb +5 -0
  57. data/app/serializers/uffizzi_core/controller/create_credential/credential_serializer.rb +7 -3
  58. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer/container_config_file_serializer/config_file_serializer.rb +8 -0
  59. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer/container_config_file_serializer.rb +7 -0
  60. data/app/serializers/uffizzi_core/controller/deploy_containers/container_serializer.rb +4 -3
  61. data/app/services/uffizzi_core/activity_item_service.rb +16 -26
  62. data/app/services/uffizzi_core/compose_file/builders/container_builder_service.rb +11 -18
  63. data/app/services/uffizzi_core/compose_file/container_service.rb +13 -9
  64. data/app/services/uffizzi_core/compose_file/dependencies_service.rb +1 -0
  65. data/app/services/uffizzi_core/compose_file/services_options_service.rb +2 -2
  66. data/app/services/uffizzi_core/compose_file_service.rb +148 -0
  67. data/app/services/uffizzi_core/container_service.rb +1 -16
  68. data/app/services/uffizzi_core/controller_service.rb +7 -1
  69. data/app/services/uffizzi_core/credential_service.rb +2 -2
  70. data/app/services/uffizzi_core/deployment_service.rb +28 -7
  71. data/app/services/uffizzi_core/github_container_registry/credential_service.rb +24 -0
  72. data/app/services/uffizzi_core/manage_activity_items_service.rb +4 -19
  73. data/app/services/uffizzi_core/repo_service.rb +2 -137
  74. data/app/services/uffizzi_core/user_generator_service.rb +78 -0
  75. data/config/locales/en.activerecord.yml +5 -0
  76. data/config/locales/en.yml +4 -1
  77. data/config/routes.rb +6 -2
  78. data/db/migrate/20220309110201_remove_secrets_from_projects.rb +7 -0
  79. data/db/migrate/20220310110150_create_project_secrets.rb +14 -0
  80. data/db/migrate/20220329123323_rename_project_secrets_to_secrets.rb +7 -0
  81. data/db/migrate/20220329124542_add_resource_to_secrets.rb +7 -0
  82. data/db/migrate/20220329143241_remove_project_ref_from_secrets.rb +7 -0
  83. data/lib/tasks/uffizzi_core_tasks.rake +5 -0
  84. data/lib/uffizzi_core/engine.rb +35 -0
  85. data/lib/uffizzi_core/version.rb +1 -1
  86. data/lib/uffizzi_core.rb +1 -30
  87. data/swagger/v1/swagger.json +220 -11
  88. metadata +45 -25
  89. data/app/clients/uffizzi_core/github/app_client.rb +0 -19
  90. data/app/clients/uffizzi_core/github/installation_client.rb +0 -11
  91. data/app/clients/uffizzi_core/github/user_client.rb +0 -51
  92. data/app/errors/uffizzi_core/compose_file/not_found_error.rb +0 -4
  93. data/app/forms/uffizzi_core/api/cli/v1/project/delete_secret_form.rb +0 -27
  94. data/app/jobs/uffizzi_core/deployment/send_github_preview_message_job.rb +0 -13
  95. data/app/services/uffizzi_core/cli/compose_file_service.rb +0 -203
  96. data/app/services/uffizzi_core/compose_file/builders/github_repo_builder_service.rb +0 -59
  97. data/app/services/uffizzi_core/compose_file/services_options/build_service.rb +0 -93
  98. data/app/services/uffizzi_core/compose_file/update_service.rb +0 -29
  99. data/app/services/uffizzi_core/github/app_service.rb +0 -51
  100. data/app/services/uffizzi_core/github/credential_service.rb +0 -124
  101. data/app/services/uffizzi_core/github/message_service.rb +0 -20
  102. data/app/services/uffizzi_core/github_service.rb +0 -28
  103. data/app/services/uffizzi_core/user_access_service.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3fa1762e392d1748e189b83b1b546d4b6005034de25e15a00189f683d65764fa
4
- data.tar.gz: 7f361a77ac67122c8bdebf1112c4b5f7a4f541e3c55ac5f75568ffbaa0e48c20
3
+ metadata.gz: 49bbe08dfa41ecd2c4c9b6d2f488334db9ba40ec952b2a249d55e3be08b819aa
4
+ data.tar.gz: 37a606bcb357ef8b4b072b8be528c08a47569d8da3e3cf0fed00ec1aff110648
5
5
  SHA512:
6
- metadata.gz: 49a8755ddc0743460d1b0f52d787f4c6fe17a68291eabcd20efdd1661007750fdfdf4a336665b97c86500fc5c5f03c44eda25ed9ec9166d6c608be9298c30465
7
- data.tar.gz: 9132eb4e35621f7a45e0a41833448c329a320d10651a000e285edda8c96c06c3f5366f6658a83f527e941af3398c652b0ce66ebc1ef058df2b6d90f03b370dca
6
+ metadata.gz: 0fcd5124498ab741cb1d03cada959eb0b821f15f8aede73f225ac0ac3a983b8deafecbe7a5905e8256c5b6f6c370348a4d85d6701b718b07bf9f56de2aea0fb2
7
+ data.tar.gz: 007c508efa144dfa7d617e36f12c00e3895cc871c9dc6cdfb00e4affd19eac3fc9ef4112898e7acf513408cae6077ff1e0bd5c2c8ffa1c71375c950c085be28e
@@ -19,6 +19,8 @@ class UffizziCore::DockerHubClient
19
19
  response = connection.post(url, params)
20
20
  request_result = RequestResult.new(result: response.body)
21
21
  request_result.result.token
22
+ rescue NoMethodError
23
+ nil
22
24
  end
23
25
 
24
26
  def public_images(q:, page: 1, per_page: 25)
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::GithubContainerRegistryClient
4
+ class RequestResult < Hashie::Mash
5
+ disable_warnings :key
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::GithubContainerRegistryClient
4
+ attr_accessor :token, :registry_url
5
+
6
+ def initialize(registry_url:, username:, password:)
7
+ @registry_url = registry_url
8
+ @username = username
9
+ @password = password
10
+ @token = access_token&.result&.token
11
+ end
12
+
13
+ def access_token
14
+ service = URI.parse(registry_url).hostname
15
+ url = "/token?service=#{service}"
16
+
17
+ response = connection.get(url, {})
18
+
19
+ RequestResult.new(result: response.body)
20
+ end
21
+
22
+ def authentificated?
23
+ token.present?
24
+ end
25
+
26
+ def manifests(image:, tag:)
27
+ url = "/v2/#{@username}/#{image}/manifests/#{tag}"
28
+ response = token_connection.get(url)
29
+
30
+ RequestResult.quiet.new(result: response.body, headers: response.headers)
31
+ end
32
+
33
+ private
34
+
35
+ def connection
36
+ Faraday.new(registry_url) do |conn|
37
+ conn.request(:basic_auth, @username, @password)
38
+ conn.request(:json)
39
+ conn.response(:json)
40
+ conn.adapter(Faraday.default_adapter)
41
+ end
42
+ end
43
+
44
+ def token_connection
45
+ Faraday.new(registry_url) do |conn|
46
+ conn.request(:authorization, 'Bearer', token)
47
+ conn.request(:json)
48
+ conn.response(:json)
49
+ conn.adapter(Faraday.default_adapter)
50
+ end
51
+ end
52
+ end
@@ -4,7 +4,7 @@ module UffizziCore::DependencyInjectionConcern
4
4
  def user_access_module
5
5
  return unless module_exists?(:rbac)
6
6
 
7
- UffizziCore::UserAccessService.new(module_class(:rbac))
7
+ module_class(:rbac).new
8
8
  end
9
9
 
10
10
  private
@@ -14,6 +14,6 @@ module UffizziCore::DependencyInjectionConcern
14
14
  end
15
15
 
16
16
  def module_class(module_name)
17
- UffizziCore.dependencies[module_name]&.constantize
17
+ Rails.application.config.uffizzi_core[:dependencies][module_name]&.constantize
18
18
  end
19
19
  end
@@ -4,6 +4,17 @@
4
4
  class UffizziCore::Api::Cli::V1::Account::CredentialsController < UffizziCore::Api::Cli::V1::Account::ApplicationController
5
5
  before_action :authorize_uffizzi_core_api_cli_v1_account_credentials
6
6
 
7
+ # Get a list of accounts credential
8
+ #
9
+ # @path [GET] /api/cli/v1/account/credentials
10
+ #
11
+ # @parameter credential(required,body) [object<username:string, password: string, type:string>]
12
+ def index
13
+ credentials = resource_account.credentials.pluck(:type)
14
+
15
+ render json: { credentials: credentials }, status: :ok
16
+ end
17
+
7
18
  # rubocop:disable Layout/LineLength
8
19
  # Create account credential
9
20
  #
@@ -14,26 +25,39 @@ class UffizziCore::Api::Cli::V1::Account::CredentialsController < UffizziCore::A
14
25
  # @response [object<errors>] 422 Unprocessable entity
15
26
  #
16
27
  # @example
17
- # type can be one of UffizziCore::Credential::Amazon, UffizziCore::Credential::Azure, UffizziCore::Credential::DockerHub, UffizziCore::Credential::Google
28
+ # type can be one of UffizziCore::Credential::Amazon, UffizziCore::Credential::Azure, UffizziCore::Credential::DockerHub, UffizziCore::Credential::Google, UffizziCore::Credential::GithubContainerRegistry
18
29
  # rubocop:enable Layout/LineLength
19
30
  def create
20
31
  credential_form = UffizziCore::Api::Cli::V1::Account::Credential::CreateForm.new
21
32
  credential_form.assign_attributes(credential_params)
22
33
  credential_form.account = resource_account
23
- credential_form.registry_url = Settings.docker_hub.registry_url if credential_form.docker_hub?
24
- if credential_form.google?
25
- credential_form.registry_url = Settings.google.registry_url
26
- credential_form.username = '_json_key'
27
- end
34
+ credential_form.registry_url = registry_url(credential_form)
35
+ credential_form.username = '_json_key' if credential_form.google?
28
36
  credential_form.activate
29
37
 
30
- if credential_form.save
31
- UffizziCore::Account::CreateCredentialJob.perform_async(credential_form.id)
32
- end
38
+ UffizziCore::Account::CreateCredentialJob.perform_async(credential_form.id) if credential_form.save
33
39
 
34
40
  respond_with credential_form
35
41
  end
36
42
 
43
+ # Check if credential of the type already exists in the account
44
+ #
45
+ # @path [GET] /api/cli/v1/account/credentials/{type}/check_credential
46
+ #
47
+ # @parameter credential(required,body) [object<type:string>]
48
+ # @response 422 Unprocessable entity
49
+ # @response 200 OK
50
+ def check_credential
51
+ credential_form = UffizziCore::Api::Cli::V1::Account::Credential::CheckCredentialForm.new
52
+ credential_form.type = params[:type]
53
+ credential_form.account = resource_account
54
+ if credential_form.valid?
55
+ respond_with credential_form
56
+ else
57
+ respond_with credential_form.errors, status: :unprocessable_entity
58
+ end
59
+ end
60
+
37
61
  # Delete account credential
38
62
  #
39
63
  # @path [DELETE] /api/cli/v1/account/credentials/{type}
@@ -52,4 +76,16 @@ class UffizziCore::Api::Cli::V1::Account::CredentialsController < UffizziCore::A
52
76
  def credential_params
53
77
  params.require(:credential)
54
78
  end
79
+
80
+ def registry_url(credential_form)
81
+ if credential_form.docker_hub?
82
+ Settings.docker_hub.registry_url
83
+ elsif credential_form.google?
84
+ Settings.google.registry_url
85
+ elsif credential_form.github_container_registry?
86
+ Settings.github_container_registry.registry_url
87
+ else
88
+ credential_form.registry_url
89
+ end
90
+ end
55
91
  end
@@ -78,10 +78,10 @@ class UffizziCore::Api::Cli::V1::Projects::ComposeFilesController < UffizziCore:
78
78
  def create_or_update_compose_file(params)
79
79
  existing_compose_file = resource_project.compose_file
80
80
  if existing_compose_file.present?
81
- UffizziCore::Cli::ComposeFileService.update(existing_compose_file, params)
81
+ UffizziCore::ComposeFileService.update(existing_compose_file, params)
82
82
  else
83
83
  kind = UffizziCore::ComposeFile.kind.main
84
- UffizziCore::Cli::ComposeFileService.create(params, kind)
84
+ UffizziCore::ComposeFileService.create(params, kind)
85
85
  end
86
86
  end
87
87
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  class UffizziCore::Api::Cli::V1::Projects::Deployments::ApplicationController < UffizziCore::Api::Cli::V1::Projects::ApplicationController
4
4
  def resource_deployment
5
- @resource_deployment ||= resource_project.deployments.find(params[:deployment_id])
5
+ @resource_deployment ||= resource_project.deployments.active.find(params[:deployment_id])
6
6
  end
7
7
  end
@@ -56,6 +56,33 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
56
56
  respond_with deployment
57
57
  end
58
58
 
59
+ # Update the deployment with new compose file
60
+ #
61
+ # @path [PUT] /api/cli/v1/projects/{project_slug}/deployments/{id}"
62
+ #
63
+ # @parameter project_slug(required,path) [string] The project slug
64
+ # @parameter params(required,body) [object<
65
+ # compose_file: object<path: string, source: string, content: string>,
66
+ # dependencies: Array<object<path: string, source: string, content: string>>>]
67
+ #
68
+ # @response [Deployment] 201 OK
69
+ # @response [object<errors: object<state: string>>] 422 Unprocessable Entity
70
+ # @response [object<errors: object<title: string>>] 404 Not found
71
+ # @response 401 Not authorized
72
+ def update
73
+ compose_file, errors = create_temporary_compose_file
74
+ return render_invalid_file if compose_file.invalid_file?
75
+ return render_errors(errors) if errors.present?
76
+
77
+ errors = check_credentials(compose_file)
78
+ return render_errors(errors) if errors.present?
79
+
80
+ deployment_id = params[:id]
81
+ deployment = UffizziCore::DeploymentService.update_from_compose(compose_file, resource_project, current_user, deployment_id)
82
+
83
+ respond_with deployment
84
+ end
85
+
59
86
  # @path [POST] /api/cli/v1/projects/{project_slug}/deployments/{id}/deploy_containers
60
87
  #
61
88
  # @parameter project_slug(required,path) [string] The project slug
@@ -99,15 +126,7 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
99
126
  def find_or_create_compose_file
100
127
  existing_compose_file = resource_project.compose_file
101
128
  if compose_file_params.present?
102
- create_params = {
103
- project: resource_project,
104
- user: current_user,
105
- compose_file_params: compose_file_params,
106
- dependencies: dependencies_params[:dependencies] || [],
107
- }
108
-
109
- kind = UffizziCore::ComposeFile.kind.temporary
110
- UffizziCore::Cli::ComposeFileService.create(create_params, kind)
129
+ create_temporary_compose_file
111
130
  else
112
131
  raise ActiveRecord::RecordNotFound if existing_compose_file.blank?
113
132
 
@@ -116,6 +135,18 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
116
135
  end
117
136
  end
118
137
 
138
+ def create_temporary_compose_file
139
+ create_params = {
140
+ project: resource_project,
141
+ user: current_user,
142
+ compose_file_params: compose_file_params,
143
+ dependencies: dependencies_params[:dependencies] || [],
144
+ }
145
+
146
+ kind = UffizziCore::ComposeFile.kind.temporary
147
+ UffizziCore::ComposeFileService.create(create_params, kind)
148
+ end
149
+
119
150
  def check_credentials(compose_file)
120
151
  credentials = resource_project.account.credentials
121
152
  check_credentials_form = UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm.new
@@ -127,7 +158,7 @@ class UffizziCore::Api::Cli::V1::Projects::DeploymentsController < UffizziCore::
127
158
  end
128
159
 
129
160
  def deployments
130
- @deployments ||= resource_project.deployments.active
161
+ @deployments ||= resource_project.deployments.existed
131
162
  end
132
163
 
133
164
  def deployment_params
@@ -8,13 +8,10 @@ class UffizziCore::Api::Cli::V1::Projects::SecretsController < UffizziCore::Api:
8
8
  #
9
9
  # @path [GET] /api/cli/v1/projects/{project_slug}/secrets
10
10
  # @parameter project_slug(required,path) [string]
11
- # @response [object<secrets: Array<object<name: string>> >] 200 OK
11
+ # @response [object<secrets: Array<object<name: string, created_at: date, updated_at: date>>>] 200 OK
12
12
  # @response 401 Not authorized
13
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
14
+ respond_with resource_project.secrets, root: :secrets
18
15
  end
19
16
 
20
17
  # Add secret to project
@@ -22,43 +19,38 @@ class UffizziCore::Api::Cli::V1::Projects::SecretsController < UffizziCore::Api:
22
19
  # @path [POST] /api/cli/v1/projects/{project_slug}/secrets/bulk_create
23
20
  # @parameter project_slug(required,path) [string]
24
21
  # @parameter secrets(required,body) [object<secrets: Array<object <name: string, value: string>>>]
25
- # @response [object<secrets: Array<object<name: string>>>] 201 Created
22
+ # @response [object<secrets: Array<object<name: string, created_at: date, updated_at: date>>>] 201 Created
26
23
  # @response 422 A compose file already exists for this project
27
24
  # @response 401 Not authorized
28
25
  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
26
+ secrets_form = UffizziCore::Api::Cli::V1::Secret::BulkAssignForm.new
27
+ secrets_form.secrets = resource_project.secrets
28
+ secrets_form.assign_secrets(secrets_params)
29
+ return respond_with secrets_form unless secrets_form.valid?
30
+
31
+ resource_project.secrets.replace(secrets_form.secrets)
32
32
 
33
- UffizziCore::ProjectService.update_compose_secrets(project_form)
34
- secrets = project_form.secrets.map { |secret| { name: secret['name'] } }
33
+ UffizziCore::ProjectService.update_compose_secrets(resource_project)
35
34
 
36
- render json: { secrets: secrets }, status: :created
35
+ respond_with resource_project.secrets, root: :secrets
37
36
  end
38
37
 
39
- # Delete a secret from project by secret id
38
+ # Delete a secret from project by secret name
40
39
  #
41
- # @path [DELETE] /api/cli/v1/projects/{project_slug}/secrets/{id}
40
+ # @path [DELETE] /api/cli/v1/projects/{project_slug}/secrets/{secret_name}
42
41
  # @parameter project_slug(required,path) [string]
43
42
  # @response [Project] 200 OK
44
- # @response 422
43
+ # @response 404
45
44
  # @response 401 Not authorized
46
45
  def destroy
47
46
  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
47
+ secret = resource_project.secrets.find_by!(name: secret_name)
51
48
 
52
- if project_form.invalid?
53
- return respond_with project_form
54
- end
49
+ UffizziCore::ProjectService.update_compose_secret_errors(resource_project, secret)
55
50
 
56
- project_form.delete_secret!
57
- if project_form.save!(validate: false)
58
- UffizziCore::ProjectService.update_compose_secret_errors(project_form, secret)
59
- end
51
+ secret.destroy
60
52
 
61
- respond_with project_form
53
+ head :no_content
62
54
  end
63
55
 
64
56
  private
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UffizziCore::ApplicationController < ActionController::Base
4
- include Pundit
4
+ include Pundit::Authorization
5
5
  include UffizziCore::ResponseService
6
6
  include UffizziCore::AuthManagement
7
7
  include UffizziCore::AuthorizationConcern
@@ -12,11 +12,13 @@ class UffizziCore::ApplicationController < ActionController::Base
12
12
 
13
13
  protect_from_forgery with: :exception
14
14
  rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
15
+ RESCUABLE_EXCEPTIONS = [RuntimeError, TypeError, NameError, ArgumentError, SyntaxError].freeze
16
+ rescue_from *RESCUABLE_EXCEPTIONS do |exception|
17
+ render_server_error(exception)
18
+ end
15
19
 
16
20
  before_action :authenticate_request!
17
21
  skip_before_action :verify_authenticity_token
18
- rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
19
-
20
22
  respond_to :json
21
23
 
22
24
  def policy_context
@@ -31,6 +33,10 @@ class UffizziCore::ApplicationController < ActionController::Base
31
33
  render json: { errors: { title: ['Resource Not Found'] } }, status: :not_found
32
34
  end
33
35
 
36
+ def render_server_error(error)
37
+ render json: { errors: { title: [error] } }, status: :internal_server_error
38
+ end
39
+
34
40
  def render_errors(errors)
35
41
  json = { errors: errors }
36
42
 
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Deployment::ImagePullError < 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,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Account::Credential::CheckCredentialForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+
6
+ attribute :type
7
+ attribute :account
8
+
9
+ validate :credential_exists?
10
+
11
+ private
12
+
13
+ def credential_exists?
14
+ errors.add(:type, 'Credential of that type already exist.') if account.credentials.by_type(type).exists?
15
+ end
16
+ end
@@ -21,6 +21,6 @@ class UffizziCore::Api::Cli::V1::Account::Credential::CreateForm < UffizziCore::
21
21
  end
22
22
 
23
23
  def credential_exists?
24
- errors.add(:type, :exist) if account.credentials.where(type: type).exists?
24
+ errors.add(:type, :exist) if account.credentials.by_type(type).exists?
25
25
  end
26
26
  end
@@ -12,9 +12,9 @@ class UffizziCore::Api::Cli::V1::ComposeFile::CheckCredentialsForm
12
12
 
13
13
  def check_containers_credentials
14
14
  compose_content = Base64.decode64(compose_file.content)
15
- compose_data = UffizziCore::Cli::ComposeFileService.parse(compose_content)
15
+ compose_data = UffizziCore::ComposeFileService.parse(compose_content)
16
16
 
17
- UffizziCore::Cli::ComposeFileService.containers_credentials(compose_data, credentials)
17
+ UffizziCore::ComposeFileService.containers_credentials(compose_data, credentials)
18
18
  rescue UffizziCore::ComposeFile::CredentialError => e
19
19
  errors.add(:credentials, e.message)
20
20
  end
@@ -3,7 +3,6 @@
3
3
  class UffizziCore::Api::Cli::V1::ComposeFile::CliForm
4
4
  include UffizziCore::ApplicationFormWithoutActiveRecord
5
5
 
6
- attribute :credential, UffizziCore::Credential
7
6
  attribute :compose_content_data, Hash
8
7
  attribute :compose_data, Hash
9
8
  attribute :compose_dependencies, Array
@@ -13,27 +12,11 @@ class UffizziCore::Api::Cli::V1::ComposeFile::CliForm
13
12
  validates :content, presence: true
14
13
 
15
14
  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
15
 
19
16
  def check_compose_parsed_data
20
17
  compose_content = Base64.decode64(content)
21
- self.compose_data = UffizziCore::Cli::ComposeFileService.parse(compose_content)
18
+ self.compose_data = UffizziCore::ComposeFileService.parse(compose_content)
22
19
  rescue UffizziCore::ComposeFile::ParseError => e
23
20
  errors.add(:content, e.message)
24
21
  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
22
  end
@@ -19,7 +19,7 @@ class UffizziCore::Api::Cli::V1::ComposeFile::TemplateForm
19
19
  validate :check_template_attributes
20
20
 
21
21
  def assign_template_attributes!
22
- self.template_attributes = UffizziCore::Cli::ComposeFileService.build_template_attributes(
22
+ self.template_attributes = UffizziCore::ComposeFileService.build_template_attributes(
23
23
  compose_data,
24
24
  source,
25
25
  credentials,
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Deployment::UpdateForm < UffizziCore::Deployment
4
+ include UffizziCore::ApplicationForm
5
+
6
+ permit containers_attributes: [
7
+ :image,
8
+ :name,
9
+ :tag,
10
+ :port,
11
+ :public,
12
+ :memory_limit,
13
+ :memory_request,
14
+ :entrypoint,
15
+ :command,
16
+ :receive_incoming_requests,
17
+ :continuously_deploy,
18
+ { variables: [:name, :value],
19
+ secret_variables: [:name, :value],
20
+ repo_attributes: [
21
+ :namespace,
22
+ :name,
23
+ :slug,
24
+ :type,
25
+ :description,
26
+ :is_private,
27
+ :repository_id,
28
+ :branch,
29
+ :kind,
30
+ :dockerfile_path,
31
+ :dockerfile_context_path,
32
+ :deploy_preview_when_pull_request_is_opened,
33
+ :delete_preview_when_pull_request_is_closed,
34
+ :deploy_preview_when_image_tag_is_created,
35
+ :delete_preview_when_image_tag_is_updated,
36
+ :share_to_github,
37
+ :delete_preview_after,
38
+ { args: [:name, :value] },
39
+ ],
40
+ container_config_files_attributes: [
41
+ :config_file_id,
42
+ :mount_path,
43
+ ] },
44
+ ]
45
+
46
+ validate :check_all_containers_have_unique_ports
47
+ validate :check_exists_ingress_container
48
+ validate :check_max_memory_limit
49
+ validate :check_max_memory_request
50
+
51
+ def assign_dependences!(project, user)
52
+ self.project = project
53
+
54
+ self.containers = containers.map do |container|
55
+ container.repo.project = project if !container.repo.nil?
56
+
57
+ container
58
+ end
59
+
60
+ self.deployed_by = user
61
+
62
+ self
63
+ end
64
+
65
+ private
66
+
67
+ def check_all_containers_have_unique_ports
68
+ active_containers = containers.select(&:active?)
69
+
70
+ errors.add(:containers, :duplicate_ports) unless UffizziCore::DeploymentService.all_containers_have_unique_ports?(active_containers)
71
+ end
72
+
73
+ def check_exists_ingress_container
74
+ active_containers = containers.select(&:active?)
75
+
76
+ errors.add(:containers, :incorrect_ingress_container) unless UffizziCore::DeploymentService.ingress_container?(active_containers)
77
+ end
78
+
79
+ def check_max_memory_limit
80
+ return if UffizziCore::DeploymentService.valid_containers_memory_limit?(self)
81
+
82
+ errors.add(:containers, :max_memory_limit_error, max: project.account.container_memory_limit)
83
+ end
84
+
85
+ def check_max_memory_request
86
+ return if UffizziCore::DeploymentService.valid_containers_memory_request?(self)
87
+
88
+ errors.add(:containers, :max_memory_request_error, max: project.account.container_memory_limit)
89
+ end
90
+ end
@@ -2,39 +2,9 @@
2
2
 
3
3
  class UffizziCore::Api::Cli::V1::Project::UpdateForm < UffizziCore::Project
4
4
  include UffizziCore::ApplicationForm
5
- MAX_SECRET_KEY_LENGTH = 256
6
5
 
7
- permit :name, :slug, :description, secrets: [:name, :value]
6
+ permit :name, :slug, :description
8
7
 
9
8
  validates :name, presence: true, uniqueness: { scope: :account }
10
9
  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
10
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UffizziCore::Api::Cli::V1::Secret::BulkAssignForm
4
+ include UffizziCore::ApplicationFormWithoutActiveRecord
5
+ MAX_SECRET_KEY_LENGTH = 256
6
+
7
+ attribute :secrets, Array
8
+ validate :check_duplicates
9
+ validate :check_length
10
+
11
+ def assign_secrets(new_secrets)
12
+ return if new_secrets.blank?
13
+
14
+ new_secrets.each do |new_secret|
15
+ secret = UffizziCore::Secret.new(name: new_secret['name'], value: new_secret['value'])
16
+ secrets.append(secret)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def check_duplicates
23
+ duplicates = []
24
+ groupped_secrets = secrets.group_by { |secret| secret['name'] }
25
+ groupped_secrets.each_pair do |key, value|
26
+ duplicates << key if value.size > 1
27
+ end
28
+
29
+ error_message = I18n.t('secrets.duplicates_exists', secrets: duplicates.join(', '))
30
+ errors.add(:secrets, error_message) if duplicates.present?
31
+ end
32
+
33
+ def check_length
34
+ secrets_with_invalid_key_length = secrets.select { |secret| secret['name'].length > MAX_SECRET_KEY_LENGTH }
35
+
36
+ error_message = I18n.t('secrets.invalid_key_length')
37
+ errors.add(:secrets, error_message) if secrets_with_invalid_key_length.present?
38
+ end
39
+ end