livebook/test/livebook_web/live/session_live/secrets_component_test.exs
2023-03-07 15:24:07 -03:00

230 lines
8.3 KiB
Elixir

defmodule LivebookWeb.SessionLive.SecretsComponentTest do
use Livebook.EnterpriseIntegrationCase, async: true
import Livebook.SessionHelpers
import Phoenix.LiveViewTest
alias Livebook.Session
alias Livebook.Sessions
describe "enterprise" do
setup %{test: name} do
start_new_instance(name)
node = EnterpriseServer.get_node(name)
url = EnterpriseServer.url(name)
token = EnterpriseServer.token(name)
id = :erpc.call(node, Enterprise.Integration, :fetch_env!, ["ENTERPRISE_ID"])
hub_id = "enterprise-#{id}"
Livebook.Hubs.subscribe([:connection, :secrets])
Livebook.Hubs.delete_hub(hub_id)
enterprise =
insert_hub(:enterprise,
id: hub_id,
external_id: id,
url: url,
token: token
)
{:ok, session} = Sessions.create_session(notebook: Livebook.Notebook.new())
Session.set_notebook_hub(session.pid, hub_id)
on_exit(fn ->
Livebook.Hubs.delete_hub(hub_id)
Session.close(session.pid)
stop_new_instance(name)
end)
{:ok, enterprise: enterprise, session: session, node: node}
end
test "creates a secret on Enterprise hub",
%{conn: conn, session: session, enterprise: enterprise} do
id = enterprise.id
secret =
build(:secret, name: "BIG_IMPORTANT_SECRET", value: "123", hub_id: id, readonly: true)
{:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}/secrets")
attrs = %{
secret: %{
name: secret.name,
value: secret.value,
hub_id: enterprise.id
}
}
form = element(view, ~s{form[phx-submit="save"]})
render_change(form, attrs)
render_submit(form, attrs)
assert_receive {:secret_created, ^secret}
assert render(view) =~ "A new secret has been created on your Livebook Hub"
assert has_element?(view, "#hub-#{enterprise.id}-secret-#{secret.name}-wrapper")
end
test "toggle a secret from Enterprise hub",
%{conn: conn, session: session, enterprise: enterprise, node: node} do
secret =
build(:secret,
name: "POSTGRES_PASSWORD",
value: "postgres",
hub_id: enterprise.id,
readonly: true
)
{:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}")
:erpc.call(node, Enterprise.Integration, :create_secret, [secret.name, secret.value])
assert_receive {:secret_created, ^secret}
Session.set_secret(session.pid, secret)
assert_session_secret(view, session.pid, secret)
end
test "adding a missing secret using 'Add secret' button",
%{conn: conn, session: session, enterprise: enterprise} do
secret =
build(:secret,
name: "PGPASS",
value: "postgres",
hub_id: enterprise.id,
readonly: true
)
# Subscribe and executes the code to trigger
# the `System.EnvError` exception and outputs the 'Add secret' button
Session.subscribe(session.id)
section_id = insert_section(session.pid)
code = ~s{System.fetch_env!("LB_#{secret.name}")}
cell_id = insert_text_cell(session.pid, section_id, :code, code)
Session.queue_cell_evaluation(session.pid, cell_id)
assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
# Enters the session to check if the button exists
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
add_secret_button = element(view, "a[href='#{expected_url}']")
assert has_element?(add_secret_button)
# Clicks the button and fills the form to create a new secret
# that prefilled the name with the received from exception.
render_click(add_secret_button)
secrets_component = with_target(view, "#secrets-modal")
form_element = element(secrets_component, "form[phx-submit='save']")
assert has_element?(form_element)
attrs = %{value: secret.value, hub_id: enterprise.id}
render_submit(form_element, %{secret: attrs})
# Checks we received the secret created event from Enterprise
assert_receive {:secret_created, ^secret}
# Checks if the secret is persisted
assert secret in Livebook.Hubs.get_secrets()
# Checks if the secret exists and is inside the session,
# then executes the code cell again and checks if the
# secret value is what we expected.
assert_session_secret(view, session.pid, secret)
Session.queue_cell_evaluation(session.pid, cell_id)
assert_receive {:operation,
{:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
assert output == "\e[32m\"#{secret.value}\"\e[0m"
end
test "granting access for missing secret using 'Add secret' button",
%{conn: conn, session: session, enterprise: enterprise, node: node} do
secret =
build(:secret,
name: "MYSQL_PASS",
value: "admin",
hub_id: enterprise.id,
readonly: true
)
# Subscribe and executes the code to trigger
# the `System.EnvError` exception and outputs the 'Add secret' button
Session.subscribe(session.id)
section_id = insert_section(session.pid)
code = ~s{System.fetch_env!("LB_#{secret.name}")}
cell_id = insert_text_cell(session.pid, section_id, :code, code)
Session.queue_cell_evaluation(session.pid, cell_id)
assert_receive {:operation, {:add_cell_evaluation_response, _, ^cell_id, _, _}}
# Enters the session to check if the button exists
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
add_secret_button = element(view, "a[href='#{expected_url}']")
assert has_element?(add_secret_button)
# Persist the secret from the Enterprise
:erpc.call(node, Enterprise.Integration, :create_secret, [secret.name, secret.value])
# Grant we receive the event, even with eventually delay
assert_receive {:secret_created, ^secret}, 10_000
# Checks if the secret is persisted
assert secret in Livebook.Hubs.get_secrets()
# Clicks the button and checks if the 'Grant access' banner
# is being shown, so clicks it's button to set the app secret
# to the session, allowing the user to fetches the secret.
render_click(add_secret_button)
secrets_component = with_target(view, "#secrets-modal")
assert render(secrets_component) =~
"in #{hub_label(enterprise)}. Allow this session to access it?"
grant_access_button = element(secrets_component, "button", "Grant access")
render_click(grant_access_button)
# Checks if the secret exists and is inside the session,
# then executes the code cell again and checks if the
# secret value is what we expected.
assert_session_secret(view, session.pid, secret)
Session.queue_cell_evaluation(session.pid, cell_id)
assert_receive {:operation,
{:add_cell_evaluation_response, _, ^cell_id, {:text, output}, _}}
assert output == "\e[32m\"#{secret.value}\"\e[0m"
end
test "shows secret events from Enterprise hub",
%{conn: conn, session: session, enterprise: enterprise, node: node} do
{:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}/secrets")
secret =
build(:secret,
name: "EVENT_SECRET",
value: "123",
hub_id: enterprise.id,
readonly: true
)
# We need the `Secret` schema from enterprise to execute
# the following functions inside `Enterprise.Integration`
enterprise_secret =
:erpc.call(node, Enterprise.Integration, :create_secret, [secret.name, secret.value])
assert_receive {:secret_created, ^secret}
assert render(view) =~ "A new secret has been created on your Livebook Hub"
:erpc.call(node, Enterprise.Integration, :update_secret, [enterprise_secret, secret.value])
assert_receive {:secret_updated, ^secret}
assert render(view) =~ "An existing secret has been updated on your Livebook Hub"
:erpc.call(node, Enterprise.Integration, :delete_secret, [enterprise_secret])
assert_receive {:secret_deleted, ^secret}
assert render(view) =~ "An existing secret has been deleted on your Livebook Hub"
end
end
end