Caller-supervised owner of Ed25519 signing handles.
Add {RequestSeal.Custody.Local.Owner, name: MyApp.Custody, keys: keys} to
your supervision tree. keys is a keyword list of
name: {"ed25519", source} entries. Sources are {:env, variable, encoding},
{:file, path, encoding}, or {:file_from_env, variable, encoding}; the last
reads a file path from the variable. Encodings are :base64url (padding optional),
:base64 (padded), :hex (either case), or :raw. Only ASCII space, tab, CR,
and LF are trimmed from text encodings; raw bytes are unchanged. Base64
encodings must be canonical. Decoded seeds must be exactly 32 bytes. Source
inputs are limited to 4,096 bytes, including whitespace. There is no guess-decoding.
Files must be regular, not symbolic links, with mode 0600 or stricter (no
execute, group, other, or special permission bits). Use {:file, ...} in
production: environment seeds are inherited by OS child processes. Avoid :raw
environment seeds; environment values cannot safely represent arbitrary binary
data. Keep source paths and their parent directories under trusted control during startup.
Bad keys do not prevent startup. status/1 reports :ready, :unconfigured
(missing or empty variable, missing file, or stopped holder), or {:error, reason}
with :invalid_seed, :insecure_file, or :unreadable. fetch/2 returns {:error, :unconfigured}
for a missing or failed key. Calls to a stopped or busy owner return
{:error, :owner_unavailable} from fetch/2 and status/1; ready?/2 is false.
No signing capability is issued for a bad source.
Key names, variable names, and paths are configuration, never seed values.
The owner becomes sensitive before reading sources. Each decoded seed goes
directly to RequestSeal.Custody.Local.new/2; only handles and bounded statuses
remain in state. Holders monitor this owner, not the process calling fetch/2.
Sources are read on every start and restart; environment variables are never
deleted. Registration after startup is unsupported. Fetch per operation, or
fetch again and retry once on custody :key_not_found after an owner restart.
During restart, :owner_unavailable means wait for the supervised owner to
become available before fetching again. A file that disappears or changes
identity after its initial checks reports :insecure_file.
Abnormal exits retain a bounded atom reason; private reason terms are discarded.
Loading the library starts nothing.
Summary
Functions
Build a child specification containing source descriptors, never loaded seeds.
Fetch a handle; distinguish an unconfigured key from an unavailable owner.
Report whether a handle is available for the named key.
Start a linked owner with a fixed set of source descriptors.
Return each configured key's bounded status.
Types
@type encoding() :: :base64url | :base64 | :hex | :raw
@type key_status() ::
:ready
| :unconfigured
| {:error, :invalid_seed | :insecure_file | :unreadable}
Functions
@spec child_spec(options()) :: Supervisor.child_spec()
Build a child specification containing source descriptors, never loaded seeds.
@spec fetch(GenServer.server(), atom()) :: {:ok, RequestSeal.KeyHandle.t()} | {:error, :unconfigured | :owner_unavailable}
Fetch a handle; distinguish an unconfigured key from an unavailable owner.
@spec ready?(GenServer.server(), atom()) :: boolean()
Report whether a handle is available for the named key.
@spec start_link(options()) :: GenServer.on_start()
Start a linked owner with a fixed set of source descriptors.
@spec status(GenServer.server()) :: %{required(atom()) => key_status()} | {:error, :owner_unavailable}
Return each configured key's bounded status.