From c10b847324fac3be8bb8322a8479a3dbcb7596cb Mon Sep 17 00:00:00 2001 From: Giuliano Silvestro Date: Wed, 20 May 2026 18:17:13 +1000 Subject: [PATCH] Fix operator role gate: platform-admin (hyphen), not platform_admin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit arcadia-app issues the role slug "platform-admin" (hyphen) — confirmed from a live arcadia-dev JWT (roles: ["admin","platform-admin"]). Every authorization check here tested for "platform_admin" (underscore), so real operator tokens got 403 on billing / dashboard / drift and an empty tenant-scoped result on inventory. The smoke tests missed it because Guardian.mint_dev_token hardcoded the underscore form — fixed there too, so the dev helper now matches what arcadia-app actually emits. Replaced the string literal "platform_admin" -> "platform-admin" in all six controllers + guardian.ex. The platform_admin?/1 function names keep underscores (Elixir identifiers can't contain hyphens) — only the role string changed. Verified: with a platform-admin token, /inventory, /billing/balance, /dashboard/margin and /drift all return 200. Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/arcadia_cloud/guardian.ex | 2 +- lib/arcadia_cloud_web/controllers/billing_controller.ex | 2 +- lib/arcadia_cloud_web/controllers/dashboard_controller.ex | 2 +- lib/arcadia_cloud_web/controllers/deployment_controller.ex | 2 +- lib/arcadia_cloud_web/controllers/drift_controller.ex | 2 +- lib/arcadia_cloud_web/controllers/inventory_controller.ex | 2 +- lib/arcadia_cloud_web/controllers/invoice_controller.ex | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/arcadia_cloud/guardian.ex b/lib/arcadia_cloud/guardian.ex index fd383c1..f838693 100644 --- a/lib/arcadia_cloud/guardian.ex +++ b/lib/arcadia_cloud/guardian.ex @@ -44,7 +44,7 @@ defmodule ArcadiaCloud.Guardian do "tenant_id" => "tenant-dev", "tenant_slug" => "dev", "email" => "dev@example.com", - "roles" => ["platform_admin"] + "roles" => ["platform-admin"] } claims = Map.merge(defaults, claims_overrides) diff --git a/lib/arcadia_cloud_web/controllers/billing_controller.ex b/lib/arcadia_cloud_web/controllers/billing_controller.ex index 012a891..5c4130f 100644 --- a/lib/arcadia_cloud_web/controllers/billing_controller.ex +++ b/lib/arcadia_cloud_web/controllers/billing_controller.ex @@ -37,7 +37,7 @@ defmodule ArcadiaCloudWeb.BillingController do defp require_platform_admin(conn) do identity = conn.assigns.current_identity - if is_list(identity.roles) and "platform_admin" in identity.roles do + if is_list(identity.roles) and "platform-admin" in identity.roles do :ok else conn diff --git a/lib/arcadia_cloud_web/controllers/dashboard_controller.ex b/lib/arcadia_cloud_web/controllers/dashboard_controller.ex index 331589c..d3173df 100644 --- a/lib/arcadia_cloud_web/controllers/dashboard_controller.ex +++ b/lib/arcadia_cloud_web/controllers/dashboard_controller.ex @@ -31,7 +31,7 @@ defmodule ArcadiaCloudWeb.DashboardController do defp require_platform_admin(conn) do identity = conn.assigns.current_identity - if is_list(identity.roles) and "platform_admin" in identity.roles do + if is_list(identity.roles) and "platform-admin" in identity.roles do :ok else conn |> put_status(:forbidden) |> json(%{error: "platform_admin_required"}) |> halt() diff --git a/lib/arcadia_cloud_web/controllers/deployment_controller.ex b/lib/arcadia_cloud_web/controllers/deployment_controller.ex index 57e829b..6d3dda7 100644 --- a/lib/arcadia_cloud_web/controllers/deployment_controller.ex +++ b/lib/arcadia_cloud_web/controllers/deployment_controller.ex @@ -126,7 +126,7 @@ defmodule ArcadiaCloudWeb.DeploymentController do end end - defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform_admin" in roles + defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform-admin" in roles defp platform_admin?(_), do: false defp shape(d) do diff --git a/lib/arcadia_cloud_web/controllers/drift_controller.ex b/lib/arcadia_cloud_web/controllers/drift_controller.ex index 9e3415c..d772d7d 100644 --- a/lib/arcadia_cloud_web/controllers/drift_controller.ex +++ b/lib/arcadia_cloud_web/controllers/drift_controller.ex @@ -41,7 +41,7 @@ defmodule ArcadiaCloudWeb.DriftController do defp require_platform_admin(conn) do identity = conn.assigns.current_identity - if is_list(identity.roles) and "platform_admin" in identity.roles do + if is_list(identity.roles) and "platform-admin" in identity.roles do :ok else conn diff --git a/lib/arcadia_cloud_web/controllers/inventory_controller.ex b/lib/arcadia_cloud_web/controllers/inventory_controller.ex index a8d3e98..17a917c 100644 --- a/lib/arcadia_cloud_web/controllers/inventory_controller.ex +++ b/lib/arcadia_cloud_web/controllers/inventory_controller.ex @@ -35,7 +35,7 @@ defmodule ArcadiaCloudWeb.InventoryController do json(conn, %{resources: resources, count: length(resources)}) end - defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform_admin" in roles + defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform-admin" in roles defp platform_admin?(_), do: false defp maybe_put(opts, _key, nil), do: opts diff --git a/lib/arcadia_cloud_web/controllers/invoice_controller.ex b/lib/arcadia_cloud_web/controllers/invoice_controller.ex index 5cfcca4..99d8369 100644 --- a/lib/arcadia_cloud_web/controllers/invoice_controller.ex +++ b/lib/arcadia_cloud_web/controllers/invoice_controller.ex @@ -36,7 +36,7 @@ defmodule ArcadiaCloudWeb.InvoiceController do end end - defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform_admin" in roles + defp platform_admin?(%{roles: roles}) when is_list(roles), do: "platform-admin" in roles defp platform_admin?(_), do: false defp shape(i) do