Packages
livebook
0.8.1
0.19.8
0.19.7
0.19.6
0.19.5
0.19.4
0.19.3
0.19.2
0.19.1
0.19.0
0.18.6
0.18.5
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
0.17.3
0.17.2
0.17.1
0.17.0
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.14.0-rc.1
0.14.0-rc.0
0.13.3
0.13.2
0.13.1
0.13.0
0.12.1
0.12.0
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.3
0.9.2
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.3
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
0.5.0
0.4.1
0.4.0
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.2
0.1.1
0.1.0
Automate code & data workflows with interactive notebooks
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/livebook/secrets.ex
defmodule Livebook.Secrets do
@moduledoc false
import Ecto.Changeset, only: [apply_action: 2]
alias Livebook.Storage
alias Livebook.Secrets.Secret
@temporary_key :livebook_temporary_secrets
@doc """
Get the secrets list from storage.
"""
@spec fetch_secrets() :: list(Secret.t())
def fetch_secrets do
temporary_secrets = :persistent_term.get(@temporary_key, [])
for fields <- Storage.all(:secrets) do
struct!(Secret, Map.delete(fields, :id))
end
|> Enum.concat(temporary_secrets)
|> Enum.sort()
end
@doc """
Gets a secret from storage.
Raises `RuntimeError` if the secret doesn't exist.
"""
@spec fetch_secret!(String.t()) :: Secret.t()
def fetch_secret!(id) do
fields = Storage.fetch!(:secrets, id)
struct!(Secret, Map.delete(fields, :id))
end
@doc """
Checks if the secret already exists.
"""
@spec secret_exists?(String.t()) :: boolean()
def secret_exists?(id) do
Storage.fetch(:secrets, id) != :error
end
@doc """
Validates a secret map and either returns a struct struct or changeset.
"""
@spec validate_secret(map()) :: {:ok, Secret.t()} | {:error, Ecto.Changeset.t()}
def validate_secret(attrs) do
changeset = Secret.changeset(%Secret{}, attrs)
apply_action(changeset, :validate)
end
@doc """
Stores the given secret as is, without validation.
"""
@spec set_secret(Secret.t()) :: Secret.t()
def set_secret(secret) do
attributes = secret |> Map.from_struct() |> Map.to_list()
:ok = Storage.insert(:secrets, secret.name, attributes)
:ok = broadcast_secrets_change({:set_secret, secret})
secret
end
@doc """
Unset secret from given id.
"""
@spec unset_secret(String.t()) :: :ok
def unset_secret(id) do
if secret_exists?(id) do
secret = fetch_secret!(id)
Storage.delete(:secrets, id)
broadcast_secrets_change({:unset_secret, secret})
end
:ok
end
@doc """
Sets additional secrets that are kept only in memory.
"""
@spec set_temporary_secrets(list(Secret.t())) :: :ok
def set_temporary_secrets(secrets) do
:persistent_term.put(@temporary_key, secrets)
end
@doc """
Subscribe to secrets updates.
## Messages
* `{:set_secret, secret}`
* `{:unset_secret, secret}`
"""
@spec subscribe() :: :ok | {:error, term()}
def subscribe do
Phoenix.PubSub.subscribe(Livebook.PubSub, "secrets")
end
@doc """
Unsubscribes from `subscribe/0`.
"""
@spec unsubscribe() :: :ok
def unsubscribe do
Phoenix.PubSub.unsubscribe(Livebook.PubSub, "secrets")
end
defp broadcast_secrets_change(message) do
Phoenix.PubSub.broadcast(Livebook.PubSub, "secrets", message)
end
end