Skip to content

selinux_fix_screen

selinux_fix_screen

Modal that offers the two SELinux-policy fixes after a setup exit 5.

The sandbox setup CLI handler exits with code 5 when all install phases succeed but the host's SELinux policy is missing — see terok-ai/terok-sandbox#298. The TUI catches that exit code and pushes this screen.

Two paths forward:

  • Install the policy (sudo bash …) — dispatches the bundled installer script as a console action; the user authenticates to sudo in the captured-log view. After a successful install, the caller re-runs setup.
  • Switch to TCP mode — flips services.mode to tcp in the user-scope config.yml; no SELinux policy is required after the flip. The caller re-runs setup.

A Skip button bails out without changing anything (the operator can re-open the same modal from the command palette by re-running setup).

SelinuxFixOutcome

Bases: Enum

User's pick from SelinuxFixScreen.

INSTALL_POLICY = 'install_policy' class-attribute instance-attribute

Run sudo bash <install_script> to load terok_socket_t.

SWITCH_TO_TCP = 'switch_to_tcp' class-attribute instance-attribute

Write services.mode: tcp to the user config and re-run setup.

SKIPPED = 'skipped' class-attribute instance-attribute

Dismiss without changing anything.

SelinuxFixScreen

Bases: ModalScreen[SelinuxFixOutcome]

Modal that surfaces the two remediations for a setup exit-5 finish.

BINDINGS = [Binding('escape', 'close', 'Close'), Binding('i', 'install_policy', 'Install policy'), Binding('t', 'switch_to_tcp', 'Switch to TCP'), Binding('s', 'skip', 'Skip')] class-attribute instance-attribute

CSS = '\n SelinuxFixScreen {\n align: center middle;\n }\n\n #selinux-fix-dialog {\n width: 80;\n max-width: 100%;\n height: auto;\n max-height: 80%;\n border: heavy $primary;\n border-title-align: right;\n background: $surface;\n padding: 1 2;\n }\n\n #selinux-fix-headline {\n height: auto;\n margin-bottom: 1;\n }\n\n #selinux-fix-blurb {\n color: $text-muted;\n height: auto;\n margin-bottom: 1;\n }\n\n #selinux-fix-buttons {\n height: auto;\n align-horizontal: right;\n }\n\n #selinux-fix-buttons Button {\n margin-left: 1;\n }\n ' class-attribute instance-attribute

compose()

Build the modal: headline, explanation, three buttons.

Source code in src/terok/tui/selinux_fix_screen.py
def compose(self) -> ComposeResult:
    """Build the modal: headline, explanation, three buttons."""
    dialog = Vertical(id="selinux-fix-dialog")
    dialog.border_title = "SELinux policy required"
    with dialog:
        yield Static(
            "Sandbox setup finished, but the terok_socket_t SELinux policy "
            "isn't loaded — containers can't reach the host sockets without it.",
            id="selinux-fix-headline",
        )
        yield Label(
            "Pick one of the two remediations below.  Both run setup again "
            "afterwards so the install can complete cleanly.",
            id="selinux-fix-blurb",
        )
        with Horizontal(id="selinux-fix-buttons"):
            yield from self._buttons()

action_close()

Esc dismisses with SelinuxFixOutcome.SKIPPED.

Source code in src/terok/tui/selinux_fix_screen.py
def action_close(self) -> None:
    """Esc dismisses with [`SelinuxFixOutcome.SKIPPED`][terok.tui.selinux_fix_screen.SelinuxFixOutcome.SKIPPED]."""
    self.dismiss(SelinuxFixOutcome.SKIPPED)

action_install_policy()

Key binding for Install policy.

Source code in src/terok/tui/selinux_fix_screen.py
def action_install_policy(self) -> None:
    """Key binding for Install policy."""
    self.dismiss(SelinuxFixOutcome.INSTALL_POLICY)

action_switch_to_tcp()

Key binding for Switch to TCP.

Source code in src/terok/tui/selinux_fix_screen.py
def action_switch_to_tcp(self) -> None:
    """Key binding for Switch to TCP."""
    self.dismiss(SelinuxFixOutcome.SWITCH_TO_TCP)

action_skip()

Key binding for Skip.

Source code in src/terok/tui/selinux_fix_screen.py
def action_skip(self) -> None:
    """Key binding for Skip."""
    self.dismiss(SelinuxFixOutcome.SKIPPED)

on_button_pressed(event)

Route the three button IDs to their dismissal outcomes.

Source code in src/terok/tui/selinux_fix_screen.py
def on_button_pressed(self, event: Button.Pressed) -> None:
    """Route the three button IDs to their dismissal outcomes."""
    match event.button.id:
        case "selinux-fix-install":
            self.dismiss(SelinuxFixOutcome.INSTALL_POLICY)
        case "selinux-fix-tcp":
            self.dismiss(SelinuxFixOutcome.SWITCH_TO_TCP)
        case "selinux-fix-skip":
            self.dismiss(SelinuxFixOutcome.SKIPPED)