2023-01-07 03:14:44 +08:00
|
|
|
defmodule LivebookWeb.SessionLive.SecretsComponentTest do
|
|
|
|
use Livebook.EnterpriseIntegrationCase, async: true
|
|
|
|
|
2023-02-04 00:15:46 +08:00
|
|
|
import Livebook.SessionHelpers
|
2023-01-07 03:14:44 +08:00
|
|
|
import Phoenix.LiveViewTest
|
|
|
|
|
|
|
|
alias Livebook.Session
|
|
|
|
alias Livebook.Sessions
|
|
|
|
|
|
|
|
describe "enterprise" do
|
2023-02-04 00:15:46 +08:00
|
|
|
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"])
|
2023-02-01 06:17:05 +08:00
|
|
|
hub_id = "enterprise-#{id}"
|
|
|
|
|
|
|
|
Livebook.Hubs.subscribe([:connection, :secrets])
|
|
|
|
Livebook.Hubs.delete_hub(hub_id)
|
2023-01-07 03:14:44 +08:00
|
|
|
|
|
|
|
enterprise =
|
|
|
|
insert_hub(:enterprise,
|
2023-02-01 06:17:05 +08:00
|
|
|
id: hub_id,
|
2023-01-11 04:12:35 +08:00
|
|
|
external_id: id,
|
2023-01-07 03:14:44 +08:00
|
|
|
url: url,
|
|
|
|
token: token
|
|
|
|
)
|
|
|
|
|
|
|
|
{:ok, session} = Sessions.create_session(notebook: Livebook.Notebook.new())
|
2023-03-08 02:24:07 +08:00
|
|
|
Session.set_notebook_hub(session.pid, hub_id)
|
2023-01-07 03:14:44 +08:00
|
|
|
|
|
|
|
on_exit(fn ->
|
2023-02-04 00:15:46 +08:00
|
|
|
Livebook.Hubs.delete_hub(hub_id)
|
2023-01-07 03:14:44 +08:00
|
|
|
Session.close(session.pid)
|
2023-02-04 00:15:46 +08:00
|
|
|
stop_new_instance(name)
|
2023-01-07 03:14:44 +08:00
|
|
|
end)
|
|
|
|
|
2023-02-04 00:15:46 +08:00
|
|
|
{:ok, enterprise: enterprise, session: session, node: node}
|
2023-01-07 03:14:44 +08:00
|
|
|
end
|
|
|
|
|
2023-02-04 00:15:46 +08:00
|
|
|
test "creates a secret on Enterprise hub",
|
|
|
|
%{conn: conn, session: session, enterprise: enterprise} do
|
2023-02-01 06:17:05 +08:00
|
|
|
id = enterprise.id
|
2023-03-08 02:24:07 +08:00
|
|
|
|
|
|
|
secret =
|
|
|
|
build(:secret, name: "BIG_IMPORTANT_SECRET", value: "123", hub_id: id, readonly: true)
|
|
|
|
|
2023-02-23 02:34:54 +08:00
|
|
|
{:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}/secrets")
|
2023-01-07 03:14:44 +08:00
|
|
|
|
|
|
|
attrs = %{
|
2023-02-07 07:37:11 +08:00
|
|
|
secret: %{
|
2023-02-01 06:17:05 +08:00
|
|
|
name: secret.name,
|
|
|
|
value: secret.value,
|
2023-03-08 02:24:07 +08:00
|
|
|
hub_id: enterprise.id
|
2023-01-07 03:14:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-01 06:17:05 +08:00
|
|
|
form = element(view, ~s{form[phx-submit="save"]})
|
|
|
|
render_change(form, attrs)
|
|
|
|
render_submit(form, attrs)
|
2023-01-07 03:14:44 +08:00
|
|
|
|
2023-02-04 00:15:46 +08:00
|
|
|
assert_receive {:secret_created, ^secret}
|
2023-02-28 21:55:52 +08:00
|
|
|
assert render(view) =~ "A new secret has been created on your Livebook Hub"
|
2023-02-28 00:45:14 +08:00
|
|
|
assert has_element?(view, "#hub-#{enterprise.id}-secret-#{secret.name}-wrapper")
|
2023-02-04 00:15:46 +08:00
|
|
|
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",
|
2023-03-08 02:24:07 +08:00
|
|
|
hub_id: enterprise.id,
|
|
|
|
readonly: true
|
2023-02-04 00:15:46 +08:00
|
|
|
)
|
|
|
|
|
2023-02-23 02:34:54 +08:00
|
|
|
{:ok, view, _html} = live(conn, ~p"/sessions/#{session.id}")
|
2023-02-04 00:15:46 +08:00
|
|
|
|
|
|
|
: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",
|
2023-03-08 02:24:07 +08:00
|
|
|
hub_id: enterprise.id,
|
|
|
|
readonly: true
|
2023-02-04 00:15:46 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
# 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
|
2023-02-23 02:34:54 +08:00
|
|
|
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
|
|
|
|
expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
|
2023-02-04 00:15:46 +08:00
|
|
|
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)
|
2023-03-08 02:24:07 +08:00
|
|
|
attrs = %{value: secret.value, hub_id: enterprise.id}
|
2023-02-07 07:37:11 +08:00
|
|
|
render_submit(form_element, %{secret: attrs})
|
2023-02-04 00:15:46 +08:00
|
|
|
|
|
|
|
# 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",
|
2023-03-08 02:24:07 +08:00
|
|
|
hub_id: enterprise.id,
|
|
|
|
readonly: true
|
2023-02-04 00:15:46 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
# 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
|
2023-02-23 02:34:54 +08:00
|
|
|
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}")
|
|
|
|
expected_url = ~p"/sessions/#{session.id}/secrets?secret_name=#{secret.name}"
|
2023-02-04 00:15:46 +08:00
|
|
|
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")
|
|
|
|
|
2023-03-08 02:24:07 +08:00
|
|
|
assert render(secrets_component) =~
|
|
|
|
"in #{hub_label(enterprise)}. Allow this session to access it?"
|
2023-02-04 00:15:46 +08:00
|
|
|
|
|
|
|
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"
|
2023-01-07 03:14:44 +08:00
|
|
|
end
|
2023-02-28 21:55:52 +08:00
|
|
|
|
|
|
|
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")
|
2023-03-08 02:24:07 +08:00
|
|
|
|
|
|
|
secret =
|
|
|
|
build(:secret,
|
|
|
|
name: "EVENT_SECRET",
|
|
|
|
value: "123",
|
|
|
|
hub_id: enterprise.id,
|
|
|
|
readonly: true
|
|
|
|
)
|
2023-02-28 21:55:52 +08:00
|
|
|
|
|
|
|
# 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
|
2023-01-07 03:14:44 +08:00
|
|
|
end
|
|
|
|
end
|