diff --git a/lib/towerops_web/live/agent_live/edit.ex b/lib/towerops_web/live/agent_live/edit.ex index 72bb95ed..7cf06bb6 100644 --- a/lib/towerops_web/live/agent_live/edit.ex +++ b/lib/towerops_web/live/agent_live/edit.ex @@ -11,9 +11,15 @@ defmodule ToweropsWeb.AgentLive.Edit do @impl true def mount(%{"id" => id}, _session, socket) do organization = socket.assigns.current_scope.organization + current_user = socket.assigns.current_scope.user - # Get agent token and verify it belongs to this organization - agent_token = Towerops.Repo.get_by!(AgentToken, id: id, organization_id: organization.id) + # Superadmins can edit any agent; regular users only their org's agents + agent_token = + if current_user.is_superuser do + Towerops.Repo.get!(AgentToken, id) + else + Towerops.Repo.get_by!(AgentToken, id: id, organization_id: organization.id) + end changeset = AgentToken.update_changeset(agent_token, %{}) diff --git a/lib/towerops_web/live/agent_live/show.ex b/lib/towerops_web/live/agent_live/show.ex index 9b9425cc..fdca6adb 100644 --- a/lib/towerops_web/live/agent_live/show.ex +++ b/lib/towerops_web/live/agent_live/show.ex @@ -12,10 +12,10 @@ defmodule ToweropsWeb.AgentLive.Show do agent_token = Agents.get_agent_token!(id) current_user = socket.assigns.current_scope.user - # Verify access: agent must belong to this org OR be a cloud poller (visible to superadmin) + # Verify access: agent must belong to this org, or superadmin can view any agent has_access = agent_token.organization_id == organization.id || - (agent_token.is_cloud_poller && current_user.is_superuser) + current_user.is_superuser if !has_access do raise Ecto.NoResultsError, queryable: Towerops.Agents.AgentToken diff --git a/test/towerops_web/live/agent_live_test.exs b/test/towerops_web/live/agent_live_test.exs index 18a7e411..61488340 100644 --- a/test/towerops_web/live/agent_live_test.exs +++ b/test/towerops_web/live/agent_live_test.exs @@ -493,4 +493,49 @@ defmodule ToweropsWeb.AgentLiveTest do end) end end + + describe "Show - Superadmin Cross-Org Access" do + setup %{user: user} do + Towerops.Repo.update!(Ecto.Changeset.change(user, %{is_superuser: true})) + :ok + end + + test "superadmin can view agent from another organization", %{conn: conn, organization: organization, user: user} do + {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, user.id, bypass_limits: true) + {:ok, agent_token, _token} = Agents.create_agent_token(other_org.id, "Other Org Agent") + + conn = Plug.Test.init_test_session(conn, %{"current_organization_id" => organization.id}) + + {:ok, _view, html} = live(conn, ~p"/agents/#{agent_token.id}") + + assert html =~ "Other Org Agent" + end + + test "superadmin can edit agent from another organization", %{conn: conn, organization: organization, user: user} do + {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, user.id, bypass_limits: true) + {:ok, agent_token, _token} = Agents.create_agent_token(other_org.id, "Other Org Agent") + + conn = Plug.Test.init_test_session(conn, %{"current_organization_id" => organization.id}) + + {:ok, _view, html} = live(conn, ~p"/agents/#{agent_token.id}/edit") + + assert html =~ "Edit Agent" + assert html =~ "Other Org Agent" + end + end + + describe "Show - Regular User Cross-Org Access" do + test "regular user cannot view agent from another organization", %{conn: conn, organization: organization, user: user} do + {:ok, other_org} = Towerops.Organizations.create_organization(%{name: "Other Org"}, user.id, bypass_limits: true) + {:ok, agent_token, _token} = Agents.create_agent_token(other_org.id, "Other Org Agent") + + conn = Plug.Test.init_test_session(conn, %{"current_organization_id" => organization.id}) + + capture_log(fn -> + assert_raise Ecto.NoResultsError, fn -> + live(conn, ~p"/agents/#{agent_token.id}") + end + end) + end + end end