Rename deploy keys to org tokens

This commit is contained in:
Alexandre de Souza 2025-08-20 17:33:20 -03:00
parent 7513202199
commit 241681a6e6
No known key found for this signature in database
GPG key ID: E39228FFBA346545
10 changed files with 80 additions and 74 deletions

View file

@ -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

View file

@ -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)

View file

@ -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()}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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, """
<!-- livebook:{"app_settings":{"access_type":"public","slug":"#{slug}"},"hub_id":"#{team.id}"} -->
@ -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",

View file

@ -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)

View file

@ -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

View file

@ -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,