# TANINUX GTK-Frontend

GTK4 + libadwaita Desktop-App neben der Textual-TUI. Teilt sich die
`taninux.core`-Engine (sysinfo / pacman / bootloader / snapshot …).

## Start

```sh
# System-Abhängigkeiten (empfohlen statt pip-Build von PyGObject):
sudo pacman -S python-gobject gtk4 libadwaita

# starten
python -m taninux.gui
# oder nach `uv pip install -e .`:
taninux-gtk
```

## Architektur

```
gui/
  app.py        Adw.Application + main()
  window.py     Adw.NavigationSplitView: Sidebar (Pillar-Liste) + Content-Stack
  process.py    async Gio.Subprocess-Runner (non-blocking), pkexec für root
  console.py    LogConsole + RunnerCard — Button → privilegierter Befehl → Live-Output
  pages/
    __init__.py PAGES-Registry (key, label, icon, builder) — Pendant zur PILLARS-Liste
    overview.py read-only, komplett aus core.sysinfo
    update.py   `pacman -Syu` via pkexec, Live-Stream (Async-Showcase)
    kernel.py   installierte Kernel + bootloader, linux-lts via pkexec installieren
    settings.py SwitchRow/ComboRow/SpinRow/ColorScheme — das libadwaita-Vokabular
```

Neue Seite = Modul in `pages/` mit `build() -> Gtk.Widget` + ein Eintrag in
`PAGES`. Genau wie ein neuer Pillar in der TUI.

## Privilege Escalation — dedizierter Helper

`process.ProcessRunner(... privileged=True)` führt root-Befehle **nicht** mehr
als `pkexec pacman …` (= beliebiges root) aus, sondern schleust das argv durch
einen dedizierten Helper:

```
pkexec /usr/lib/taninux/taninux-helper  <argv…>
```

Der Helper (`helper/taninux-helper`) validiert das argv gegen eine feste
**Allowlist** und lehnt alles andere mit Exit ≠ 0 ab. Erlaubt sind nur:

| Kommando   | Operationen                                  | erlaubte Flags                              |
|------------|----------------------------------------------|---------------------------------------------|
| `pacman`   | `-S` `-Sy` `-Su` `-Syu` `-R` `-Rs` `-Rns`    | `--noconfirm` `--needed` `--noprogressbar`  |
| `bootctl`  | `set-default` `set-oneshot`                  | —                                           |
| `paccache` | `-r` `-rk1` `-rk0` `-ruk0`                    | `-k` `0`–`3` `--remove` `--uninstalled`     |

Operanden (Paketnamen, Boot-Einträge) sind frei — Tokens mit führendem `-`,
die nicht oben stehen, werden abgelehnt. Es läuft KEINE Shell, der Helper
`execvp()`t exakt das übergebene argv. Die argv-Schnittstelle nach aussen
(`RunnerCard(label, ["pacman","-Syu"], privileged=True)`) bleibt unverändert.

Findet `process.py` `/usr/lib/taninux/taninux-helper` nicht, fällt es auf den
Helper im Repo zurück (`gui/helper/taninux-helper`) — praktisch für Dev ohne
Installation.

### Installation (Helper + Policy)

```sh
sudo install -Dm755 src/taninux/gui/helper/taninux-helper \
    /usr/lib/taninux/taninux-helper
sudo cp src/taninux/gui/polkit/ch.gabrielevarano.Taninux.policy \
    /usr/share/polkit-1/actions/
```

Die Policy (`action id = ch.gabrielevarano.taninux.maintain`,
`exec.path = /usr/lib/taninux/taninux-helper`, `allow_active = auth_admin_keep`)
sorgt für **einmal Passwort pro Session**, danach gecached.

### polkit-Auth-Agent

Damit pkexec **ohne** Terminal nach dem Passwort fragen kann, muss ein
polkit-Auth-Agent laufen. Auf wlroots/eww-Setups ist der oft nicht automatisch
da — starte einen in deiner Autostart-Config:

- `polkit-gnome` Agent, oder
- `lxqt-policykit` (`/usr/lib/lxqt-policykit/lxqt-policykit-agent`), oder
- `mate-polkit` / `hyprpolkitagent`
