status
status
¶
One vault-state picture for every surface — CLI status, TUI pill, sickbay.
VaultStatus.load
computes everything the frontends used to derive independently (and
with independently-drifting wording): the lock classification, the
per-tier chain table with shadowing, the session-shadow comparison,
and a catalog of VaultWarnings
whose text is authored exactly once. A renderer's whole job is
picking which fields to show — never re-deciding what they mean.
"Locked" alone hides three different operator problems with three different remedies, so the classification keeps them apart:
VaultState.UNPROVISIONED— fresh install: no DB and no tier holds anything. The remedy is the provisioning flow, not an unlock prompt.VaultState.LOCKED— a passphrase problem;lock_reasonsays which one (empty chain, wrong key, or a broken fail-closed tier).VaultState.ERROR— the DB failed for a non-passphrase reason (schema drift, permissions);db_errorcarries it verbatim.VaultState.UNLOCKED— a tier resolves and (when the DB exists) opens it.
__all__ = ['ChainRow', 'SessionShadow', 'VaultState', 'VaultStatus', 'VaultWarning', 'VaultWarningKind', 'active_durable_source', 'clear_redundant_session_file', 'session_shadow_state']
module-attribute
¶
SessionShadow(durable_source, redundant)
dataclass
¶
A session-file tier sitting on top of a durable tier.
redundant is the actionable bit:
True— the session copy is byte-identical to what the durable tier resolves to, so it's pure residue (a pastunlockon a box that already auto-unlocks). Safe to delete; nothing is lost.False— the two differ. Either a deliberate re-key in progress or a stale unlock masking the durable value; never auto-removed.None— the durable tier is present but couldn't be read to compare (broken seal, dead helper), so the session file may be doing real work. Left alone.
VaultState
¶
Bases: StrEnum
The four operator-distinct answers to "can I use the vault?".
UNPROVISIONED = 'unprovisioned'
class-attribute
instance-attribute
¶
Fresh install — no credentials DB and no tier holds a passphrase. The remedy is the provisioning flow (setup / the TUI tier chooser), not an unlock prompt keying a brand-new vault to a typo.
LOCKED = 'locked'
class-attribute
instance-attribute
¶
A passphrase problem — lock_reason names which of the three:
empty chain, wrong key, or a broken fail-closed tier.
UNLOCKED = 'unlocked'
class-attribute
instance-attribute
¶
A tier resolves the passphrase and, when the DB exists, opens it.
ERROR = 'error'
class-attribute
instance-attribute
¶
The DB failed for a non-passphrase reason — db_error has it verbatim.
ChainRow(tier, present, active, shadowed, detail)
dataclass
¶
One tier of the resolution chain, annotated for display.
active marks the tier the resolver would use right now;
shadowed marks a durable tier outranked by a volatile one (the
"why is my TPM2 box reading a RAM-backed file?" diagnostic).
VaultWarningKind
¶
Bases: StrEnum
Stable identifiers for the warning catalog — frontends dispatch on these.
BROKEN_TIER = 'broken-tier'
class-attribute
instance-attribute
¶
RECOVERY_UNCONFIRMED = 'recovery-unconfirmed'
class-attribute
instance-attribute
¶
RECOVERY_VOLATILE = 'recovery-volatile'
class-attribute
instance-attribute
¶
SHADOW_REDUNDANT = 'shadow-redundant'
class-attribute
instance-attribute
¶
SHADOW_OVERRIDE = 'shadow-override'
class-attribute
instance-attribute
¶
SHADOW_UNREADABLE = 'shadow-unreadable'
class-attribute
instance-attribute
¶
VaultWarning(kind, severity, brief, message)
dataclass
¶
One vault warning, authored here and only here.
brief is the compact form for pills / one-line summaries;
message the full sentence for notifications and status pages.
kind is the semantic identifier — a renderer that wants to
attach a remedy (a CLI verb, a TUI button) maps it per frontend
rather than reading command strings out of the library layer.
VaultStatus(state, lock_reason, db_error, source, chain, shadow, recovery, db_path, db_exists, providers, credential_types, ssh_keys, warnings)
dataclass
¶
Everything a frontend needs to render the vault — loaded in one call.
state
instance-attribute
¶
lock_reason
instance-attribute
¶
Why the vault counts as locked, in operator language. None
unless state is LOCKED.
db_error
instance-attribute
¶
Verbatim non-passphrase DB failure. None unless state is ERROR.
source
instance-attribute
¶
The tier the resolver would use right now, or None.
chain
instance-attribute
¶
shadow
instance-attribute
¶
recovery
instance-attribute
¶
db_path
instance-attribute
¶
db_exists
instance-attribute
¶
False on a fresh install — the DB is created encrypted on
first use, so "unlocked" then means "the key is ready", not "the
DB opened".
providers
instance-attribute
¶
Sorted provider slugs stored in the vault; None when the DB
couldn't be read (locked / error).
credential_types
instance-attribute
¶
provider → type (api_key / oauth_token / …), read in
the same DB pass as providers so no renderer ever pays a second
SQLCipher key derivation just to label a row. None exactly
when providers is.
ssh_keys
instance-attribute
¶
Count of stored SSH keypairs, from the same DB pass. None
exactly when providers is.
warnings
instance-attribute
¶
load(cfg=None)
classmethod
¶
Compute the full vault picture for cfg (defaults if None).
Read-only by construction: unlike a bare
cfg.open_credential_db() this never creates the DB — a
fresh install stays fresh no matter how often status is
rendered. Never prompts (a status read must not block on
stdin) and pays the one durable-tier unseal only when a
session-shadow actually needs comparing.
Source code in src/terok_sandbox/vault/store/status.py
active_durable_source(cfg)
¶
Name the durable tier that already resolves the vault, or None.
Probes the chain minus the session file (file presence only — no unseal, no command exec): if a reboot-surviving tier is present, a session write would merely shadow it. The single source of truth for the no-shadow guard, shared by the session writer and the CLI's skip-the-prompt early-out.
Source code in src/terok_sandbox/vault/store/status.py
session_shadow_state(cfg)
¶
Describe a session-file-over-durable-tier shadow, or None if there is none.
Returns None in the common cases — no session file, or no durable
tier beneath it — without resolving anything. Only when both are
present does it resolve the durable chain (omitting the session
file) to compare values; that one comparison is the only place
status / remediation pay an unseal. The session secret never leaves
the process — this reads two tiers and compares, exactly what the
resolver already does internally.
Source code in src/terok_sandbox/vault/store/status.py
clear_redundant_session_file(cfg)
¶
Remove the session-unlock file iff it merely duplicates a durable tier.
Same-key residue only: a session file whose passphrase differs from
the durable tier is a deliberate override (or a re-key mid-flight)
and is kept. Re-verifies state at call time rather than trusting a
caller's stale read. Returns the durable tier it deduplicated
against, or None when there was nothing safe to remove.