Skip to content

linux-updater: background system updates with history and rollback for any major distro - #389

Draft
UmedjonBA wants to merge 1 commit into
noctalia-dev:mainfrom
UmedjonBA:linux-updater-plugin
Draft

linux-updater: background system updates with history and rollback for any major distro#389
UmedjonBA wants to merge 1 commit into
noctalia-dev:mainfrom
UmedjonBA:linux-updater-plugin

Conversation

@UmedjonBA

Copy link
Copy Markdown
Contributor

Plugin

  • Id: umedbazarov/linux-updater
  • New plugin
  • Update to an existing plugin (version bumped in plugin.toml)

What it does

A system updater for any major distribution, grown out of arch-updater (relation disclosed below). One click updates the system in the background: polkit asks for the password, the panel shows a live tail of the update log with a progress bar, the run is fully non-interactive and detached (it survives a shell restart — the engine re-attaches to the log). Finished runs land on a history strip: one segment per run, click opens its package list, and where the distribution supports it packages or whole runs can be rolled back (two-click confirmation; the package manager itself refuses any transaction that would break dependencies). An expandable Ignored section unifies the plugin's own ignore list (editable from package rows) with the system's mechanisms (IgnorePkg, apt-mark hold), and the ignore list is honored during updates. When the system is missing a one-time setup piece — the polkit keep-authorization rule so one password covers a run, apt's list-refresh timers — the panel says so and offers a one-click, one-confirmation fix; nothing is changed silently.

