Shows error message if deployment is unauthorized

This commit is contained in:
Alexandre de Souza 2025-08-08 17:47:48 -03:00
parent e9c131eb1c
commit 4edafb0a92
No known key found for this signature in database
GPG key ID: E39228FFBA346545
3 changed files with 108 additions and 4 deletions

View file

@ -8,6 +8,7 @@ defmodule Livebook.Teams.Requests do
@deploy_key_prefix Teams.Constants.deploy_key_prefix()
@error_message "Something went wrong, try again later or please file a bug if it persists"
@unauthorized_error_message "You are not authorized to perform this action, make sure you have the access and you are not in a Livebook App Server/Offline instance"
@unauthorized_app_deployment_error_message "You are not authorized to perform this action, make sure you have the access to deploy apps to this deployment group"
@typep api_result :: {:ok, map()} | error_result()
@typep error_result :: {:error, map() | String.t()} | {:transport_error, String.t()}
@ -300,6 +301,11 @@ defmodule Livebook.Teams.Requests do
defp upload(path, content, params, team) do
build_req(team)
|> Req.Request.put_header("content-length", "#{byte_size(content)}")
|> Req.Request.append_response_steps(
livebook_put_private: fn {request, response} ->
{request, Req.Response.put_private(response, :livebook_app_deployment, true)}
end
)
|> Req.post(url: path, params: params, body: content)
|> handle_response()
|> dispatch_messages(team)
@ -337,10 +343,20 @@ defmodule Livebook.Teams.Requests do
defp handle_response(response) do
case response do
{:ok, %{status: status} = response} when status in 200..299 -> {:ok, response.body}
{:ok, %{status: status} = response} when status in [410, 422] -> return_error(response)
{:ok, %{status: 401}} -> {:transport_error, @unauthorized_error_message}
_otherwise -> {:transport_error, @error_message}
{:ok, %{status: status} = response} when status in 200..299 ->
{:ok, response.body}
{:ok, %{status: status} = response} when status in [410, 422] ->
return_error(response)
{:ok, %{status: 401, private: %{livebook_app_deployment: true}}} ->
{:transport_error, @unauthorized_app_deployment_error_message}
{:ok, %{status: 401}} ->
{:transport_error, @unauthorized_error_message}
_otherwise ->
{:transport_error, @error_message}
end
end

View file

@ -112,6 +112,58 @@ defmodule LivebookCLI.Integration.DeployTest do
end
end
test "fails with unauthorized deploy key",
%{team: team, node: node, org: org, tmp_dir: tmp_dir} do
title = "Test CLI Deploy App"
slug = Utils.random_short_id()
app_path = Path.join(tmp_dir, "#{slug}.livemd")
{key, _} = TeamsRPC.create_deploy_key(node, org: org)
deployment_group =
TeamsRPC.create_deployment_group(node, org: org, url: @url, deploy_auth: true)
hub_id = team.id
deployment_group_id = to_string(deployment_group.id)
stamp_notebook(app_path, """
<!-- livebook:{"app_settings":{"access_type":"public","slug":"#{slug}"},"hub_id":"#{hub_id}"} -->
# #{title}
## Test Section
```elixir
IO.puts("Hello from CLI deployed app!")
```
""")
output =
ExUnit.CaptureIO.capture_io(fn ->
assert_raise(LivebookCLI.Error, "Some app deployments failed.", fn ->
assert deploy(
key,
team.teams_key,
deployment_group.id,
app_path
) == :ok
end)
end)
assert output =~ "* Preparing to deploy notebook #{slug}.livemd"
assert output =~
"* Test CLI Deploy App failed to deploy. Transport error: You are not authorized to perform this action, make sure you have the access to deploy apps to this deployment group"
refute_receive {:app_deployment_started,
%{
title: ^title,
slug: ^slug,
deployment_group_id: ^deployment_group_id,
hub_id: ^hub_id,
deployed_by: "CLI"
}}
end
test "fails with invalid deploy key", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do
slug = Utils.random_short_id()
app_path = Path.join(tmp_dir, "#{slug}.livemd")

View file

@ -603,5 +603,41 @@ defmodule LivebookWeb.Integration.SessionLiveTest do
assert render(view) =~
"Failed to pack files: the notebook and its attachments have exceeded the maximum size of 20MB"
end
test "shows an error when the deployment is unauthorized",
%{team: team, org: org, node: node, conn: conn, session: session} do
Session.set_notebook_hub(session.pid, team.id)
slug = Livebook.Utils.random_short_id()
app_settings = %{Livebook.Notebook.AppSettings.new() | slug: slug}
Session.set_app_settings(session.pid, app_settings)
deployment_group =
TeamsRPC.create_deployment_group(node, mode: :online, org: org, deploy_auth: true)
id = to_string(deployment_group.id)
assert_receive {:deployment_group_created, %{id: ^id}}
Session.set_notebook_deployment_group(session.pid, id)
assert_receive {:operation, {:set_notebook_deployment_group, _, ^id}}
%{files_dir: files_dir} = session
image_file = FileSystem.File.resolve(files_dir, "image.jpg")
:ok = FileSystem.File.write(image_file, :crypto.strong_rand_bytes(1024 * 1024))
Session.add_file_entries(session.pid, [%{type: :attachment, name: "image.jpg"}])
{:ok, view, _} = live(conn, ~p"/sessions/#{session.id}/app-teams")
# From this point forward we are in a child LV
view = find_live_child(view, "app-teams")
assert render(view) =~ "App deployment with Livebook Teams"
view
|> element("button", "Deploy")
|> render_click()
assert render(view) =~
"You are not authorized to perform this action, make sure you have the access to deploy apps to this deployment group"
end
end
end