Current section
Files
Jump to
Current section
Files
lib/planck/agent/secrets.ex
defmodule Planck.Agent.Secrets do
@moduledoc """
Behaviour for secret storage and service rule management in Planck.
Declare the implementation module in `config.json`:
{ "secrets_hook": "Sidecar.Secrets.AgentVault" }
When not set, `Planck.Headless.Secrets.EnvFile` is used — reads and writes
`.planck/.env` and `~/.planck/.env`.
Both `planck_headless` and the sidecar depend on `planck_agent`, so
implementations in either package can reference this behaviour at compile time.
## Service rules
Service rules tell the credential proxy which credentials to inject for
outbound requests to a given host. The proxy injects unconditionally —
the agent makes plain HTTP calls with no credential knowledge required.
Rules are stored alongside credentials: `EnvFile` uses `# planck-service:`
comment lines in `.env`; `AgentVault` uses the vault service rules API.
"""
@typedoc "A map of secret key → value pairs."
@type t :: %{optional(String.t()) => String.t()}
@typedoc """
A service rule that tells the credential proxy to inject a credential for
all requests to the given host.
- `auth_type` — `"bearer"` (Authorization header) or `"api-key"` (custom header)
- `header` — the header name for `api-key` type (e.g. `"x-api-key"`); `nil` for bearer
"""
@type service :: %{
host: String.t(),
auth_type: String.t(),
credential_key: String.t(),
header: String.t() | nil
}
@doc "Store a secret. Overwrites any existing value for the same key."
@callback store(key :: String.t(), value :: String.t()) :: :ok | {:error, term()}
@doc "Fetch a secret by key. Returns `:not_found` when absent."
@callback fetch(key :: String.t()) :: {:ok, String.t()} | :not_found | {:error, term()}
@doc "Fetch all secrets as a map."
@callback fetch_all() :: t()
@doc "List all stored secret keys."
@callback list() :: {:ok, [String.t()]} | {:error, term()}
@doc "Delete a secret by key. No-op if not found."
@callback delete(key :: String.t()) :: :ok | {:error, term()}
@doc """
Upsert a service rule for the given host.
`opts` may include `header: String.t()` when `auth_type` is `"api-key"`.
"""
@callback store_service(
host :: String.t(),
auth_type :: String.t(),
credential_key :: String.t(),
opts :: keyword()
) :: :ok | {:error, term()}
@doc "Delete the service rule for the given host. No-op if not found."
@callback delete_service(host :: String.t()) :: :ok | {:error, term()}
@doc "List all configured service rules."
@callback list_services() :: {:ok, [service()]} | {:error, term()}
end