Skip to content

Preflight

preflight

First-run readiness gate for terok-executor run.

Mandatory prerequisites (podman, sandbox services, container images) block the launch if unmet after interactive remediation; optional prerequisites (SSH key, per-agent credentials) print the consequence of skipping and let the launch proceed.

The check-and-fix surface lives on the Preflight class: parameters that thread through every probe (provider, base image, family, interactivity mode, --yes short-circuit) are held once on the instance instead of being repeated in every free-function signature. Callers construct Preflight(provider="claude").run() in production; tests construct it with defaults and call individual check_* methods.

CheckResult(name, ok, message) dataclass

Outcome of a single prerequisite check.

name instance-attribute

ok instance-attribute

message instance-attribute

Preflight(provider, base_image='ubuntu:24.04', family=None, interactive=True, assume_yes=False, credential_set='default', mounts_dir=None) dataclass

Holds the parameters that thread through every prerequisite check.

The orchestrator run walks every gate / probe in order and reports a single "mandatory-everything-passed" verdict. Individual probes (check_podman etc.) are exposed as methods so callers (doctor surfaces, tests) can ask narrow questions without paying for the full sweep.

provider instance-attribute

base_image = 'ubuntu:24.04' class-attribute instance-attribute

family = None class-attribute instance-attribute

interactive = True class-attribute instance-attribute

assume_yes = field(default=False) class-attribute instance-attribute

credential_set = 'default' class-attribute instance-attribute

Vault DB namespace to check for stored credentials. Pairs with Authenticator.run's credential_set — a project running with per-project credentials passes its own value so the preflight verdict reflects what the runtime will actually load, not the shared host-wide bucket.

mounts_dir = None class-attribute instance-attribute

Override for the agent-config mount tree. None means use the global paths.mounts_dir. Callers that pair a non-"default" credential_set with a per-project mount tree (terok in scope=project mode) must override this too — otherwise the captured OAuth credential's post-capture writer drops the phantom marker into the wrong tree and the runtime never sees it.

run()

Run every prerequisite check and return True iff mandatory items pass.

In non-interactive mode, missing mandatory prerequisites are reported once and the return is False; in interactive mode each one is offered up as a y/N fix before counting against readiness. Optional items never turn the return into False — their consequence is printed and the launch proceeds.

Source code in src/terok_executor/preflight.py
def run(self) -> bool:
    """Run every prerequisite check and return ``True`` iff mandatory items pass.

    In non-interactive mode, missing mandatory prerequisites are
    reported once and the return is ``False``; in interactive mode
    each one is offered up as a y/N fix before counting against
    readiness.  Optional items never turn the return into ``False`` —
    their consequence is printed and the launch proceeds.
    """
    print()
    all_ready = True

    if not self._require_podman():
        return False

    self._offer_git()

    if not self._require_sandbox_services():
        all_ready = False

    if not self._require_images():
        all_ready = False

    self._offer_ssh_key()
    self._offer_credentials()
    self._note_shield_bypass()

    if all_ready and self.interactive:
        self._provider_hints()

    print()
    return all_ready

check_podman()

Verify that podman is installed and responds to podman version.

Source code in src/terok_executor/preflight.py
def check_podman(self) -> CheckResult:  # noqa: PLR6301
    """Verify that podman is installed and responds to ``podman version``."""
    if not shutil.which("podman"):
        return CheckResult("podman", False, "not found on PATH")
    try:
        result = subprocess.run(
            ["podman", "version", "--format", "{{.Client.Version}}"],
            capture_output=True,
            timeout=10,
        )
    except (subprocess.TimeoutExpired, FileNotFoundError, OSError) as exc:
        return CheckResult("podman", False, f"found but not responding: {exc}")
    if result.returncode != 0:
        detail = (result.stderr or b"").decode(errors="ignore").strip() or "non-zero exit"
        return CheckResult("podman", False, f"found but not responding: {detail}")
    return CheckResult("podman", True, "ok")

check_git()

Report whether git is available on the host PATH.

Informational only: terok-sandbox's git gate uses the host git binary to mirror upstream repositories, but a container without a gate is functionally identical from a security perspective — the gate exists to provide a push channel, not to enforce isolation. A missing git therefore degrades the workflow (no in-container git push) but never blocks a launch.

