panic
panic
¶
Emergency panic — immediately cut all resource access across all projects.
Three-step sequence: quarantine → kill supervisors → (optionally) kill the containers themselves. Quarantine alone is not enough: each container's supervisor talks to its container over a bind-mounted unix socket, and nft sees no traffic there. Killing the host-side supervisor process is what actually denies the container any more vault / clearance / signer cycles.
Phase 1 (always): in parallel,
- Quarantine every running container's shield (nft blackhole).
- Kill every supervisor via the per-container PID files under
state_root()/pids/— SIGKILL, no graceful TERM, because panic targets misbehaving containers and the SIGTERM grace period would just hand the supervisor more time to answer socket calls. The gate runs inside each container's supervisor, so this same kill stops the gate too — there is no separate host gate daemon to stop. - Hard-lock the vault by destroying every stored passphrase
tier — session file and persistent tiers alike — so nothing can
auto-unlock it afterwards. Recovery is by re-supplying the
escrowed recovery passphrase (see
_stop_vault).
Phase 2 (optional, stop_containers=True): SIGKILL each container
via podman stop --time 0. Containers are not removed.
Token revocation is deliberately excluded — it is irreversible and shields + dead supervisors already cut access.
logger = logging.getLogger(__name__)
module-attribute
¶
PanicResult(shields_raised=list(), shield_errors=list(), supervisors_killed=list(), supervisor_errors=list(), vault_stopped=False, vault_error=None, containers_stopped=list(), container_stop_errors=list(), shield_bypassed=False, total_running=0)
dataclass
¶
Outcome of an execute_panic invocation.
shields_raised = field(default_factory=list)
class-attribute
instance-attribute
¶
shield_errors = field(default_factory=list)
class-attribute
instance-attribute
¶
supervisors_killed = field(default_factory=list)
class-attribute
instance-attribute
¶
supervisor_errors = field(default_factory=list)
class-attribute
instance-attribute
¶
vault_stopped = False
class-attribute
instance-attribute
¶
vault_error = None
class-attribute
instance-attribute
¶
containers_stopped = field(default_factory=list)
class-attribute
instance-attribute
¶
container_stop_errors = field(default_factory=list)
class-attribute
instance-attribute
¶
shield_bypassed = False
class-attribute
instance-attribute
¶
total_running = 0
class-attribute
instance-attribute
¶
has_errors
property
¶
Return whether any operation failed.
execute_panic(*, stop_containers=False)
¶
Execute the full panic sequence.
Discovers every running container, then (in parallel) raises shields, kills the per-container supervisors (which also stops each container's embedded gate), and destroys every stored copy of the vault passphrase (hard-lock). If stop_containers, also SIGKILLs the containers afterwards (they are not removed).
Source code in src/terok/lib/domain/panic.py
panic_stop_containers()
¶
Discover and SIGKILL all running containers (Phase 2 standalone).
is_panicked()
¶
clear_panic_lock()
¶
format_panic_report(result)
¶
Format a human-readable summary of the panic result.