The engine is distro-neutral. Each package manager is a backend file (backends/*.luau) declaring commands, parsers and a capability set the UI honors, so a backend without rollback simply shows no rollback buttons. The backend is picked from /etc/os-release (ID, then ID_LIKE — Manjaro and friends resolve to pacman), overridable in settings:

  • pacman (Arch family): full feature set — AUR via paru/yay, [ignored] detection, download size, Arch news, cache-based per-package/per-run rollback with same-run dependencies, --ignore.
  • dnf (Fedora): old→new versions via rpm join, whole-run rollback through dnf history undo (transaction id recorded after each run), needs-restarting, --exclude.
  • apt (Debian/Ubuntu/Mint/…): unprivileged check via apt list --upgradable (relies on the apt-daily timers; a self-check offers to enable them), holds applied for the duration of the transaction, /var/run/reboot-required.
  • zypper (openSUSE): dup on Tumbleweed / up on Leap, locks for the ignore list, zypper needs-rebooting; rollback deliberately off (snapper is the right tool there).
  • xbps (Void): dry-run check, holds via xbps-pkgdb; runit-aware (no systemd calls).
  • PackageKit: generic fallback for anything else; escalation through PackageKit's own polkit policies (no pkexec at all).

Flatpak checking/updating works on every backend. NixOS is intentionally out of scope (nix-monitor already covers it); the backend interface is open for a Gentoo/other contribution. The README carries the full capability matrix and an honest Testing status section.

External dependencies

Declared in dependencies; only the entry matching the distribution is actually needed (the panel reports what is missing): pacman+pacman-contrib, or dnf, or apt-get, or zypper, or xbps-install, or pkcon; plus sh, awk, sed, tail, test, uname, pkexec; optional paru/yay, flatpak, sudo, xdg-open, a terminal emulator.

Full accounting: network access equals what the corresponding manual check/upgrade would contact, plus the Arch news feed on the pacman backend. Files are written only to the plugin data directory (update.log, runs.json, ignore.json, news_state.json, run_meta.json, staged polkit rule + install marker) — with one exception: /etc/polkit-1/rules.d/49-linux-updater-<pm>.rules, written by pkexec install only after the user explicitly clicks the install button and authenticates. Spawned processes per backend are listed in each backends/*.luau header and the README Notes. Package-manager configuration files are never edited; the ignore mechanisms used are the managers' own (hold/lock), applied and released around the transaction.

Testing

  • Arch (pacman backend): fully exercised on a real system — background run including an AUR build (live log, progress, notification, auto re-check), per-package rollback from the cache and roll-forward, ignore/unignore, the polkit rule install button, history strip, engine resume mid-run.

  • dnf/apt/zypper/xbps/PackageKit: command layers exercised in podman containers on the real package managers — including the full upgrade → dnf history undo cycle on Fedora 41 and apt hold semantics on Ubuntu 24.04 — with outputs recorded as fixtures; all six parsers run against those fixtures in a test harness (luau CLI).

  • Not verified by anyone yet: live polkit dialogs / full UI on non-Arch distributions (containers cannot reproduce a polkit session), the dnf4 output branch, Debian deviations from Ubuntu. Non-Arch backends are labeled beta in the README; capability flags mean a gap degrades to a missing feature, not a broken system.

  • Tested on Niri

  • Tested on Hyprland

  • Tested on Sway

  • Tested on another compositor:

  • Noctalia version tested against: noctalia-git 5.0.0.r5274.gbf4da239d-1

  • Plugin API level: 9

Screenshots / Videos

In the plugin directory (also embedded in the README): screenshots/panel.png (pending updates with the download estimate and the polkit-rule offer) and screenshots/history.png (clean state with the update-history strip after an update → rollback → roll-forward cycle).

Checklist

  • The directory name matches the part of id after the / in plugin.toml exactly.
  • It ships plugin.toml, README.md, thumbnail.webp, and translations/en.json.
  • README.md follows the
    README template, documents
    every entry id and dependency, and includes exact panel IPC commands and launcher prefixes where applicable.
  • I created thumbnail.webp with the thumbnail generator.
  • version follows semver and is bumped in this PR; plugin_api is the oldest API level this plugin requires.
  • Every non-English translation in this PR uses a locale supported by Noctalia core, and I can read, write, and
    understand that language well enough to review and maintain it (no unreviewed machine/LLM translations).
  • I did not edit catalog.toml; CI generates it.
  • This PR touches exactly one plugin directory.

The thumbnail box is unchecked because it was composed manually (real panel screenshot on the card layout, 960×540 WebP); happy to redo it with the generator if required. This PR ships translations/en.json only.

Code review attestation

Plugins run as trusted, unsandboxed Luau in the user's session. Confirm:

  • The code is readable and not obfuscated, minified, or generated.
  • It does not download and execute remote code.
  • Every network call, filesystem write, and spawned process is something the description above accounts for.
  • I have the right to publish this code under the license declared in plugin.toml.

Relation to arch-updater: this plugin generalizes the background-update engine I proposed for yuuto/arch-updater in #384. If #384's feature part is not wanted there, this standalone plugin is the home for it; the bugfix commit of #384 stands on its own either way.

A note on language: the author doesn't speak English and used AI assistance for this text and the review conversation to come. The plugin itself is tested as described above.

🤖 Generated with Claude Code

@UmedjonBA
UmedjonBA force-pushed the linux-updater-plugin branch from 2580fb2 to 93a3972 Compare August 17, 2026 08:45
Multi-distro system updater grown out of arch-updater: background
updates with a live log tail and progress, an update-history strip
with rollback, panel-managed ignore lists, and one-click fixes for
missing system setup. The engine is distro-neutral; per-manager
backends (pacman, dnf, apt, zypper, xbps, PackageKit as the generic
fallback) declare capabilities the UI honors, and the right backend
is picked from /etc/os-release. Command layers of the non-Arch
backends are verified in containers against recorded fixtures; the
plugin is fully exercised on Arch.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@UmedjonBA
UmedjonBA force-pushed the linux-updater-plugin branch from 93a3972 to 8f50bb8 Compare August 17, 2026 09:22
@ItsLemmy

Copy link
Copy Markdown
Contributor
  1. blocking

The thumbnail generator was not used.

  1. blocking - linux-updater/backends/apt.luau:99

The background command separates repository refresh, ignore setup, and the upgrade with ;. An apt-get update or apt-mark hold failure
therefore does not stop the upgrade. The same failure-open behavior exists for xbps holds at linux-updater/backends/xbps.luau:72 and zypper
locks at linux-updater/backends/zypper.luau:82.

If hold or lock setup fails, packages the user explicitly ignored can still be upgraded. Gate the upgrade on successful refresh and ignore
setup, while retaining unconditional cleanup after the transaction.

  1. blocking - linux-updater/plugin.toml:9

The dependency metadata does not account for every external command spawned by the plugin. Examples include apt-mark and systemctl at
linux-updater/backends/apt.luau:59 and linux-updater/backends/apt.luau:131, rpm and head at linux-updater/backends/dnf.luau:58 and
linux-updater/backends/dnf.luau:110, pactree and wc at linux-updater/backends/pacman.luau:194 and
linux-updater/backends/pacman.luau:198, xbps-pkgdb at linux-updater/backends/xbps.luau:80, and install, grep, date, less, tee,
head, and rm throughout linux-updater/service.luau.

Repository policy requires external commands to be declared in dependencies and mentioned under README Requirements. Add the appropriate
command or package identifiers and document them.

  1. non-blocking - linux-updater/README.md:180

The Testing status says every backend parser runs against recorded fixtures in CI-able tests, but the PR contains no fixtures or parser
test harness. The repository validation only exercises manifest validation, not these parsers. Include the referenced test artifacts or
revise the testing claim so the advertised coverage is reproducible.

@ItsLemmy
ItsLemmy marked this pull request as draft August 17, 2026 12:35
@Reiling-Jeff

Reiling-Jeff commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Appreciate the transparency about the relation to #384, and generalizing the engine across distros is genuinely impressive work. Alongside the review that already blocked this on the dependency accounting, the fail-open hold/lock ordering, and the testing-status claim. I want to flag a separate point that those fixes won't resolve on their own.

#384 is still an open discussion, not a rejected one. The two structural points I raised there aren't arch-updater-specific, they're about the design of the background-update engine itself:

  • Terminal-driven updates need to stay a first-class, always-available option, not something that only appears after a silent background run has already failed. Some of us need to watch an AUR helper's (or in this case, any package manager's) interactive output as it happens, not just retry after the fact.
  • The stale-log timeout (RUN_STALE_LIMIT_S) can't be applied uniformly to interactive terminal runs - a user legitimately reviewing a diff/prompt for >30 minutes isn't a stuck process, and declaring it "failed" while the real process is still running risks a second concurrent run on the same log file.

Since this PR explicitly reuses that same engine, both concerns carry over directly; across six backends now instead of one. That's not a smaller surface than #384, it's a considerably larger one: every backend (pacman, dnf, apt, zypper, xbps, PackageKit) needs the same scrutiny this repo asks for trusted, unsandboxed code. readable, every side effect accounted for, no silent behavior changes for existing workflows.

So even once the already-flagged blocking items are fixed, I'd rather we settle the direction on #384 before this moves further. If "background-only, terminal demoted to fallback" isn't acceptable for arch-updater, that's the same answer for the shared engine here, it'll need addressing in every backend, not just the pacman one. If you're open to it, let's continue the design discussion on #384 and revisit this once that's resolved, so we're not reviewing the same unresolved design question twice.

@UmedjonBA

Copy link
Copy Markdown
Contributor Author

@Reiling-Jeff Thanks for taking the time on this, and for laying out why the two concerns carry over to every backend rather than just the pacman one.

I'm working on both sides: the blocking items here, and the design points you raised on #384. I agree they shouldn't be settled twice, so the answer that comes out of #384 is the one I'll apply across all backends here.

One practical note: I can't push the update right now. GitHub is having an ongoing incident today (Pull Requests, Actions, Git operations and the API are all degraded — https://www.githubstatus.com), so my pushes keep failing. As soon as it clears I'll send the update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants