Skip to content

prereqs

prereqs

Host binary prerequisite checks for the shield runtime.

Exported for higher layers (terok-sandbox aggregator, operator diagnostics) so the place that owns each binary — shield — is the place that publishes the list of binaries it depends on. Keeps the install-time preflight and the runtime failure sites honest about what the shield actually needs.

Pure probes: every check is shutil.which or a sbin-aware variant. No subprocess invocation, no side effects.

BinaryCheck(name, path, purpose) dataclass

Result of probing for a single prerequisite binary.

name instance-attribute

Invocation name, as the shell would resolve it.

path instance-attribute

Absolute path to the resolved binary, or empty string if missing.

purpose instance-attribute

One-line rationale, rendered in verbose CLI output.

ok property

True when the binary was located on PATH or a standard sbin directory.

check_firewall_binaries()

Probe the host for binaries the shield runtime uses.

Returns a stable-ordered tuple covering nft (ruleset enforcement), dnsmasq (optional local DNS tier), and dig (profile-domain resolution). Callers render the results however they want and decide whether a missing entry should warn, block, or be ignored for their workflow.

Source code in src/terok_shield/prereqs.py
def check_firewall_binaries() -> tuple[BinaryCheck, ...]:
    """Probe the host for binaries the shield runtime uses.

    Returns a stable-ordered tuple covering ``nft`` (ruleset
    enforcement), ``dnsmasq`` (optional local DNS tier), and ``dig``
    (profile-domain resolution).  Callers render the results however
    they want and decide whether a missing entry should warn, block,
    or be ignored for their workflow.
    """
    return (
        BinaryCheck("nft", which_sbin_aware("nft"), "nftables ruleset enforcement"),
        BinaryCheck("dnsmasq", which_sbin_aware("dnsmasq"), "local DNS caching resolver"),
        BinaryCheck("dig", shutil.which("dig") or "", "DNS resolution for allowlist domains"),
    )

check_krun_binaries()

Probe the host for binaries the krun runtime path adds.

Separate from check_firewall_binaries because the krun runtime is experimental — callers should gate this probe on whatever flag they use to expose krun (in terok, the top-level experimental: toggle). Reporting ip as missing to an operator who never touches krun would be noise.

Source code in src/terok_shield/prereqs.py
def check_krun_binaries() -> tuple[BinaryCheck, ...]:
    """Probe the host for binaries the krun runtime path adds.

    Separate from [`check_firewall_binaries`][terok_shield.prereqs.check_firewall_binaries]
    because the krun runtime is experimental — callers should gate this
    probe on whatever flag they use to expose krun (in terok, the
    top-level ``experimental:`` toggle).  Reporting ``ip`` as missing
    to an operator who never touches krun would be noise.
    """
    return (
        BinaryCheck(
            "ip",
            which_sbin_aware("ip"),
            "in-netns IP assignment for the krun runtime",
        ),
    )

which_sbin_aware(name)

Resolve name like shutil.which, falling back to sbin directories.

Returns the absolute path of the first match or an empty string when the binary is not on PATH and not in /usr/sbin or /sbin. The sbin fallback reuses shutil.which with an explicit path= so executability (os.X_OK) is checked the same way PATH resolution would — a regular non-executable file in /usr/sbin shouldn't count as a hit.

Source code in src/terok_shield/prereqs.py
def which_sbin_aware(name: str) -> str:
    """Resolve *name* like [`shutil.which`][shutil.which], falling back to sbin directories.

    Returns the absolute path of the first match or an empty string
    when the binary is not on ``PATH`` and not in ``/usr/sbin`` or
    ``/sbin``.  The sbin fallback reuses [`shutil.which`][shutil.which] with an
    explicit ``path=`` so executability (``os.X_OK``) is checked the
    same way ``PATH`` resolution would — a regular non-executable file
    in ``/usr/sbin`` shouldn't count as a hit.
    """
    for search_path in (None, *_SBIN_DIRS):
        found = shutil.which(name, path=search_path)
        if found:
            return found
    return ""