Skip to content

simple_clearance

simple_clearance

Terminal-based clearance fallback for hosts without the D-Bus hub.

simple-clearance is the stripped-down sibling of the full Clearance flow: instead of desktop notifications and a TUI sharing signals over org.terok.Shield1, it streams blocked-connection events from a subprocess NFLOG reader and prompts the operator on a terminal. Verdicts are applied by shelling out to the audited terok-shield allow|deny CLI, so the trust boundary is identical.

Refuses to run when the D-Bus hub is active on the session bus — concurrent application from both paths would race on the same verdict, so only one is enabled at a time.

ClearanceSession(*, state_dir, container)

Drive the terminal clearance loop for a single container.

Owns the reader subprocess, the operator prompt UI, and the verdict subprocess calls. Lives until the reader exits or the operator interrupts with Ctrl-C.

Prepare the session — the reader is spawned in run.

Source code in src/terok_shield/simple_clearance.py
def __init__(self, *, state_dir: Path, container: str) -> None:
    """Prepare the session — the reader is spawned in [`run`][terok_shield.simple_clearance.ClearanceSession.run]."""
    self._state_dir = state_dir
    self._container = container
    self._queue: list[_Pending] = []
    self._stop_requested = False

run()

Spawn the reader, then multiplex its stdout with stdin prompts.

Source code in src/terok_shield/simple_clearance.py
def run(self) -> None:  # pragma: no cover — real subprocess + tty I/O, integration path
    """Spawn the reader, then multiplex its stdout with stdin prompts."""
    reader = self._spawn_reader()
    if reader.stdout is None:
        print("Error: reader stdout is closed.", file=sys.stderr)
        raise SystemExit(1)

    self._install_signal_handlers()
    print("Watching for blocked connections... (Ctrl-C to stop)\n", flush=True)
    try:
        self._event_loop(reader)
    finally:
        self._shutdown_reader(reader)

run_simple_clearance(state_dir, container)

Run the terminal clearance fallback for container.

Refuses to start when org.terok.Shield1 already has an owner on the session bus — the D-Bus hub would race this tool on every verdict.

Parameters:

Name Type Description Default
state_dir Path

Per-container shield state directory.

required
container str

Container name.

required
Source code in src/terok_shield/simple_clearance.py
def run_simple_clearance(state_dir: Path, container: str) -> None:
    """Run the terminal clearance fallback for *container*.

    Refuses to start when ``org.terok.Shield1`` already has an owner on
    the session bus — the D-Bus hub would race this tool on every verdict.

    Args:
        state_dir: Per-container shield state directory.
        container: Container name.
    """
    if _dbus_hub_active():
        print(
            "D-Bus hub (org.terok.Shield1) is active — use a D-Bus clearance "
            "client (desktop notifier or TUI).  To use this terminal fallback, "
            "stop the hub first:  systemctl --user stop terok-clearance-hub",
            file=sys.stderr,
        )
        raise SystemExit(1)

    session = ClearanceSession(state_dir=state_dir, container=container)
    session.run()