commands
commands
¶
Command registry for terok-sandbox — one module per subsystem.
Follows the same CommandDef /
ArgDef pattern as
terok_shield.registry. Higher-level consumers (terok,
terok-executor) import COMMANDS to build their own CLI frontends
without duplicating argument definitions or handler logic.
Per-subsystem modules:
sandbox— setup/uninstall (composes shield + vault + gate + clearance into one verb).gate— gate server lifecycle.shield— egress-firewall hooks.vault— vault passphrase verbs (the unlock/lock/seal trio that drives the SQLCipher chain).ssh— SSH-key CRUD against the credentials DB.doctor— host-side health checks.credentials— credentials-DB encryption chooser, provisioning, and migration phase.launch— prepare/run/cleanup for user-owned containers.
Shield commands are delegated to terok-shield's own registry —
SHIELD_COMMANDS re-exports the non-standalone subset.
CREDENTIALS_COMMANDS = (CommandDef(name='credentials', help='Credentials DB management', children=(CommandDef(name='encrypt-db', help='Migrate a legacy plaintext credentials DB to SQLCipher-encrypted (deprecated in 0.8.0, removed in 0.9.0)', handler=_handle_credentials_encrypt_db),)),)
module-attribute
¶
DOCTOR_COMMANDS = (CommandDef(name='doctor', help='Run sandbox health checks', handler=_handle_doctor, group='doctor'),)
module-attribute
¶
GATE_COMMANDS = (CommandDef(name='gate', help='Git gate inspection', children=(CommandDef(name='path', help="Print the file:// URL of a project's bare mirror", handler=_handle_gate_path, args=(ArgDef(name='project', help='Project name (the mirror is <project>.git)'),)),)),)
module-attribute
¶
LAUNCH_COMMANDS = (CommandDef(name='prepare', help='Print podman flags for sandboxing a user-owned container', handler=_handle_prepare, epilog=_BRIDGES_EPILOG, args=(ArgDef(name='container', help='Container name (becomes --name)'), ArgDef(name='--no-shield', action='store_true', help='Disable egress firewall (default: on)', dest='no_shield'), ArgDef(name='--no-gate', action='store_true', help='Disable git gate (default: on; requires --scope)', dest='no_gate'), ArgDef(name='--no-broker', action='store_true', help='Disable vault token broker (default: on; requires --scope)', dest='no_broker'), ArgDef(name='--scope', help='Credential scope; enables vault SSH agent and is required by gate/broker'), ArgDef(name='--profiles', type=_csv_list, help="Override shield profiles for this container (comma-separated, e.g. 'dev,pypi')"), ArgDef(name='--json', action='store_true', dest='output_json', help='Output JSON array instead of a shell-quoted string'))), CommandDef(name='run', help='Launch a sandboxed user-owned container (exec into podman run)', handler=_handle_run, epilog=_BRIDGES_EPILOG, args=(ArgDef(name='container', help='Container name (becomes --name)'), ArgDef(name='--no-shield', action='store_true', help='Disable egress firewall (default: on)', dest='no_shield'), ArgDef(name='--no-gate', action='store_true', help='Disable git gate (default: on; requires --scope)', dest='no_gate'), ArgDef(name='--no-broker', action='store_true', help='Disable vault token broker (default: on; requires --scope)', dest='no_broker'), ArgDef(name='--scope', help='Credential scope; enables vault SSH agent and is required by gate/broker'), ArgDef(name='--profiles', type=_csv_list, help="Override shield profiles for this container (comma-separated, e.g. 'dev,pypi')"))), CommandDef(name='cleanup', help='Revoke tokens and drop shield rules for a sandboxed container', handler=_handle_cleanup, args=(ArgDef(name='container', help='Container name to clean up'),)))
module-attribute
¶
SETUP_COMMANDS = (CommandDef(name='setup', help='Install supervisor hooks + shield hooks in one step', handler=_handle_sandbox_setup, args=(ArgDef(name='--no-shield', action='store_true', help='Skip shield install'), ArgDef(name='--no-vault', action='store_true', help='Skip the credentials-DB encryption phase'), ArgDef(name='--echo-passphrase', action='store_true', help='Also print any auto-generated vault passphrase to stdout (default off — the value otherwise only reaches /dev/tty, so non-interactive bootstraps must opt in to capture it)'), ArgDef(name='--passphrase-tier', default=None, help='Force credentials-DB passphrase storage to a specific tier (systemd-creds | keyring | session-file | config) instead of the auto-detect / chooser chain. Required on a non-TTY host without systemd-creds — the silent session-file fallback was removed in v0.0.100 because it minted a passphrase the operator never saw and lost it on the first reboot.'))), CommandDef(name='uninstall', help='Remove supervisor hooks + shield hooks in one step', handler=_handle_sandbox_uninstall, args=(ArgDef(name='--no-shield', action='store_true', help='Skip shield uninstall'),)))
module-attribute
¶
SHIELD_COMMANDS = (CommandDef(name='shield', help='Egress firewall management', children=(_SANDBOX_VERBS + _imported_shield_children())),)
module-attribute
¶
SSH_COMMANDS = (CommandDef(name='ssh', help='SSH keypair management', children=(CommandDef(name='list', help='List SSH keys stored in the vault', handler=_handle_ssh_list, args=(ArgDef(name='--scope', help='Show keys for a specific credential scope only', default=None),)), CommandDef(name='import', help='Import an OpenSSH keypair from files into the vault DB', handler=_handle_ssh_import, args=(ArgDef(name='scope', help='Credential scope to associate the key with'), ArgDef(name='--private-key', help='Path to the private key file', dest='private_key', required=True), ArgDef(name='--public-key', help='Path to the .pub file (default: derive from the private key)', default=None, dest='public_key'), ArgDef(name='--comment', help="Override the key's comment string", default=None))), CommandDef(name='add', help='Generate a new SSH keypair in the vault for a credential scope', handler=_handle_ssh_add, args=(ArgDef(name='scope', help='Credential scope to associate the key with'), ArgDef(name='--key-type', help='Key algorithm: ed25519 (default) or rsa', default='ed25519', dest='key_type'), ArgDef(name='--comment', help='Comment embedded in the public key (default: tk-main:<scope>)', default=None), ArgDef(name='--force', help='Rotate — unassign all existing keys from the scope and generate fresh', action='store_true'))), CommandDef(name='export', help="Export a scope's SSH keypair to standard OpenSSH files", handler=_handle_ssh_export, args=(ArgDef(name='scope', help='Credential scope to export'), ArgDef(name='--out-dir', help='Directory to write files into', dest='out_dir', required=True), ArgDef(name='--key-id', help='Export a specific ssh_keys.id (default: most recently added)', default=None, dest='key_id', type=int), ArgDef(name='--out-name', help='Override the output filename stem (default: id_<type>_<fp8>)', default=None, dest='out_name'))), CommandDef(name='pub', help="Print a scope's public key to stdout", handler=_handle_ssh_pub, args=(ArgDef(name='scope', help='Credential scope'), ArgDef(name='--key-id', help='Specific ssh_keys.id (default: most recently added)', default=None, dest='key_id', type=int), ArgDef(name='--all', help='Print every key assigned to the scope, one per line', action='store_true', dest='all_keys'))), CommandDef(name='link', help='Link an existing vault key to an additional scope', handler=_handle_ssh_link, args=(ArgDef(name='scope', help='Credential scope to link the key to'), ArgDef(name='--key-id', help='ssh_keys.id of the key already stored in the vault', dest='key_id', type=int, required=True))), CommandDef(name='rename', help='Change the comment of a stored SSH key (selected by fingerprint prefix)', handler=_handle_ssh_rename, args=(ArgDef(name='fingerprint', help='Fingerprint prefix identifying the key (min 8 chars recommended)'), ArgDef(name='comment', help='New comment text'))), CommandDef(name='remove', help='Unassign SSH keys from scopes (orphaned keys cascade-delete)', handler=_handle_ssh_remove, args=(ArgDef(name='--scope', help='Filter by credential scope (exact match)', default=None), ArgDef(name='--comment', help='Filter by comment (supports glob wildcards)', default=None), ArgDef(name='--fingerprint', help='Filter by fingerprint prefix (min 8 chars recommended)', default=None), ArgDef(name='--yes', help='Skip confirmation prompts', action='store_true', dest='yes'))))),)
module-attribute
¶
SUPERVISOR_COMMANDS = (CommandDef(name='supervisor', help='Run the per-container supervisor (internal; spawned by the OCI hook)', handler=_handle_supervisor, group='internal', args=(ArgDef(name='container_id', help='Container ID the supervisor manages'), ArgDef(name='sidecar_path', help='Absolute path to the per-container sidecar JSON'))),)
module-attribute
¶
VAULT_COMMANDS = (CommandDef(name='vault', help='Vault passphrase management', children=(CommandDef(name='unlock', help='Provision the credentials-DB passphrase for this session (tmpfs file)', handler=_handle_vault_unlock), CommandDef(name='lock', help='Remove the session-unlock tmpfs file', handler=_handle_vault_lock), CommandDef(name='list', help='Inventory stored credentials (and optionally proxy tokens)', handler=_handle_vault_list, args=(ArgDef(name='--include-tokens', action='store_true', help='Also show proxy-token rows (token values are masked)'), ArgDef(name='--json', dest='as_json', action='store_true', help='Machine-readable JSON output'))), _PASSPHRASE_GROUP)),)
module-attribute
¶
COMMANDS = CommandTree(SETUP_COMMANDS + GATE_COMMANDS + SHIELD_COMMANDS + VAULT_COMMANDS + SSH_COMMANDS + CREDENTIALS_COMMANDS + LAUNCH_COMMANDS + DOCTOR_COMMANDS + SUPERVISOR_COMMANDS)
module-attribute
¶
__all__ = ['ArgDef', 'CommandDef', 'CommandTree', 'KeyRow', 'COMMANDS', 'CREDENTIALS_COMMANDS', 'DOCTOR_COMMANDS', 'GATE_COMMANDS', 'LAUNCH_COMMANDS', 'SETUP_COMMANDS', 'SHIELD_COMMANDS', 'SSH_COMMANDS', 'SUPERVISOR_COMMANDS', 'VAULT_COMMANDS', '_ask_passphrase_mode', '_back_up_plaintext_db', '_build_key_rows', '_filter_key_rows', '_forget_config_tier_updates', '_handle_cleanup', '_handle_credentials_encrypt_db', '_handle_doctor', '_handle_gate_path', '_handle_prepare', '_handle_run', '_handle_sandbox_setup', '_handle_sandbox_uninstall', '_handle_shield_setup', '_handle_shield_uninstall', '_handle_ssh_add', '_handle_ssh_export', '_handle_ssh_import', '_handle_ssh_link', '_handle_ssh_list', '_handle_ssh_pub', '_handle_ssh_remove', '_handle_ssh_rename', '_handle_supervisor', '_handle_vault_destroy_passphrase', '_handle_vault_list', '_handle_vault_lock', 'handle_vault_seal', 'handle_vault_to_keyring', '_handle_vault_unlock', '_key_id_from_row', '_open_db', '_persist_mode_choice', '_print_key_table', '_provision_passphrase', '_run_credentials_setup_phase', '_validate_scope_name']
module-attribute
¶
handle_vault_seal(*, cfg=None, key='auto')
¶
Seal the credentials-DB passphrase into a systemd-creds credential.
Adds the systemd-creds tier to the resolution chain: machine-bound
(TPM2 + host key, or either alone), survives reboot, no OS
keyring required. After sealing, every new supervisor resolves the
passphrase via systemd-creds decrypt on start — no operator
interaction needed at boot, no plaintext-on-disk.
Requires an already-resolvable passphrase — typically from a fresh
vault unlock in the current session.
Source code in src/terok_sandbox/commands/vault.py
handle_vault_to_keyring(*, cfg=None)
¶
Move the current passphrase from its current tier into the OS keyring.
Resolves the passphrase via the chain (or prompts as a last resort),
writes it to the keyring, flips credentials.use_keyring to true
in config.yml, clears any plaintext credentials.passphrase /
credentials.passphrase_command wiring, and removes the
session-file and sealed systemd-creds copies.
The validate-before-destroy ordering is deliberate: if the keyring write fails, the source tier is still intact.