diff --git a/front/lib/front_web/controllers/settings_controller.ex b/front/lib/front_web/controllers/settings_controller.ex
index 5364f430e..b344e9231 100644
--- a/front/lib/front_web/controllers/settings_controller.ex
+++ b/front/lib/front_web/controllers/settings_controller.ex
@@ -90,6 +90,39 @@ defmodule FrontWeb.SettingsController do
)
end
+ def confirm_enforce_workflow(conn, _params) do
+ org_id = conn.assigns.organization_id
+ permissions = conn.assigns.permissions || %{}
+
+ if Map.get(permissions, "organization.general_settings.manage", false) do
+ case Models.OrganizationSettings.modify(org_id, %{"enforce_whitelist" => "true"}) do
+ {:ok, _updated_settings} ->
+ conn
+ |> put_flash(:notice, "Whitelist enforcement applied successfully.")
+ |> redirect(to: settings_path(conn, :show))
+
+ {:error, %Ecto.Changeset{} = changeset} ->
+ errors =
+ changeset.errors |> Enum.map(fn {field, {message, _}} -> "#{field}: #{message}" end)
+
+ conn
+ |> put_flash(:errors, errors)
+ |> put_flash(:alert, "Failed to apply whitelist enforcement.")
+ |> redirect(to: settings_path(conn, :show))
+
+ {:error, reason} ->
+ conn
+ |> put_flash(:errors, ["#{inspect(reason)}"])
+ |> put_flash(:alert, "Failed to apply whitelist enforcement.")
+ |> redirect(to: settings_path(conn, :show))
+ end
+ else
+ conn
+ |> put_flash(:alert, "Insufficient permissions.")
+ |> redirect(to: settings_path(conn, :show))
+ end
+ end
+
def confirm_delete(conn, _params) do
org_id = conn.assigns.organization_id
diff --git a/front/lib/front_web/router.ex b/front/lib/front_web/router.ex
index caf202a58..0e3fb417a 100644
--- a/front/lib/front_web/router.ex
+++ b/front/lib/front_web/router.ex
@@ -126,6 +126,8 @@ defmodule FrontWeb.Router do
get("/settings/confirm_delete", SettingsController, :confirm_delete)
+ post("/settings/confirm_enforce", SettingsController, :confirm_enforce_workflow)
+
delete("/settings", SettingsController, :destroy)
get("/jwt_config", OrganizationJWTConfigController, :show)
diff --git a/front/lib/front_web/templates/settings/show.html.eex b/front/lib/front_web/templates/settings/show.html.eex
index f62c83164..a5225070a 100644
--- a/front/lib/front_web/templates/settings/show.html.eex
+++ b/front/lib/front_web/templates/settings/show.html.eex
@@ -37,6 +37,16 @@
<% end %>
+
+
Whitelist Enforcement
+
Applies new Whitelist rules to old tags and branches
+
+ <%= link "Enforce Whitelist",
+ to: settings_path(@conn, :confirm_enforce_workflow),
+ method: :post,
+ class: "btn btn-secondary danger" %>
+
+
<%= if FeatureProvider.feature_enabled?(:multiple_organizations, param: @conn.assigns[:organization_id]) do %>
<%= if @permissions["organization.delete"] do %>
diff --git a/front/test/front_web/controllers/settings_controller_test.exs b/front/test/front_web/controllers/settings_controller_test.exs
index de5eab32c..2b0cdc6ae 100644
--- a/front/test/front_web/controllers/settings_controller_test.exs
+++ b/front/test/front_web/controllers/settings_controller_test.exs
@@ -2,6 +2,8 @@ defmodule FrontWeb.SettingsControllerTest do
use FrontWeb.ConnCase
alias Support.Stubs.DB
+ import Mock
+
setup %{conn: conn} do
Cacheman.clear(:front)
@@ -201,6 +203,86 @@ defmodule FrontWeb.SettingsControllerTest do
end
end
+ describe "POST confirm_enforce_workflow" do
+ test "when the user lacks manage permissions => denies the request", %{
+ conn: conn,
+ organization_id: organization_id
+ } do
+ with_mock Front.Models.OrganizationSettings,
+ modify: fn ^organization_id, _ ->
+ send(self(), :modify_called)
+ {:ok, %{}}
+ end do
+ conn =
+ conn
+ |> post("/settings/confirm_enforce")
+
+ assert redirected_to(conn) =~ "/settings"
+ assert get_flash(conn, :alert) == "Insufficient permissions."
+ refute_received :modify_called
+ end
+ end
+
+ test "when the user can manage general settings => applies the enforcement", %{
+ conn: conn,
+ user_id: user_id,
+ organization_id: organization_id
+ } do
+ Support.Stubs.PermissionPatrol.add_permissions(
+ organization_id,
+ user_id,
+ ["organization.view", "organization.general_settings.manage"]
+ )
+
+ with_mock Front.Models.OrganizationSettings,
+ modify: fn ^organization_id, %{"enforce_whitelist" => "true"} ->
+ send(self(), :modify_called)
+ {:ok, %{}}
+ end do
+ conn =
+ conn
+ |> post("/settings/confirm_enforce")
+
+ assert redirected_to(conn) == "/settings"
+ assert get_flash(conn, :notice) == "Whitelist enforcement applied successfully."
+ assert_received :modify_called
+ end
+ end
+
+ test "when enforcing fails => shows the error", %{
+ conn: conn,
+ user_id: user_id,
+ organization_id: organization_id
+ } do
+ Support.Stubs.PermissionPatrol.add_permissions(
+ organization_id,
+ user_id,
+ ["organization.view", "organization.general_settings.manage"]
+ )
+
+ changeset = %Ecto.Changeset{
+ valid?: false,
+ changes: %{},
+ errors: [enforce_whitelist: {"boom", []}],
+ data: %{},
+ types: %{}
+ }
+
+ with_mock Front.Models.OrganizationSettings,
+ modify: fn ^organization_id, %{"enforce_whitelist" => "true"} ->
+ {:error, changeset}
+ end do
+ conn =
+ conn
+ |> post("/settings/confirm_enforce")
+
+ assert redirected_to(conn) == "/settings"
+ assert get_flash(conn, :alert) == "Failed to apply whitelist enforcement."
+ assert get_flash(conn, :errors) == ["enforce_whitelist: boom"]
+ end
+ end
+ end
+
describe "DELETE destroy" do
test "when everything works => redirects to me page", %{
conn: conn,