WardrikVault (wardrik_vault v0.1.0-rc.1)
Copy MarkdownKeeps credentials sealed in a WardrikStore, and gives them to WardrikCore agents' tools.
children = [
{WardrikStore, store},
{WardrikVault, name: MyApp.Vault, store: store, keys: [System.fetch_env!("VAULT_KEY")]}
]
WardrikCore.start_agent(
agent_id: "digest",
model: "anthropic:claude-haiku-4-5",
principal: %WardrikCore.Principal{id: "user:jon"},
credentials: {WardrikVault, MyApp.Vault}
)The vault implements WardrikCore.Credentials. A tool gets only what the agent's principal
holds.
Functions that take a vault raise ArgumentError if it isn't started.
Summary
Types
A secret someone put in, or a grant someone gave by authorizing.
A vault, by the name your app gave it.
An option that holds a secret: the secret itself, or {:secret, name} for one of the deployment's.
Functions
Returns a specification to start this module under a supervisor.
Removes what principal holds as name. Returns :ok, also when there's nothing to remove.
Returns the principal that holds the deployment's own secrets.
Returns the value principal holds as name, unsealed.
Returns a new key, base64-encoded, for :keys.
Returns every credential as {principal_id, name, kind}. Needs no key.
Returns what principal holds as name, unsealed, with its kind and version.
Returns the names principal holds. Needs no key.
Seals value as name for principal. Returns {:ok, vsn}, or {:error, :no_key} without
keys.
Returns the value principal holds as name, without a running vault.
Starts the vault.
Returns the secret an option holds.
Types
@type kind() :: :secret | :grant
A secret someone put in, or a grant someone gave by authorizing.
@type t() :: atom()
A vault, by the name your app gave it.
An option that holds a secret: the secret itself, or {:secret, name} for one of the deployment's.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec delete(t(), WardrikCore.Principal.t(), String.t()) :: :ok | {:error, term()}
Removes what principal holds as name. Returns :ok, also when there's nothing to remove.
@spec deployment() :: WardrikCore.Principal.t()
Returns the principal that holds the deployment's own secrets.
These are your app's keys, such as a model provider's, and the secrets options name with
{:secret, name}. No agent works for this principal.
{:ok, _vsn} = WardrikVault.put(MyApp.Vault, WardrikVault.deployment(), "SLACK_SIGNING_SECRET", secret)
@spec fetch(t(), WardrikCore.Principal.t(), String.t()) :: {:ok, binary()} | {:error, term()}
Returns the value principal holds as name, unsealed.
WardrikVault.fetch(MyApp.Vault, principal, "github")
#=> {:ok, "ghp_..."}Returns {:error, :not_found} if there's none, and {:error, :no_key} without keys.
@spec generate_key() :: String.t()
Returns a new key, base64-encoded, for :keys.
Returns every credential as {principal_id, name, kind}. Needs no key.
WardrikVault.list(MyApp.Vault)
#=> [{"user:jon", "github", :secret}]Names aren't sealed. Anyone who can read the store can see who holds a credential of which name.
@spec lookup(t(), WardrikCore.Principal.t(), String.t()) :: {:ok, kind(), binary(), WardrikStore.vsn()} | {:error, term()} | {:error, kind(), term()}
Returns what principal holds as name, unsealed, with its kind and version.
WardrikVault.lookup(MyApp.Vault, principal, "github")
#=> {:ok, :secret, "ghp_...", vsn}Returns {:error, kind, reason} if the value is there but won't unseal.
@spec names(t(), WardrikCore.Principal.t()) :: [String.t()]
Returns the names principal holds. Needs no key.
@spec put(t(), WardrikCore.Principal.t(), String.t(), binary(), kind: kind(), if_vsn: WardrikStore.vsn() ) :: {:ok, WardrikStore.vsn()} | {:error, term()}
Seals value as name for principal. Returns {:ok, vsn}, or {:error, :no_key} without
keys.
{:ok, vsn} = WardrikVault.put(MyApp.Vault, principal, "github", "ghp_...")Options
:kind-:secretor:grant.:secretunless set.:if_vsn- writes only over this version. SeeWardrikStore.put/4.
@spec read(WardrikStore.t(), [String.t()], WardrikCore.Principal.t(), String.t()) :: {:ok, binary()} | {:error, term()}
Returns the value principal holds as name, without a running vault.
Use it to read a secret before the vault starts, such as while reading config. store and
keys are what the vault is started with.
WardrikVault.read(store, [System.fetch_env!("VAULT_KEY")], principal, "github")
#=> {:ok, "ghp_..."}
@spec read_value(WardrikStore.t(), [String.t()], value()) :: {:ok, String.t() | nil} | {:error, term()}
Returns the secret an option holds, as value/2 does, without a running vault. See read/4.
@spec start_link(keyword()) :: GenServer.on_start()
Starts the vault.
WardrikVault.start_link(
name: MyApp.Vault,
store: store,
keys: [System.fetch_env!("VAULT_KEY"), System.fetch_env!("OLD_VAULT_KEY")]
)Values are sealed with AES-256-GCM. The first key seals. Any key unseals. To rotate, put a new key first and keep the old one until nothing needs it.
Options
:name- required. What the vault is reached by.:store- required. TheWardrikStoreto keep credentials in.:keys- base64 keys fromgenerate_key/0.[]unless set. Without keys, nothing is sealed or unsealed. A key that isn't 32 bytes is dropped with a warning.:grants-{module, opts}, wheremoduleimplementsWardrikVault.Grants.nilunless set.
Returns the secret an option holds.
WardrikVault.value(MyApp.Vault, {:secret, "SLACK_SIGNING_SECRET"})
#=> {:ok, "8f14..."}
WardrikVault.value(MyApp.Vault, "8f14...")
#=> {:ok, "8f14..."}{:secret, name} reads the deployment's secret on each call, so a new one takes effect at once.
A string or nil is returned as it is.