diff --git a/README.md b/README.md index f029483..22b6227 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,90 @@ -# layer_wizard +# Layer Wizard -A new Flutter project. +A GUI installer wizard for permanently layering an RPM package onto a +bootc/image-based (read-only root) Linux system via `rpm-ostree install`, +with a guided reboot step and a one-click rollback if the result looks wrong. -## Getting Started +Built for Universal Blue / Fedora bootc systems, where plain `dnf install` +refuses to run (the root filesystem is read-only) and the persistent +mechanism is `rpm-ostree install `, which stages a new deployment that +only takes effect after a reboot. -This project is a starting point for a Flutter application. +## What it does -A few resources to get you started if this is your first Flutter project: +1. **Welcome** — shows the currently booted version/image. +2. **Package** — enter a package name; "Check" confirms it resolves + (`dnf repoquery`) before anything privileged happens. +3. **Confirm** — review the package and what's about to happen. +4. **Apply** — runs `pkexec rpm-ostree install -y `, with the + PolicyKit password prompt and a live streamed log. On success, offers + **Reboot Now** / **Reboot Later**. +5. After rebooting, the app **launches itself automatically** and asks: + "Is everything working correctly?" — **Yes, keep this update**, or + **No, something's wrong — roll back**, which runs + `pkexec bootc rollback --apply` (reboots immediately into the previous + deployment). -- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) -- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources) +## How the post-reboot check works -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. +This system has no `greenboot` and no automated bad-boot detection +(`systemd-bless-boot.service` exists but isn't wired up to anything here) — +so the rollback offer is **self-reported**, not automatic. Two pieces make +that work: + +- **Autostart entry.** Right after a successful install, + `ConfirmationMarker.installAutostart()` (`lib/confirmation_marker.dart`) + writes `~/.config/autostart/com.ironmagma.layer_wizard.desktop`, with + `Exec=` pointing at the currently-running binary + (`Platform.resolvedExecutable`). KDE's session runs everything in + `~/.config/autostart/` on login, which is what makes the app reappear on + its own right after the reboot — you don't have to remember to open it. + +- **The check itself runs on every launch, not just via autostart.** + `lib/main.dart`'s `_StartupRouter` calls `ConfirmationMarker.read()` before + deciding what to show: + + ```dart + future: ConfirmationMarker.read(), + builder: (context, snapshot) { + final pending = snapshot.data; + if (pending != null) return ConfirmationPage(pending: pending); + return const WizardHomePage(); + } + ``` + + `read()` just checks whether + `~/.local/state/layer_wizard/pending_confirmation.json` exists and parses + it. That file is written by the wizard right after a successful install + (`ConfirmationMarker.write(...)` in `lib/wizard_page.dart`), and deleted — + along with the autostart entry — as soon as you click **Keep** or + **Roll back** in `lib/confirmation_page.dart`. + + Running the check unconditionally at startup (rather than only when + launched via autostart) is deliberate: if autostart doesn't fire for some + reason, or you dismiss it and reopen the app later, you still land on the + confirmation screen instead of that pending state getting silently + dropped. + +## Project layout + +- `lib/ostree_service.dart` — all privileged/unprivileged shelling out: + `rpm-ostree status --json`, `dnf repoquery`, `pkexec rpm-ostree install`, + `pkexec bootc rollback --apply`, `pkexec systemctl reboot`. +- `lib/confirmation_marker.dart` — the pending-confirmation marker file and + autostart `.desktop` entry (write/read/clear, install/remove). +- `lib/wizard_page.dart` — the install wizard (`Stepper`-based). +- `lib/confirmation_page.dart` — the post-reboot "did this work?" screen. +- `lib/main.dart` — startup routing between the two. + +Privilege escalation follows the same pattern as the sibling +[`dnf-package-store`](https://github.com/quine-global-labs/dnf-package-store) +app: `pkexec` through the desktop PolicyKit agent, with stdout/stderr +streamed line-by-line into the UI. + +## Building + +``` +flutter build linux +``` + +Produces `build/linux/x64/release/bundle/layer_wizard`.