diff --git a/Makefile b/Makefile
index b496919e72..d0e6124aac 100644
--- a/Makefile
+++ b/Makefile
@@ -93,6 +93,14 @@ sso-stop:
docker stop idp
docker remove idp
+generate-corefile:
+ $(call require, integration_id)
+ integration_id=$(integration_id) envsubst < $(PWD)/extra/fixture/Corefile.template > $(PWD)/extra/fixture/Corefile.gen.$(integration_id)
+
+mock-dns: generate-corefile
+ $(call require, integration_id)
+ docker run --rm -p 5353:53/udp -v $(PWD)/extra/fixture/Corefile.gen.$(integration_id):/Corefile coredns/coredns:latest -conf Corefile
+
loadtest-server:
@echo "Ensure your OTP installation is built with --enable-lock-counter"
MIX_ENV=load ERL_FLAGS="-emu_type lcnt +Mdai max" iex -S mix do phx.digest + phx.server
diff --git a/config/.env.dev b/config/.env.dev
index 87cfab1031..a2122f288d 100644
--- a/config/.env.dev
+++ b/config/.env.dev
@@ -15,6 +15,7 @@ SHOW_CITIES=true
PADDLE_VENDOR_AUTH_CODE=895e20d4efaec0575bb857f44b183217b332d9592e76e69b8a
PADDLE_VENDOR_ID=3942
SSO_ENABLED=true
+SSO_VERIFICATION_NAMESERVERS=0.0.0.0:5353
GOOGLE_CLIENT_ID=875387135161-l8tp53dpt7fdhdg9m1pc3vl42si95rh0.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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
diff --git a/config/runtime.exs b/config/runtime.exs
index 6322db7532..bf937a7c06 100644
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -312,6 +312,23 @@ sso_saml_adapter =
"real" -> PlausibleWeb.SSO.RealSAMLAdapter
end
+sso_verification_nameservers =
+ case get_var_from_path_or_env(config_dir, "SSO_VERIFICATION_NAMESERVERS") do
+ nil ->
+ []
+
+ some ->
+ some
+ |> String.split(",")
+ |> Enum.map(fn addr ->
+ uri = URI.parse("dns://#{addr}")
+ host = uri.host
+ port = uri.port || 53
+ {:ok, addr} = :inet.parse_address(to_charlist(host))
+ {addr, port}
+ end)
+ end
+
config :plausible,
environment: env,
mailer_email: mailer_email,
@@ -323,7 +340,8 @@ config :plausible,
data_dir: data_dir,
session_transfer_dir: session_transfer_dir,
sso_enabled: sso_enabled,
- sso_saml_adapter: sso_saml_adapter
+ sso_saml_adapter: sso_saml_adapter,
+ sso_verification_nameservers: sso_verification_nameservers
config :plausible, :selfhost,
enable_email_verification: enable_email_verification,
diff --git a/extra/fixture/.gitignore b/extra/fixture/.gitignore
new file mode 100644
index 0000000000..1d43f5366c
--- /dev/null
+++ b/extra/fixture/.gitignore
@@ -0,0 +1 @@
+Corefile.gen.*
diff --git a/extra/fixture/Corefile.template b/extra/fixture/Corefile.template
new file mode 100644
index 0000000000..c7decfab01
--- /dev/null
+++ b/extra/fixture/Corefile.template
@@ -0,0 +1,9 @@
+. {
+ bind 0.0.0.0
+ template IN TXT plausible.test {
+ answer "{{ .Name }} 60 IN TXT \"plausible-sso-verification=${integration_id}\""
+ fallthrough
+ }
+ log
+ errors
+}
diff --git a/extra/lib/plausible/auth/sso.ex b/extra/lib/plausible/auth/sso.ex
index 781caa6ea9..ecebc0a774 100644
--- a/extra/lib/plausible/auth/sso.ex
+++ b/extra/lib/plausible/auth/sso.ex
@@ -11,6 +11,8 @@ defmodule Plausible.Auth.SSO do
alias Plausible.Repo
alias Plausible.Teams
+ use Plausible.Auth.SSO.Domain.Status
+
@type policy_attr() ::
{:sso_default_role, Teams.Policy.sso_member_role()}
| {:sso_session_timeout_minutes, non_neg_integer()}
@@ -184,15 +186,23 @@ defmodule Plausible.Auth.SSO do
case {check, force_deprovision?} do
{:ok, _} ->
- Repo.delete!(integration)
+ {:ok, :ok} =
+ Repo.transaction(fn ->
+ integration = Repo.preload(integration, :sso_domains)
+ Enum.each(integration.sso_domains, &SSO.Domains.cancel_verification(&1.domain))
+ Repo.delete!(integration)
+ :ok
+ end)
+
:ok
{{:error, :sso_users_present}, true} ->
- users = Repo.preload(integration, :users).users
-
{:ok, :ok} =
Repo.transaction(fn ->
+ users = Repo.preload(integration, :users).users
+ integration = Repo.preload(integration, :sso_domains)
Enum.each(users, &deprovision_user!/1)
+ Enum.each(integration.sso_domains, &SSO.Domains.cancel_verification(&1.domain))
Repo.delete!(integration)
:ok
end)
@@ -216,7 +226,7 @@ defmodule Plausible.Auth.SSO do
)
domains = Enum.flat_map(integrations, & &1.sso_domains)
- no_verified_domains? = Enum.all?(domains, &(&1.status != :verified))
+ no_verified_domains? = Enum.all?(domains, &(&1.status != Status.verified()))
cond do
integrations == [] -> {:error, :no_integration}
diff --git a/extra/lib/plausible/auth/sso/domain.ex b/extra/lib/plausible/auth/sso/domain.ex
index 938ceb15dc..cf4c722e38 100644
--- a/extra/lib/plausible/auth/sso/domain.ex
+++ b/extra/lib/plausible/auth/sso/domain.ex
@@ -25,6 +25,8 @@ defmodule Plausible.Auth.SSO.Domain do
@spec verification_methods() :: list(verification_method())
def verification_methods(), do: @verification_methods
+ use Plausible.Auth.SSO.Domain.Status
+
schema "sso_domains" do
field :identifier, Ecto.UUID
field :domain, :string
@@ -32,8 +34,8 @@ defmodule Plausible.Auth.SSO.Domain do
field :last_verified_at, :naive_datetime
field :status, Ecto.Enum,
- values: [:pending, :in_progress, :verified, :unverified],
- default: :pending
+ values: Status.all(),
+ default: Status.pending()
belongs_to :sso_integration, Plausible.Auth.SSO.Integration
@@ -59,11 +61,11 @@ defmodule Plausible.Auth.SSO.Domain do
|> change()
|> put_change(:verified_via, method)
|> put_change(:last_verified_at, now)
- |> put_change(:status, :verified)
+ |> put_change(:status, Status.verified())
end
@spec unverified_changeset(t(), NaiveDateTime.t(), atom()) :: Ecto.Changeset.t()
- def unverified_changeset(sso_domain, now, status \\ :in_progress) do
+ def unverified_changeset(sso_domain, now, status \\ Status.in_progress()) do
sso_domain
|> change()
|> put_change(:verified_via, nil)
diff --git a/extra/lib/plausible/auth/sso/domain/status.ex b/extra/lib/plausible/auth/sso/domain/status.ex
new file mode 100644
index 0000000000..730417f37a
--- /dev/null
+++ b/extra/lib/plausible/auth/sso/domain/status.ex
@@ -0,0 +1,21 @@
+defmodule Plausible.Auth.SSO.Domain.Status do
+ @moduledoc false
+
+ defmacro __using__(opts) do
+ as = Keyword.get(opts, :as, Status)
+
+ quote do
+ require Plausible.Auth.SSO.Domain.Status
+ alias Plausible.Auth.SSO.Domain.Status, as: unquote(as)
+ end
+ end
+
+ defmacro pending(), do: :pending
+ defmacro in_progress(), do: :in_progress
+ defmacro verified(), do: :verified
+ defmacro unverified(), do: :unverified
+
+ defmacro all() do
+ [pending(), in_progress(), verified(), unverified()]
+ end
+end
diff --git a/extra/lib/plausible/auth/sso/domain/verification/worker.ex b/extra/lib/plausible/auth/sso/domain/verification/worker.ex
index 68a1027355..d50b275b34 100644
--- a/extra/lib/plausible/auth/sso/domain/verification/worker.ex
+++ b/extra/lib/plausible/auth/sso/domain/verification/worker.ex
@@ -9,29 +9,33 @@ defmodule Plausible.Auth.SSO.Domain.Verification.Worker do
queue: :sso_domain_ownership_verification,
unique: true
+ use Plausible.Auth.SSO.Domain.Status
+
alias Plausible.Auth.SSO
alias Plausible.Repo
# roughly around 34h, given the snooze back-off
@max_snoozes 14
+ @spec cancel(String.t()) :: :ok
+ def cancel(domain) do
+ {:ok, job} =
+ %{domain: domain}
+ |> new()
+ |> Oban.insert()
+
+ Oban.cancel_job(job)
+ end
+
+ @spec enqueue(String.t()) :: {:ok, Oban.Job.t()}
def enqueue(domain) do
- {:ok, result} =
- Repo.transaction(fn ->
- with {:ok, sso_domain} <- SSO.Domains.get(domain) do
- SSO.Domains.mark_unverified!(sso_domain, :in_progress)
- end
+ {:ok, job} =
+ %{domain: domain}
+ |> new()
+ |> Oban.insert()
- {:ok, job} =
- %{domain: domain}
- |> new()
- |> Oban.insert()
-
- :ok = Oban.retry_job(job)
- {:ok, job}
- end)
-
- result
+ :ok = Oban.retry_job(job)
+ {:ok, job}
end
@impl true
@@ -42,7 +46,10 @@ defmodule Plausible.Auth.SSO.Domain.Verification.Worker do
})
when attempt <= @max_snoozes do
service_opts = [
- skip_checks?: meta["skip_checks"] == true
+ skip_checks?: meta["skip_checks"] == true,
+ verification_opts: [
+ nameservers: Application.get_env(:plausible, :sso_verification_nameservers) || []
+ ]
]
service_opts =
@@ -55,7 +62,7 @@ defmodule Plausible.Auth.SSO.Domain.Verification.Worker do
case SSO.Domains.get(domain) do
{:ok, sso_domain} ->
case SSO.Domains.verify(sso_domain, service_opts) do
- %SSO.Domain{status: :verified} = verified ->
+ %SSO.Domain{status: Status.verified()} = verified ->
verification_complete(sso_domain)
{:ok, verified}
@@ -82,7 +89,7 @@ defmodule Plausible.Auth.SSO.Domain.Verification.Worker do
defp verification_failure(domain) do
with {:ok, sso_domain} <- SSO.Domains.get(domain) do
sso_domain
- |> SSO.Domains.mark_unverified!(:unverified)
+ |> SSO.Domains.mark_unverified!(Status.unverified())
|> send_failure_notification()
end
diff --git a/extra/lib/plausible/auth/sso/domains.ex b/extra/lib/plausible/auth/sso/domains.ex
index ad47e7a05e..f30a3cd785 100644
--- a/extra/lib/plausible/auth/sso/domains.ex
+++ b/extra/lib/plausible/auth/sso/domains.ex
@@ -7,8 +7,11 @@ defmodule Plausible.Auth.SSO.Domains do
alias Plausible.Auth
alias Plausible.Auth.SSO
+ alias Plausible.Auth.SSO.Domain.Verification
alias Plausible.Repo
+ use Plausible.Auth.SSO.Domain.Status
+
@spec add(SSO.Integration.t(), String.t()) ::
{:ok, SSO.Domain.t()} | {:error, Ecto.Changeset.t()}
def add(integration, domain) do
@@ -17,6 +20,34 @@ defmodule Plausible.Auth.SSO.Domains do
Repo.insert(changeset)
end
+ @spec start_verification(String.t()) :: SSO.Domain.t()
+ def start_verification(domain) when is_binary(domain) do
+ {:ok, result} =
+ Repo.transaction(fn ->
+ with {:ok, sso_domain} <- get(domain) do
+ sso_domain = mark_unverified!(sso_domain, Status.in_progress())
+ {:ok, _} = Verification.Worker.enqueue(domain)
+ {:ok, sso_domain}
+ end
+ end)
+
+ result
+ end
+
+ @spec cancel_verification(String.t()) :: :ok
+ def cancel_verification(domain) when is_binary(domain) do
+ {:ok, :ok} =
+ Repo.transaction(fn ->
+ with {:ok, sso_domain} <- get(domain) do
+ mark_unverified!(sso_domain, Status.unverified())
+ end
+
+ :ok = Verification.Worker.cancel(domain)
+ end)
+
+ :ok
+ end
+
@spec verify(SSO.Domain.t(), Keyword.t()) :: SSO.Domain.t()
def verify(%SSO.Domain{} = sso_domain, opts \\ []) do
skip_checks? = Keyword.get(opts, :skip_checks?, false)
@@ -69,7 +100,7 @@ defmodule Plausible.Auth.SSO.Domains do
inner_join: i in assoc(d, :sso_integration),
inner_join: t in assoc(i, :team),
where: d.domain == ^search,
- where: d.status == :verified,
+ where: d.status == ^Status.verified(),
preload: [sso_integration: {i, team: t}]
)
|> Repo.one()
@@ -90,17 +121,21 @@ defmodule Plausible.Auth.SSO.Domains do
case {check, force_deprovision?} do
{:ok, _} ->
- Repo.delete!(sso_domain)
+ {:ok, :ok} =
+ Repo.transaction(fn ->
+ Repo.delete!(sso_domain)
+ :ok = cancel_verification(sso_domain.domain)
+ end)
+
:ok
{{:error, :sso_users_present}, true} ->
- domain_users = users_by_domain(sso_domain)
-
{:ok, :ok} =
Repo.transaction(fn ->
+ domain_users = users_by_domain(sso_domain)
Enum.each(domain_users, &SSO.deprovision_user!/1)
Repo.delete!(sso_domain)
- :ok
+ cancel_verification(sso_domain.domain)
end)
:ok
diff --git a/extra/lib/plausible_web/live/sso_management.ex b/extra/lib/plausible_web/live/sso_management.ex
index 89b280d214..b47d1c6248 100644
--- a/extra/lib/plausible_web/live/sso_management.ex
+++ b/extra/lib/plausible_web/live/sso_management.ex
@@ -8,13 +8,16 @@ defmodule PlausibleWeb.Live.SSOManagement do
alias Plausible.Teams
alias PlausibleWeb.Router.Helpers, as: Routes
+ use Plausible.Auth.SSO.Domain.Status
- @fake_verify_interval :timer.seconds(10)
+ @refresh_integration_interval :timer.seconds(5)
def mount(_params, _session, socket) do
socket = load_integration(socket, socket.assigns.current_team)
- Process.send_after(self(), :fake_domain_verify, @fake_verify_interval)
+ if connected?(socket) do
+ Process.send_after(self(), :refresh_integration, @refresh_integration_interval)
+ end
{:ok, route_mode(socket)}
end
@@ -172,7 +175,7 @@ defmodule PlausibleWeb.Live.SSOManagement do
Verifying domain {@domain.domain}
-
You can verify the domain using one of 3 methods:
+
You can verify ownership of the domain using one of 3 methods:
-
@@ -201,8 +204,20 @@ defmodule PlausibleWeb.Live.SSOManagement do
-
"""
@@ -296,16 +311,31 @@ defmodule PlausibleWeb.Live.SSOManagement do
<.table rows={@integration.sso_domains}>
<:thead>
<.th>Domain
- <.th>Added at
+ <.th hide_on_mobile>Added at
<.th>Status
<.th invisible>Actions
<:tbody :let={domain}>
<.td>{domain.domain}
- <.td>{Calendar.strftime(domain.inserted_at, "%b %-d, %Y at %H:%m UTC")}
- <.td>{domain.status}
+ <.td hide_on_mobile>
+ {Calendar.strftime(domain.inserted_at, "%b %-d, %Y at %H:%m UTC")}
+
+ <.td :if={domain.status != Status.in_progress()}>{domain.status}
+ <.td :if={domain.status == Status.in_progress()}>
+
+ <.spinner class="w-4 h-4" />
+ <.styled_link
+ id={"cancel-verify-domain-#{domain.identifier}"}
+ phx-click="cancel-verify-domain"
+ phx-value-identifier={domain.identifier}
+ >
+ Cancel
+
+
+
<.td actions>
<.styled_link
+ :if={domain.status not in [Status.in_progress(), Status.verified()]}
id={"verify-domain-#{domain.identifier}"}
phx-click="verify-domain"
phx-value-identifier={domain.identifier}
@@ -458,8 +488,16 @@ defmodule PlausibleWeb.Live.SSOManagement do
{:noreply, socket}
end
- def handle_event("show-manage", _params, socket) do
- {:noreply, route_mode(socket, :manage)}
+ def handle_event("verify-domain-submit", params, socket) do
+ integration = socket.assigns.integration
+ sso_domain = Enum.find(integration.sso_domains, &(&1.identifier == params["identifier"]))
+
+ if sso_domain do
+ SSO.Domains.start_verification(sso_domain.domain)
+ {:noreply, route_mode(load_integration(socket, socket.assigns.current_team), :manage)}
+ else
+ {:noreply, socket}
+ end
end
def handle_event("show-domain-setup", _params, socket) do
@@ -483,6 +521,21 @@ defmodule PlausibleWeb.Live.SSOManagement do
end
end
+ def handle_event("cancel-verify-domain", params, socket) do
+ integration = socket.assigns.integration
+ domain = Enum.find(integration.sso_domains, &(&1.identifier == params["identifier"]))
+
+ socket =
+ if domain do
+ :ok = SSO.Domains.cancel_verification(domain.domain)
+ load_integration(socket, socket.assigns.current_team)
+ else
+ socket
+ end
+
+ {:noreply, socket}
+ end
+
def handle_event("remove-domain", params, socket) do
integration = socket.assigns.integration
domain = Enum.find(integration.sso_domains, &(&1.identifier == params["identifier"]))
@@ -551,29 +604,9 @@ defmodule PlausibleWeb.Live.SSOManagement do
{:noreply, socket}
end
- def handle_info(:fake_domain_verify, %{assigns: %{integration: integration}} = socket)
- when not is_nil(integration) do
- sso_domains =
- integration.sso_domains
- |> Enum.map(fn domain ->
- if domain.status == :pending do
- SSO.Domains.verify(domain, skip_checks?: true)
- else
- domain
- end
- end)
-
- Process.send_after(self(), :fake_domain_verify, @fake_verify_interval)
-
- integration = %{integration | sso_domains: sso_domains}
-
- {:noreply, assign(socket, :integration, integration)}
- end
-
- def handle_info(:fake_domain_verify, socket) do
- Process.send_after(self(), :fake_domain_verify, @fake_verify_interval)
-
- {:noreply, socket}
+ def handle_info(:refresh_integration, socket) do
+ Process.send_after(self(), :refresh_integration, @refresh_integration_interval)
+ {:noreply, load_integration(socket, socket.assigns.current_team)}
end
defp load_integration(socket, team) do
diff --git a/test/plausible/auth/sso/domain/validation_test.exs b/test/plausible/auth/sso/domain/verification_test.exs
similarity index 100%
rename from test/plausible/auth/sso/domain/validation_test.exs
rename to test/plausible/auth/sso/domain/verification_test.exs
diff --git a/test/plausible/auth/sso/domains_test.exs b/test/plausible/auth/sso/domains_test.exs
index c2332f307f..e3501ff4f8 100644
--- a/test/plausible/auth/sso/domains_test.exs
+++ b/test/plausible/auth/sso/domains_test.exs
@@ -6,6 +6,8 @@ defmodule Plausible.Auth.SSO.DomainsTest do
on_ee do
use Plausible.Teams.Test
+ use Plausible.Auth.SSO.Domain.Status
+ use Oban.Testing, repo: Plausible.Repo
alias Plausible.Auth.SSO
alias Plausible.Teams
@@ -29,7 +31,7 @@ defmodule Plausible.Auth.SSO.DomainsTest do
assert is_binary(sso_domain.identifier)
refute sso_domain.verified_via
refute sso_domain.last_verified_at
- assert sso_domain.status == :pending
+ assert sso_domain.status == Status.pending()
end
test "normalizes domain before adding", %{integration: integration} do
@@ -110,7 +112,7 @@ defmodule Plausible.Auth.SSO.DomainsTest do
assert verified_domain.id == sso_domain.id
assert verified_domain.verified_via == :dns_txt
- assert verified_domain.status == :verified
+ assert verified_domain.status == Status.verified()
assert verified_domain.last_verified_at
end
@@ -124,11 +126,49 @@ defmodule Plausible.Auth.SSO.DomainsTest do
assert unverified_domain.id == sso_domain.id
refute unverified_domain.verified_via
- assert unverified_domain.status == :in_progress
+ assert unverified_domain.status == Status.in_progress()
assert unverified_domain.last_verified_at
end
end
+ describe "start_verification/1" do
+ test "no domain" do
+ assert {:error, :not_found} = SSO.Domains.start_verification("example.com")
+ end
+
+ test "sets domain status to in progress", %{integration: integration} do
+ domain = generate_domain()
+ {:ok, _} = SSO.Domains.add(integration, domain)
+ assert {:ok, sso_domain} = SSO.Domains.start_verification(domain)
+ assert sso_domain.status == Status.in_progress()
+ end
+
+ test "enqueues background work", %{integration: integration} do
+ domain = generate_domain()
+ {:ok, _} = SSO.Domains.add(integration, domain)
+ assert {:ok, _} = SSO.Domains.start_verification(domain)
+
+ assert_enqueued(
+ worker: Plausible.Auth.SSO.Domain.Verification.Worker,
+ args: %{domain: domain}
+ )
+ end
+ end
+
+ describe "cancel_verification/1" do
+ test "no domain" do
+ assert :ok = SSO.Domains.cancel_verification("example.com")
+ end
+
+ test "sets domain status to unverified", %{integration: integration} do
+ domain = generate_domain()
+ {:ok, _} = SSO.Domains.add(integration, domain)
+ assert {:ok, sso_domain} = SSO.Domains.start_verification(domain)
+ assert :ok = SSO.Domains.cancel_verification(domain)
+ assert Repo.reload!(sso_domain).status == Status.unverified()
+ end
+ end
+
describe "lookup/1" do
test "looks up domain by email", %{integration: integration} do
domain = generate_domain()
diff --git a/test/plausible/auth/sso_test.exs b/test/plausible/auth/sso_test.exs
index 76d676ef7e..813aabaf82 100644
--- a/test/plausible/auth/sso_test.exs
+++ b/test/plausible/auth/sso_test.exs
@@ -3,6 +3,7 @@ defmodule Plausible.Auth.SSOTest do
use Plausible
on_ee do
+ use Oban.Testing, repo: Plausible.Repo
use Plausible.Teams.Test
alias Plausible.Auth
@@ -746,6 +747,50 @@ defmodule Plausible.Auth.SSOTest do
refute sso_user.sso_identity_id
refute sso_user.sso_integration_id
end
+
+ test "cancels verification jobs for all domains when integration is removed" do
+ team = new_site().team
+
+ integration = SSO.initiate_saml_integration(team)
+ domain1 = "example-#{Enum.random(1..10_000)}.com"
+ domain2 = "test-#{Enum.random(1..10_000)}.com"
+
+ {:ok, _} = SSO.Domains.add(integration, domain1)
+ {:ok, _} = SSO.Domains.add(integration, domain2)
+
+ {:ok, _} = SSO.Domains.start_verification(domain1)
+ {:ok, _} = SSO.Domains.start_verification(domain2)
+
+ assert_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain1})
+ assert_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain2})
+
+ assert :ok = SSO.remove_integration(integration)
+
+ refute Repo.reload(integration)
+ refute_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain1})
+ refute_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain2})
+ end
+
+ test "cancels verification jobs when integration is force removed with SSO users" do
+ team = new_site().team
+
+ integration = SSO.initiate_saml_integration(team)
+ domain = "example-#{Enum.random(1..10_000)}.com"
+
+ {:ok, sso_domain} = SSO.Domains.add(integration, domain)
+ SSO.Domains.verify(sso_domain, skip_checks?: true)
+
+ identity = new_identity("Test User", "test@" <> domain)
+ {:ok, _, _, _} = SSO.provision_user(identity)
+
+ {:ok, _} = SSO.Domains.start_verification(domain)
+ assert_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain})
+
+ assert :ok = SSO.remove_integration(integration, force_deprovision?: true)
+
+ refute Repo.reload(integration)
+ refute_enqueued(worker: SSO.Domain.Verification.Worker, args: %{domain: domain})
+ end
end
defp new_identity(name, email, id \\ Ecto.UUID.generate()) do
diff --git a/test/plausible_web/live/sso_management_test.exs b/test/plausible_web/live/sso_management_test.exs
index f2ea62906c..688aa4859c 100644
--- a/test/plausible_web/live/sso_management_test.exs
+++ b/test/plausible_web/live/sso_management_test.exs
@@ -1,5 +1,6 @@
defmodule PlausibleWeb.Live.SSOMangementTest do
use PlausibleWeb.ConnCase, async: false
+ use Oban.Testing, repo: Plausible.Repo
@moduletag :ee_only
@@ -108,7 +109,12 @@ defmodule PlausibleWeb.Live.SSOMangementTest do
text = render(lv) |> text()
assert text =~ "Verifying domain"
- lv |> element("form#show-manage") |> render_submit()
+ lv |> element("form#verify-domain-submit") |> render_submit()
+
+ assert_enqueued(
+ worker: SSO.Domain.Verification.Worker,
+ args: %{domain: "example.com"}
+ )
html = render(lv)
text = text(html)
@@ -185,7 +191,12 @@ defmodule PlausibleWeb.Live.SSOMangementTest do
html = render(lv)
assert text(html) =~ "Verifying domain new.example.com"
- lv |> element("form#show-manage") |> render_submit()
+ lv |> element("form#verify-domain-submit") |> render_submit()
+
+ assert_enqueued(
+ worker: SSO.Domain.Verification.Worker,
+ args: %{domain: "new.example.com"}
+ )
text = text(render(lv))
assert text =~ "org.example.com"
diff --git a/test/workers/sso_domain_verification_worker_test.exs b/test/workers/sso_domain_verification_worker_test.exs
index 70daad72e2..6ecbfa0e91 100644
--- a/test/workers/sso_domain_verification_worker_test.exs
+++ b/test/workers/sso_domain_verification_worker_test.exs
@@ -3,15 +3,13 @@ defmodule Plausible.Auth.SSO.Domain.Verification.WorkerTest do
use Plausible
on_ee do
- use Oban.Testing, repo: Plausible.Repo
-
use Bamboo.Test, shared: true
-
- alias Plausible.Auth.SSO.Domain.Verification.Worker
+ use Oban.Testing, repo: Plausible.Repo
+ use Plausible.Auth.SSO.Domain.Status
+ use Plausible.Teams.Test
alias Plausible.Auth.SSO
-
- use Plausible.Teams.Test
+ alias Plausible.Auth.SSO.Domain.Verification.Worker
test "no sso domain cancels the job" do
assert {:cancel, :domain_not_found} =
@@ -29,6 +27,13 @@ defmodule Plausible.Auth.SSO.Domain.Verification.WorkerTest do
assert_enqueued(worker: Worker, args: %{domain: "example.com"})
end
+ test "enqueue then cancel" do
+ {:ok, _} = Worker.enqueue("example.com")
+ assert_enqueued(worker: Worker, args: %{domain: "example.com"})
+ :ok = Worker.cancel("example.com")
+ refute_enqueued(worker: Worker, args: %{domain: "example.com"})
+ end
+
describe "integration set up" do
setup do
owner = new_user()
@@ -45,19 +50,13 @@ defmodule Plausible.Auth.SSO.Domain.Verification.WorkerTest do
sso_domain: sso_domain}
end
- test "enqueue resets domain status", %{sso_domain: sso_domain} do
- %{status: :unverified} = SSO.Domains.mark_unverified!(sso_domain, :unverified)
- {:ok, _} = Worker.enqueue(sso_domain.domain)
- assert Plausible.Repo.reload!(sso_domain).status == :in_progress
- end
-
test "domain is marked as in progress and job is snoozed", %{domain: domain} do
- assert {:ok, %{status: :pending}} = SSO.Domains.get(domain)
+ assert {:ok, %{status: Status.pending()}} = SSO.Domains.get(domain)
assert {:snooze, 15} =
perform_job(Worker, %{"domain" => domain}, meta: %{bypass_checks: true})
- assert {:ok, %{status: :in_progress}} = SSO.Domains.get(domain)
+ assert {:ok, %{status: Status.in_progress()}} = SSO.Domains.get(domain)
assert {:snooze, 7680} =
perform_job(Worker, %{"domain" => domain},
@@ -65,7 +64,7 @@ defmodule Plausible.Auth.SSO.Domain.Verification.WorkerTest do
meta: %{bypass_checks: true}
)
- assert {:ok, %{status: :in_progress}} = SSO.Domains.get(domain)
+ assert {:ok, %{status: Status.in_progress()}} = SSO.Domains.get(domain)
end
test "domain is marked as verified and emails are sent", %{
@@ -75,7 +74,7 @@ defmodule Plausible.Auth.SSO.Domain.Verification.WorkerTest do
} do
owner2 = add_member(team, role: :owner)
- assert {:ok, %{status: :verified}} =
+ assert {:ok, %{status: Status.verified()}} =
perform_job(Worker, %{"domain" => domain}, meta: %{skip_checks: true})
assert_email_delivered_with(