diff --git a/docs/teams/deploy_via_cli.md b/docs/teams/deploy_via_cli.md index 694cea8fb..b5928841f 100644 --- a/docs/teams/deploy_via_cli.md +++ b/docs/teams/deploy_via_cli.md @@ -8,7 +8,7 @@ Deploying via CLI is as simple as calling `livebook deploy` with your configurat ```shell livebook deploy - --deploy-key="lb_dk_your_deploy_key_here" + --org-token="lb_ok_your_org_token_here" --teams-key="lb_tk_your_teams_key_here" --deployment-group-id="13" path/to/notebook.livemd @@ -38,17 +38,17 @@ Before using CLI deployment, ensure you have: CLI deployment requires two authentication tokens: -### Deploy key +### Org token -Deploy keys are organization-level authentication tokens that allow CLI access for deployments. +Org tokens are organization-level authentication tokens that allow CLI access for deployments. -To create a deploy key, follow these steps: +To create a org token, follow these steps: 1. Log in to Livebook Teams 2. Navigate to your organization -3. Go to the **Deploy keys** page in the menu -4. Click the **Create deploy key** button -5. Provide a descriptive name (e.g., "CI/CD Pipeline" or "Local CLI") and copy the generated key +3. Go to the **Tokens** page in the menu +4. Click the **Create org token** button +5. Provide a descriptive name (e.g., "CI/CD Pipeline" or "Local CLI") and copy the generated token ### Teams key @@ -68,7 +68,7 @@ Deploy a single notebook: ```bash livebook deploy \ - --deploy-key="lb_dk_..." \ + --org-token="lb_ok_..." \ --teams-key="lb_tk_..." \ --deployment-group-id="17" \ path/to/notebook.livemd @@ -80,7 +80,7 @@ Deploy multiple notebooks: ```bash livebook deploy \ - --deploy-key="lb_dk_..." \ + --org-token="lb_ok_..." \ --teams-key="lb_tk_..." \ --deployment-group-id="13" \ app1.livemd app2.livemd app3.livemd @@ -90,7 +90,7 @@ Use glob patterns for convenience: ```bash livebook deploy \ - --deploy-key="lb_dk_..." \ + --org-token="lb_ok_..." \ --teams-key="lb_tk_..." \ --deployment-group-id="7" \ notebooks/*.livemd @@ -98,7 +98,7 @@ livebook deploy \ ### Available options -- `--deploy-key`: A deploy key from your Livebook Teams organization (required) +- `--org-token`: A token from your Livebook Teams organization (required) - `--teams-key`: Teams key from your Teams organization (required) - `--deployment-group-id`: ID of the target deployment group (required) @@ -134,13 +134,13 @@ jobs: - name: Deploy notebooks run: | livebook deploy \ - --deploy-key="${{ secrets.LIVEBOOK_DEPLOY_KEY }}" \ + --org-token="${{ secrets.LIVEBOOK_TEAMS_ORG_TOKEN }}" \ --teams-key="${{ secrets.LIVEBOOK_TEAMS_KEY }}" \ --deployment-group-id="3" \ ./notebooks/*.livemd ``` -Store your deploy key and teams key as repository secrets for secure access. +Store your org token and teams key as repository secrets for secure access. ## FAQ diff --git a/lib/livebook/hubs/team.ex b/lib/livebook/hubs/team.ex index e8639f414..2e86e38bb 100644 --- a/lib/livebook/hubs/team.ex +++ b/lib/livebook/hubs/team.ex @@ -104,7 +104,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do @teams_key_prefix Teams.Constants.teams_key_prefix() @public_key_prefix Teams.Constants.public_key_prefix() - @deploy_key_prefix Teams.Constants.deploy_key_prefix() + @org_token_prefix Teams.Constants.org_token_prefix() def load(team, fields) do {offline?, fields} = Map.pop(fields, :offline?, false) @@ -132,7 +132,7 @@ defimpl Livebook.Hubs.Provider, for: Livebook.Hubs.Team do def type(_team), do: "team" - def connection_spec(%{session_token: @deploy_key_prefix <> _}), do: nil + def connection_spec(%{session_token: @org_token_prefix <> _}), do: nil def connection_spec(team), do: {TeamClient, team} def disconnect(team), do: TeamClient.stop(team.id) diff --git a/lib/livebook/teams.ex b/lib/livebook/teams.ex index 8e688b54d..ab82bb4a1 100644 --- a/lib/livebook/teams.ex +++ b/lib/livebook/teams.ex @@ -236,7 +236,7 @@ defmodule Livebook.Teams do end @doc """ - Fetches the CLI session using a deploy key. + Fetches the CLI session using a org token. """ @spec fetch_cli_session(map()) :: {:ok, Team.t()} | {:error, String.t()} | {:transport_error, String.t()} @@ -262,7 +262,7 @@ defmodule Livebook.Teams do end @doc """ - Deploys the given app deployment to given deployment group using a deploy key. + Deploys the given app deployment to given deployment group using an org token. """ @spec deploy_app_from_cli(Team.t(), Teams.AppDeployment.t(), integer()) :: {:ok, String.t()} | {:error, map()} | {:transport_error, String.t()} diff --git a/lib/livebook/teams/constants.ex b/lib/livebook/teams/constants.ex index 23fb6b7c6..f859a5ebd 100644 --- a/lib/livebook/teams/constants.ex +++ b/lib/livebook/teams/constants.ex @@ -12,10 +12,10 @@ defmodule Livebook.Teams.Constants do def agent_key_prefix, do: "lb_ak_" @doc """ - Returns the Deploy Key prefix + Returns the Org Token prefix """ - @spec deploy_key_prefix() :: String.t() - def deploy_key_prefix, do: "lb_dk_" + @spec org_token_prefix() :: String.t() + def org_token_prefix, do: "lb_ok_" @doc """ Returns the Teams Key prefix diff --git a/lib/livebook/teams/requests.ex b/lib/livebook/teams/requests.ex index 57eda9ad6..121911155 100644 --- a/lib/livebook/teams/requests.ex +++ b/lib/livebook/teams/requests.ex @@ -5,7 +5,7 @@ defmodule Livebook.Teams.Requests do alias Livebook.Secrets.Secret alias Livebook.Teams - @deploy_key_prefix Teams.Constants.deploy_key_prefix() + @org_token_prefix Teams.Constants.org_token_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 "Deployment not authorized, check deploy permissions for this deployment group" @@ -230,7 +230,7 @@ defmodule Livebook.Teams.Requests do end @doc """ - Send a request to Livebook Team API to return a session using a deploy key. + Send a request to Livebook Team API to return a session using an org token. """ @spec fetch_cli_session(map()) :: api_result() def fetch_cli_session(config) do @@ -238,7 +238,7 @@ defmodule Livebook.Teams.Requests do end @doc """ - Send a request to Livebook Team API to deploy an app using a deploy key. + Send a request to Livebook Team API to deploy an app using an org token. """ @spec deploy_app_from_cli(Team.t(), Teams.AppDeployment.t(), integer()) :: api_result() def deploy_app_from_cli(team, app_deployment, deployment_group_id) do @@ -324,7 +324,7 @@ defmodule Livebook.Teams.Requests do Req.Request.append_request_steps(req, unauthorized: &{&1, Req.Response.new(status: 401)}) end - defp add_team_auth(req, %{session_token: @deploy_key_prefix <> _} = team) do + defp add_team_auth(req, %{session_token: @org_token_prefix <> _} = team) do token = "#{team.session_token}:#{Teams.Org.key_hash(%Teams.Org{teams_key: team.teams_key})}" Req.Request.merge_options(req, auth: {:bearer, token}) end diff --git a/lib/livebook_cli/deploy.ex b/lib/livebook_cli/deploy.ex index 18715e90b..4f158fc1c 100644 --- a/lib/livebook_cli/deploy.ex +++ b/lib/livebook_cli/deploy.ex @@ -4,7 +4,7 @@ defmodule LivebookCLI.Deploy do @behaviour LivebookCLI.Task - @deploy_key_prefix Teams.Constants.deploy_key_prefix() + @org_token_prefix Teams.Constants.org_token_prefix() @teams_key_prefix Teams.Constants.teams_key_prefix() @impl true @@ -14,7 +14,7 @@ defmodule LivebookCLI.Deploy do ## Available options - --deploy-key Deploy key from your Livebook Teams organization + --org-token Token from your Livebook Teams organization --teams-key Teams key from your Teams workspace --deployment-group-id The ID of the deployment group you want to deploy to @@ -24,16 +24,16 @@ defmodule LivebookCLI.Deploy do Deploys a single notebook: - livebook deploy --deploy-key="lb_dk_..." --teams-key="lb_tk_..." --deployment-group-id=123 path/to/app1.livemd + livebook deploy --org-token="lb_ok_..." --teams-key="lb_tk_..." --deployment-group-id=123 path/to/app1.livemd Deploys multiple notebooks: - livebook deploy --deploy-key="lb_dk_..." --teams-key="lb_tk_..." --deployment-group-id=123 path/to/*.livemd\ + livebook deploy --org-token="lb_ok_..." --teams-key="lb_tk_..." --deployment-group-id=123 path/to/*.livemd\ """ end @switches [ - deploy_key: :string, + org_token: :string, teams_key: :string, deployment_group_id: :integer ] @@ -54,7 +54,7 @@ defmodule LivebookCLI.Deploy do %{ paths: paths, - session_token: opts[:deploy_key], + session_token: opts[:org_token], teams_key: opts[:teams_key], deployment_group_id: opts[:deployment_group_id] } @@ -69,15 +69,19 @@ defmodule LivebookCLI.Deploy do add_error(acc, normalize_key(key), "can't be blank") {:session_token, value}, acc -> - if not String.starts_with?(value, @deploy_key_prefix) do - add_error(acc, normalize_key(:session_token), "must be a Livebook Teams Deploy Key") + if not String.starts_with?(value, @org_token_prefix) do + add_error( + acc, + normalize_key(:session_token), + "must be a Livebook Teams organization token" + ) else acc end {:teams_key, value}, acc -> if not String.starts_with?(value, @teams_key_prefix) do - add_error(acc, normalize_key(:teams_key), "must be a Livebook Teams Key") + add_error(acc, normalize_key(:teams_key), "must be a Livebook Teams key") else acc end @@ -211,11 +215,11 @@ defmodule LivebookCLI.Deploy do end defp normalize_key(key) when is_atom(key), do: to_string(key) |> normalize_key() - defp normalize_key("session_token"), do: "Deploy Key" - defp normalize_key("teams_key"), do: "Teams Key" - defp normalize_key("deployment_group_id"), do: "Deployment Group ID" + defp normalize_key("session_token"), do: "Token" + defp normalize_key("teams_key"), do: "Teams key" + defp normalize_key("deployment_group_id"), do: "Deployment group id" - defp normalize_key("paths"), do: "File Paths" + defp normalize_key("paths"), do: "File paths" defp format_errors(errors, prefix) do errors diff --git a/test/livebook_teams/cli/deploy_test.exs b/test/livebook_teams/cli/deploy_test.exs index ba928f62c..181bbf088 100644 --- a/test/livebook_teams/cli/deploy_test.exs +++ b/test/livebook_teams/cli/deploy_test.exs @@ -21,7 +21,7 @@ defmodule LivebookCLI.Integration.DeployTest 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) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) hub_id = team.id deployment_group_id = to_string(deployment_group.id) @@ -63,7 +63,7 @@ defmodule LivebookCLI.Integration.DeployTest do test "successfully deploys multiple notebooks from directory", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) hub_id = team.id deployment_group_id = to_string(deployment_group.id) @@ -112,12 +112,12 @@ defmodule LivebookCLI.Integration.DeployTest do end end - test "fails with unauthorized deploy key", + test "fails with unauthorized org token", %{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) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url, deploy_auth: true) @@ -164,7 +164,7 @@ defmodule LivebookCLI.Integration.DeployTest do }} end - test "fails with invalid deploy key", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do + test "fails with invalid org token", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do slug = Utils.random_short_id() app_path = Path.join(tmp_dir, "#{slug}.livemd") deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) @@ -175,20 +175,22 @@ defmodule LivebookCLI.Integration.DeployTest do # Test App """) - assert_raise LivebookCLI.Error, ~r/Deploy Key must be a Livebook Teams Deploy Key/s, fn -> - deploy( - "invalid_key", - team.teams_key, - deployment_group.id, - app_path - ) - end + assert_raise LivebookCLI.Error, + ~r/Token must be a Livebook Teams organization token/s, + fn -> + deploy( + "invalid_key", + team.teams_key, + deployment_group.id, + app_path + ) + end end test "fails with invalid teams 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") - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) stamp_notebook(app_path, """ @@ -197,7 +199,7 @@ defmodule LivebookCLI.Integration.DeployTest do # Test App """) - assert_raise LivebookCLI.Error, ~r/Teams Key must be a Livebook Teams Key/s, fn -> + assert_raise LivebookCLI.Error, ~r/Teams key must be a Livebook Teams key/s, fn -> deploy( key, "invalid-key", @@ -211,7 +213,7 @@ defmodule LivebookCLI.Integration.DeployTest do %{team: team, node: node, org: org, tmp_dir: tmp_dir} do slug = Utils.random_short_id() app_path = Path.join(tmp_dir, "#{slug}.livemd") - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) stamp_notebook(app_path, """ @@ -236,7 +238,7 @@ defmodule LivebookCLI.Integration.DeployTest 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) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) hub_id = team.id deployment_group_id = to_string(deployment_group.id) @@ -265,7 +267,7 @@ defmodule LivebookCLI.Integration.DeployTest do end) end) - assert output =~ ~r/Deployment Group ID does not exist/ + assert output =~ ~r/Deployment group id does not exist/ refute_receive {:app_deployment_started, %{ @@ -278,10 +280,10 @@ defmodule LivebookCLI.Integration.DeployTest do end test "fails with non-existent file", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) - assert_raise LivebookCLI.Error, ~r/File Paths must be a valid path/s, fn -> + assert_raise LivebookCLI.Error, ~r/File paths must be a valid path/s, fn -> deploy( key, team.teams_key, @@ -292,10 +294,10 @@ defmodule LivebookCLI.Integration.DeployTest do end test "fails with directory argument", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) - assert_raise LivebookCLI.Error, ~r/File Paths must be a file path/s, fn -> + assert_raise LivebookCLI.Error, ~r/File paths must be a file path/s, fn -> deploy( key, team.teams_key, @@ -307,7 +309,7 @@ defmodule LivebookCLI.Integration.DeployTest do test "handles partial failure when deploying multiple notebooks", %{team: team, node: node, org: org, tmp_dir: tmp_dir} do - {deploy_key, _} = TeamsRPC.create_deploy_key(node, org: org) + {org_token, _} = TeamsRPC.create_org_token(node, org: org) deployment_group = TeamsRPC.create_deployment_group(node, org: org, url: @url) hub_id = team.id @@ -345,7 +347,7 @@ defmodule LivebookCLI.Integration.DeployTest do ExUnit.CaptureIO.capture_io(fn -> assert_raise(LivebookCLI.Error, "Some app deployments failed.", fn -> deploy( - deploy_key, + org_token, team.teams_key, deployment_group.id, [invalid_app_path, valid_app_path] @@ -376,7 +378,7 @@ defmodule LivebookCLI.Integration.DeployTest do end end - defp deploy(deploy_key, teams_key, deployment_group_id, path) do + defp deploy(org_token, teams_key, deployment_group_id, path) do paths = if is_list(path) do path @@ -396,8 +398,8 @@ defmodule LivebookCLI.Integration.DeployTest do LivebookCLI.Deploy.call( [ - "--deploy-key", - deploy_key, + "--org-token", + org_token, "--teams-key", teams_key, "--deployment-group-id", diff --git a/test/livebook_teams/teams_test.exs b/test/livebook_teams/teams_test.exs index 181ec93d2..153691c50 100644 --- a/test/livebook_teams/teams_test.exs +++ b/test/livebook_teams/teams_test.exs @@ -255,7 +255,7 @@ defmodule Livebook.TeamsTest do @describetag teams_for: :cli @tag teams_persisted: false - test "authenticates the deploy key", %{team: team} do + test "authenticates the org token", %{team: team} do config = %{teams_key: team.teams_key, session_token: team.session_token} refute Livebook.Hubs.hub_exists?(team.id) @@ -264,9 +264,9 @@ defmodule Livebook.TeamsTest do end @tag teams_for: :user - test "authenticates the deploy key when hub already exists", + test "authenticates the org token when hub already exists", %{team: team, org: org, node: node} do - {key, _} = TeamsRPC.create_deploy_key(node, org: org) + {key, _} = TeamsRPC.create_org_token(node, org: org) config = %{teams_key: team.teams_key, session_token: key} assert Teams.fetch_cli_session(config) == @@ -291,7 +291,7 @@ defmodule Livebook.TeamsTest do @tag teams_persisted: false test "returns error with invalid credentials", %{team: team} do - config = %{teams_key: team.teams_key, session_token: "lb_dk_foo"} + config = %{teams_key: team.teams_key, session_token: "lb_ok_foo"} assert {:transport_error, "You are not authorized" <> _} = Teams.fetch_cli_session(config) refute Livebook.Hubs.hub_exists?(team.id) @@ -332,7 +332,7 @@ defmodule Livebook.TeamsTest do assert {:ok, app_deployment} = Teams.AppDeployment.new(notebook, files_dir) # fetch the cli session - {key, _deploy_key} = TeamsRPC.create_deploy_key(node, org: org) + {key, _org_token} = TeamsRPC.create_org_token(node, org: org) config = %{teams_key: team.teams_key, session_token: key} assert {:ok, team} = Teams.fetch_cli_session(config) diff --git a/test/support/integration/teams_rpc.ex b/test/support/integration/teams_rpc.ex index 0fc83733f..d6e5dc136 100644 --- a/test/support/integration/teams_rpc.ex +++ b/test/support/integration/teams_rpc.ex @@ -137,9 +137,9 @@ defmodule Livebook.TeamsRPC do :erpc.call(node, TeamsRPC, :create_authorization_group, [attrs]) end - def create_deploy_key(node, attrs \\ []) do - key = :erpc.call(node, TeamsRPC, :generate_deploy_key, []) - {key, :erpc.call(node, TeamsRPC, :create_deploy_key, [key, attrs])} + def create_org_token(node, attrs \\ []) do + key = :erpc.call(node, TeamsRPC, :generate_org_token, []) + {key, :erpc.call(node, TeamsRPC, :create_org_token, [key, attrs])} end # Update resource diff --git a/test/support/integration/teams_tests.ex b/test/support/integration/teams_tests.ex index 71a6508ff..420da39db 100644 --- a/test/support/integration/teams_tests.ex +++ b/test/support/integration/teams_tests.ex @@ -151,7 +151,7 @@ defmodule Livebook.TeamsIntegrationHelper do ) deployment_group = TeamsRPC.create_deployment_group(node, attrs) - {key, deploy_key} = TeamsRPC.create_deploy_key(node, org: org) + {key, org_token} = TeamsRPC.create_org_token(node, org: org) TeamsRPC.create_billing_subscription(node, org) @@ -169,7 +169,7 @@ defmodule Livebook.TeamsIntegrationHelper do ) %{ - deploy_key: Map.replace!(deploy_key, :key_hash, key), + org_token: Map.replace!(org_token, :key_hash, key), deployment_group: deployment_group, org: org, org_key: org_key,