Source code in src/terok_executor/preflight.py
def check_git(self) -> CheckResult:  # noqa: PLR6301
    """Report whether ``git`` is available on the host PATH.

    Informational only: terok-sandbox's git gate uses the host git
    binary to mirror upstream repositories, but a container without a
    gate is functionally identical from a security perspective — the
    gate exists to provide a *push channel*, not to enforce isolation.
    A missing git therefore degrades the workflow (no in-container
    ``git push``) but never blocks a launch.
    """
    if not shutil.which("git"):
        return CheckResult("git", False, "not found on PATH — git gate disabled")
    return CheckResult("git", True, "ok")

check_sandbox_services()

Verify the shield OCI hooks are installed.

The vault and git gate are not host services: the per-container supervisor (spawned by the terok-sandbox OCI hook) embeds the vault proxy and serves the git gate in-process, both starting on demand. The only host-side service that must exist before a launch is therefore the shield OCI hooks; the git binary that drives gate mirrors is surfaced separately by check_git.

Source code in src/terok_executor/preflight.py
def check_sandbox_services(self) -> CheckResult:  # noqa: PLR6301
    """Verify the shield OCI hooks are installed.

    The vault and git gate are not host services: the per-container
    supervisor (spawned by the terok-sandbox OCI hook) embeds the
    vault proxy *and* serves the git gate in-process, both starting
    on demand.  The only host-side service that must exist before a
    launch is therefore the shield OCI hooks; the git binary that
    drives gate mirrors is surfaced separately by
    [`check_git`][terok_executor.preflight.Preflight.check_git].
    """
    from terok_executor.integrations.sandbox import SandboxConfig, check_environment

    # One SandboxConfig read keeps the probe from rebuilding it from
    # layered YAML on every call.
    cfg = SandboxConfig()
    # "bypass" means the hooks are installed but the operator opted
    # out — that's a ready environment (the bypass itself is surfaced
    # as a warning by ``_note_shield_bypass``), so only a genuinely
    # missing/broken environment fails the check.
    if check_environment(cfg).health not in ("ok", "bypass"):
        return CheckResult("sandbox services", False, "missing: shield hooks")
    return CheckResult("sandbox services", True, "shield ready")

check_images()

Check whether L0+L1 container images exist.

Source code in src/terok_executor/preflight.py
def check_images(self) -> CheckResult:
    """Check whether L0+L1 container images exist."""
    from terok_executor.container.build import ImageBuilder

    tag = ImageBuilder(self.base_image).l1_tag()
    try:
        result = subprocess.run(
            ["podman", "image", "exists", tag],
            capture_output=True,
            timeout=10,
        )
        if result.returncode == 0:
            return CheckResult("container images", True, "ready")
    except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
        pass
    return CheckResult("container images", False, "not built")

check_credentials()

Check whether credentials are stored for the configured provider.

Source code in src/terok_executor/preflight.py
def check_credentials(self) -> CheckResult:
    """Check whether credentials are stored for the configured *provider*."""
    from terok_executor.integrations.sandbox import SandboxConfig

    try:
        db = SandboxConfig().open_credential_db()
    except Exception:  # noqa: BLE001
        return CheckResult(
            f"{self.provider} credentials", False, "credential database unavailable"
        )
    try:
        cred = db.load_credential(self.credential_set, self.provider)
    finally:
        db.close()
    if cred:
        return CheckResult(f"{self.provider} credentials", True, "stored")
    return CheckResult(f"{self.provider} credentials", False, "not found")

check_ssh_key(scope='standalone')

Check whether a gate-signing SSH key exists for scope.

Source code in src/terok_executor/preflight.py
def check_ssh_key(self, scope: str = "standalone") -> CheckResult:  # noqa: PLR6301
    """Check whether a gate-signing SSH key exists for *scope*."""
    from terok_executor.integrations.sandbox import SandboxConfig

    try:
        db = SandboxConfig().open_credential_db()
    except Exception:  # noqa: BLE001
        return CheckResult("ssh key", False, "credential database unavailable")
    try:
        keys = db.list_ssh_keys_for_scope(scope)
    finally:
        db.close()
    if keys:
        return CheckResult("ssh key", True, f"{len(keys)} key(s) registered for '{scope}'")
    return CheckResult("ssh key", False, f"none registered for '{scope}'")

check_shield()

Check whether shield OCI hooks are installed (informational).

Source code in src/terok_executor/preflight.py
def check_shield(self) -> CheckResult:  # noqa: PLR6301
    """Check whether shield OCI hooks are installed (informational)."""
    from terok_executor.integrations.sandbox import check_environment

    ec = check_environment()
    if ec.health == "ok":
        return CheckResult("shield", True, "active")
    return CheckResult("shield", False, "not installed (containers have unrestricted network)")