diff --git a/app/actions/projects/create.rb b/app/actions/projects/create.rb index 152ca9b5..5458d035 100644 --- a/app/actions/projects/create.rb +++ b/app/actions/projects/create.rb @@ -71,8 +71,8 @@ module Projects steps << Projects::ValidateNamespaceAvailability steps << Projects::Save - # Only register webhook in non-local mode - if !Rails.application.config.local_mode && provider.git? + # Only register webhook in cloud mode + if Rails.application.config.cloud_mode && provider.git? steps << Projects::RegisterGitWebhook end diff --git a/app/controllers/accounts/stack_managers_controller.rb b/app/controllers/accounts/stack_managers_controller.rb index 35bfa84a..7ecfaa0c 100644 --- a/app/controllers/accounts/stack_managers_controller.rb +++ b/app/controllers/accounts/stack_managers_controller.rb @@ -10,6 +10,8 @@ module Accounts head :not_found end + # If the user is not having an email domain end in the + # portainer stack url, don't log them out, just return a different unauthorized. if stack_manager.stack.client.authenticated? head :ok else @@ -107,7 +109,12 @@ module Accounts private def stack_manager_params - params.require(:stack_manager).permit(:provider_url, :stack_manager_type) + params.require(:stack_manager).permit( + :provider_url, + :stack_manager_type, + :access_token, + :enable_role_based_access_control + ) end def set_stack diff --git a/app/jobs/projects/build_job.rb b/app/jobs/projects/build_job.rb index 645c676d..26befd69 100644 --- a/app/jobs/projects/build_job.rb +++ b/app/jobs/projects/build_job.rb @@ -22,7 +22,7 @@ class Projects::BuildJob < ApplicationJob Builders::BuildCloud.new( build, K8::BuildCloudManager.new( - K8::Connection.new(project, user), + K8::Connection.new(project, user, allow_anonymous: true), project.build_configuration.build_cloud ) ) diff --git a/app/models/stack_manager.rb b/app/models/stack_manager.rb index d6791370..8d4516a1 100644 --- a/app/models/stack_manager.rb +++ b/app/models/stack_manager.rb @@ -2,13 +2,14 @@ # # Table name: stack_managers # -# id :bigint not null, primary key -# access_token :string -# provider_url :string not null -# stack_manager_type :integer default("portainer"), not null -# created_at :datetime not null -# updated_at :datetime not null -# account_id :bigint not null +# id :bigint not null, primary key +# access_token :string +# enable_role_based_access_control :boolean default(TRUE) +# provider_url :string not null +# stack_manager_type :integer default("portainer"), not null +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint not null # # Indexes # @@ -40,6 +41,14 @@ class StackManager < ApplicationRecord end end + def domain_host + URI.parse(provider_url).host + end + + def is_user?(user) + user.email.ends_with?("@#{domain_host}") + end + private def strip_trailing_slash_from_provider_url diff --git a/app/services/k8/connection.rb b/app/services/k8/connection.rb index 37f3c24e..bfef4db9 100644 --- a/app/services/k8/connection.rb +++ b/app/services/k8/connection.rb @@ -1,8 +1,9 @@ class K8::Connection - attr_reader :clusterable, :user - def initialize(clusterable, user) + attr_reader :clusterable, :user, :allow_anonymous + def initialize(clusterable, user, allow_anonymous: false) @clusterable = clusterable @user = user + @allow_anonymous = allow_anonymous end def cluster @@ -24,7 +25,7 @@ class K8::Connection cluster.kubeconfig else raise StandardError.new("No stack manager found") if stack_manager.blank? - stack = stack_manager.stack.connect(user) + stack = stack_manager.stack.connect(user, allow_anonymous: allow_anonymous) stack.fetch_kubeconfig(cluster) end end diff --git a/app/views/accounts/stack_managers/_form.html.erb b/app/views/accounts/stack_managers/_form.html.erb index 7b91f4bf..2f3de1b1 100644 --- a/app/views/accounts/stack_managers/_form.html.erb +++ b/app/views/accounts/stack_managers/_form.html.erb @@ -20,9 +20,19 @@ Access Token <% end %> <%= form.text_field :access_token, class: "input input-bordered w-full" %> + <% end %> +
+ <%= form.label :enable_role_based_access_control, class: "label cursor-pointer justify-start gap-2" do %> + <%= form.check_box :enable_role_based_access_control, class: "checkbox" %> + Enable Role-Based Access Control + <% end %> +
+
diff --git a/app/views/projects/create/_new_form_git.html.erb b/app/views/projects/create/_new_form_git.html.erb index 2911fbe2..b832622f 100644 --- a/app/views/projects/create/_new_form_git.html.erb +++ b/app/views/projects/create/_new_form_git.html.erb @@ -93,13 +93,11 @@
<% end %> - <% unless Rails.application.config.local_mode %> - <%= render(FormFieldComponent.new( - label: "Autodeploy", - description: "Automatically deploy the project when the branch is pushed to." - )) do %> - <%= form.check_box :autodeploy, class: "checkbox" %> - <% end %> + <%= render(FormFieldComponent.new( + label: "Autodeploy", + description: "Automatically deploy the project when the branch is pushed to." + )) do %> + <%= form.check_box :autodeploy, class: "checkbox" %> <% end %> <%= render(FormFieldComponent.new( diff --git a/db/migrate/20251009003742_enable_role_based_access_control_to_stack_managers.rb b/db/migrate/20251009003742_enable_role_based_access_control_to_stack_managers.rb new file mode 100644 index 00000000..661ea43f --- /dev/null +++ b/db/migrate/20251009003742_enable_role_based_access_control_to_stack_managers.rb @@ -0,0 +1,5 @@ +class EnableRoleBasedAccessControlToStackManagers < ActiveRecord::Migration[7.2] + def change + add_column :stack_managers, :enable_role_based_access_control, :boolean, default: true + end +end diff --git a/db/schema.rb b/db/schema.rb index 00133d3e..dbc7bd77 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2025_10_02_214647) do +ActiveRecord::Schema[7.2].define(version: 2025_10_09_003742) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -451,6 +451,7 @@ ActiveRecord::Schema[7.2].define(version: 2025_10_02_214647) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "access_token" + t.boolean "enable_role_based_access_control", default: true t.index ["account_id"], name: "index_stack_managers_on_account_id", unique: true end diff --git a/lib/portainer/login.rb b/lib/portainer/login.rb index ffd944aa..f35a6c2c 100644 --- a/lib/portainer/login.rb +++ b/lib/portainer/login.rb @@ -6,7 +6,7 @@ class Portainer::Login executed do |context| provider_url = context.account.stack_manager.provider_url - hostname = URI.parse(provider_url).host + hostname = context.account.stack_manager.domain_host context.user = User.find_or_initialize_by( email: context.username + "@#{hostname}", ) diff --git a/lib/portainer/stack.rb b/lib/portainer/stack.rb index a6f8b5c3..7c27c7ac 100644 --- a/lib/portainer/stack.rb +++ b/lib/portainer/stack.rb @@ -11,8 +11,10 @@ class Portainer::Stack self end - def connect(user) - access_token = if stack_manager.access_token.present? + def connect(user, allow_anonymous: false) + access_token = if stack_manager.access_token.present? && !enable_role_based_access_control + stack_manager.access_token + elsif stack_manager.access_token.present? && allow_anonymous stack_manager.access_token else user.portainer_jwt diff --git a/spec/factories/stack_managers.rb b/spec/factories/stack_managers.rb index b7f03f1e..f9582541 100644 --- a/spec/factories/stack_managers.rb +++ b/spec/factories/stack_managers.rb @@ -2,13 +2,14 @@ # # Table name: stack_managers # -# id :bigint not null, primary key -# access_token :string -# provider_url :string not null -# stack_manager_type :integer default("portainer"), not null -# created_at :datetime not null -# updated_at :datetime not null -# account_id :bigint not null +# id :bigint not null, primary key +# access_token :string +# enable_role_based_access_control :boolean default(TRUE) +# provider_url :string not null +# stack_manager_type :integer default("portainer"), not null +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint not null # # Indexes # diff --git a/spec/models/stack_manager_spec.rb b/spec/models/stack_manager_spec.rb index 6ff4b39a..3d9671ba 100644 --- a/spec/models/stack_manager_spec.rb +++ b/spec/models/stack_manager_spec.rb @@ -2,13 +2,14 @@ # # Table name: stack_managers # -# id :bigint not null, primary key -# access_token :string -# provider_url :string not null -# stack_manager_type :integer default("portainer"), not null -# created_at :datetime not null -# updated_at :datetime not null -# account_id :bigint not null +# id :bigint not null, primary key +# access_token :string +# enable_role_based_access_control :boolean default(TRUE) +# provider_url :string not null +# stack_manager_type :integer default("portainer"), not null +# created_at :datetime not null +# updated_at :datetime not null +# account_id :bigint not null # # Indexes #