From 8ca045de4adb584b6640c5e92fa4189d03da4240 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 14:01:31 +0100 Subject: [PATCH 1/7] Polkit agent for compositor sessions; libvirt group for virt-manager virt-manager on niri/Noctalia failed with 'authentication unavailable: no polkit agent available to authenticate action org.libvirt.unix.manage' - bare compositors ship no polkit agent, unlike GNOME/KDE. Two fixes: - install_session_prereqs installs polkit-gnome and wires its agent .desktop into /etc/xdg/autostart (paths overridable for testing). - niri module optionally installs the qemu/libvirt stack, enables libvirtd, and adds the user to the libvirt group: members manage qemu:///system with no polkit prompt at all (the real fix; applies after re-login). --- lib/session.sh | 14 ++++++++++++++ modules/twm/niri.sh | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/lib/session.sh b/lib/session.sh index 72d6e60..610d4d6 100644 --- a/lib/session.sh +++ b/lib/session.sh @@ -85,7 +85,21 @@ install_session_prereqs() { install_packages \ xdg-desktop-portal \ polkit \ + polkit-gnome \ pipewire \ pipewire-pulseaudio \ wireplumber + + # A bare compositor (niri, MangoWC, Hyprland) has NO polkit agent: without + # one, anything needing privilege elevation (virt-manager's libvirt access, + # disks, network settings) fails with "no polkit agent available to + # authenticate". Autostart it for every graphical session via the XDG + # autostart dir the session runs. + local autostart="${XDG_AUTOSTART_DIR:-/etc/xdg/autostart}" + local desktop_src="${POLKIT_AGENT_DESKTOP:-/usr/share/applications/polkit-gnome-authentication-agent-1.desktop}" + if [[ -f "$desktop_src" ]] && [[ ! -e "$autostart/$(basename "$desktop_src")" ]]; then + info "Enabling polkit agent for compositor sessions..." + sudo mkdir -p "$autostart" + sudo ln -sf "$desktop_src" "$autostart/$(basename "$desktop_src")" + fi } diff --git a/modules/twm/niri.sh b/modules/twm/niri.sh index 5917489..35adbba 100755 --- a/modules/twm/niri.sh +++ b/modules/twm/niri.sh @@ -28,4 +28,14 @@ install_nerd_font JetBrainsMono install_packages sddm switch_display_manager sddm +# virt-manager/qemu:///system without password prompts: libvirt group + +# enabled daemon. Group membership applies to NEW sessions (re-login). +install_optional qemu-kvm libvirt virt-install virt-manager virt-viewer +if pkg_installed libvirt; then + info "Enabling libvirtd and adding $USER to the libvirt group..." + sudo systemctl enable --now libvirtd 2>/dev/null || true + sudo usermod -aG libvirt "$USER" || true + info "Group membership applies after re-login." +fi + ok "Niri setup complete. Log out and pick Niri in SDDM." -- 2.47.3 From eacceee29623f32b70e3e6a9b4937271e092e705 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 14:07:49 +0100 Subject: [PATCH 2/7] polkit agent: polkit-gnome is orphaned/EPEL-only on F44; use polkit-kde MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VM run failed: 'No match for argument: polkit-gnome'. polkit-gnome is orphaned in Fedora (EPEL9 only). polkit-kde 6.6.4 is in F44 and ships its agent's /etc/xdg/autostart .desktop itself, so the manual symlink wiring is gone too — installing the package is the whole fix. --- lib/session.sh | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/lib/session.sh b/lib/session.sh index 610d4d6..d6f4cde 100644 --- a/lib/session.sh +++ b/lib/session.sh @@ -82,24 +82,14 @@ write_x11_session() { # Common login-time plumbing every Wayland compositor wants on a bare install. install_session_prereqs() { + # polkit-kde ships the agent AND its /etc/xdg/autostart .desktop itself — + # no manual wiring needed. (polkit-gnome is orphaned, EPEL-only: not on F44, + # which is why the first attempt failed with "No match for argument".) install_packages \ xdg-desktop-portal \ polkit \ - polkit-gnome \ + polkit-kde \ pipewire \ pipewire-pulseaudio \ wireplumber - - # A bare compositor (niri, MangoWC, Hyprland) has NO polkit agent: without - # one, anything needing privilege elevation (virt-manager's libvirt access, - # disks, network settings) fails with "no polkit agent available to - # authenticate". Autostart it for every graphical session via the XDG - # autostart dir the session runs. - local autostart="${XDG_AUTOSTART_DIR:-/etc/xdg/autostart}" - local desktop_src="${POLKIT_AGENT_DESKTOP:-/usr/share/applications/polkit-gnome-authentication-agent-1.desktop}" - if [[ -f "$desktop_src" ]] && [[ ! -e "$autostart/$(basename "$desktop_src")" ]]; then - info "Enabling polkit agent for compositor sessions..." - sudo mkdir -p "$autostart" - sudo ln -sf "$desktop_src" "$autostart/$(basename "$desktop_src")" - fi } -- 2.47.3 From dbf75d1239899de59fa6df5a5182f05ca3a55995 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 14:19:26 +0100 Subject: [PATCH 3/7] qemu/libvirt belongs to the advanced menu, not the niri module A clean-snapshot run showed qemu/virt-manager installed without choosing it: PR #4 had embedded the install in the niri module. Removed from there (zero virt packages in a plain niri run, harness-verified) and moved into install_category_pkgs Virtualisation: picking qemu/virt-manager there now also enables libvirtd and adds the user to the libvirt group. --- modules/twm/niri.sh | 10 ---------- setup.sh | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/twm/niri.sh b/modules/twm/niri.sh index 35adbba..5917489 100755 --- a/modules/twm/niri.sh +++ b/modules/twm/niri.sh @@ -28,14 +28,4 @@ install_nerd_font JetBrainsMono install_packages sddm switch_display_manager sddm -# virt-manager/qemu:///system without password prompts: libvirt group + -# enabled daemon. Group membership applies to NEW sessions (re-login). -install_optional qemu-kvm libvirt virt-install virt-manager virt-viewer -if pkg_installed libvirt; then - info "Enabling libvirtd and adding $USER to the libvirt group..." - sudo systemctl enable --now libvirtd 2>/dev/null || true - sudo usermod -aG libvirt "$USER" || true - info "Group membership applies after re-login." -fi - ok "Niri setup complete. Log out and pick Niri in SDDM." diff --git a/setup.sh b/setup.sh index 4a99070..06bca69 100755 --- a/setup.sh +++ b/setup.sh @@ -533,6 +533,20 @@ run_advanced_menu() { install_category_pkgs() { local cat="$1"; shift case "$cat" in + Virtualisation) + # qemu:///system without password prompts: libvirt group + enabled + # daemon. Only when the picked packages actually use libvirt. + local wants_libvirt=false item + for item in "$@"; do + [[ "$item" == *libvirt* || "$item" == *virt-manager* || "$item" == *virt-install* ]] && wants_libvirt=true + done + if $wants_libvirt; then + info "Enabling libvirtd and adding $USER to the libvirt group..." + sudo systemctl enable --now libvirtd 2>/dev/null || true + sudo usermod -aG libvirt "$USER" || true + warn "libvirt group membership applies after re-login." + fi + ;; Browsers) local needs_chrome=false needs_brave=false item for item in "$@"; do -- 2.47.3 From 6a9941771a70e6d631647ab3b88aafa57072e2e6 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 14:37:41 +0100 Subject: [PATCH 4/7] polkit-kde agent never starts in niri: strip OnlyShowIn=KDE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The VM error persisted with polkit-kde installed: the package's autostart .desktop carries OnlyShowIn=KDE;, so XDG autostart (which niri honors via xdg-desktop-autostart.target) skips the agent in a niri session. Package present, agent never running — exactly the observed behavior. install_session_prereqs now rewrites the .desktop without the OnlyShowIn line in place (idempotent: only rewrites when the line is present). --- lib/session.sh | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/lib/session.sh b/lib/session.sh index d6f4cde..0ed7a7e 100644 --- a/lib/session.sh +++ b/lib/session.sh @@ -82,9 +82,11 @@ write_x11_session() { # Common login-time plumbing every Wayland compositor wants on a bare install. install_session_prereqs() { - # polkit-kde ships the agent AND its /etc/xdg/autostart .desktop itself — - # no manual wiring needed. (polkit-gnome is orphaned, EPEL-only: not on F44, - # which is why the first attempt failed with "No match for argument".) + # polkit-kde ships the agent (polkit-gnome is orphaned, EPEL-only). + # BUT its autostart file has OnlyShowIn=KDE; — XDG autostart SKIPS it in a + # niri/Hyprland/MangoWC session (VM-proven: package installed, error + # persisted). Copy the .desktop without the OnlyShowIn line so the agent + # starts in every session; the copy shadows the original by name. install_packages \ xdg-desktop-portal \ polkit \ @@ -92,4 +94,14 @@ install_session_prereqs() { pipewire \ pipewire-pulseaudio \ wireplumber + + local src="${POLKIT_AGENT_DESKTOP:-/etc/xdg/autostart/polkit-kde-authentication-agent-1.desktop}" + local dst="${XDG_AUTOSTART_DIR:-/etc/xdg/autostart}/polkit-kde-authentication-agent-1.desktop" + # src and dst are the same file in production — the condition to rewrite + # is "the file still contains OnlyShowIn", not "dst lacks it". + if [[ -f "$src" ]] && grep -q "^OnlyShowIn=" "$src" 2>/dev/null; then + info "Making polkit agent session-agnostic (stripping OnlyShowIn=KDE)..." + sudo mkdir -p "$(dirname "$dst")" + grep -v '^OnlyShowIn=' "$src" | sudo tee "$dst" >/dev/null + fi } -- 2.47.3 From 0814c5bde711a63371b66728ceb61519e820a30d Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 14:51:44 +0100 Subject: [PATCH 5/7] polkit agent via user systemd unit, not XDG autostart MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second VM failure: Fedora's polkit-kde .desktop carries X-systemd-skip=true (and OnlyShowIn on some versions), so niri's xdg-desktop-autostart.target skips the agent regardless — package installed, agent dead, same error. Stop fighting .desktop semantics: install a polkit-agent.service USER unit (WantedBy=graphical-session.target, which niri/Hyprland/Mango all bring up) with the Fedora kf6 binary path, pre-linked into graphical-session.target.wants. Idempotent on both file and symlink. --- lib/session.sh | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/session.sh b/lib/session.sh index 0ed7a7e..8454b57 100644 --- a/lib/session.sh +++ b/lib/session.sh @@ -83,10 +83,12 @@ write_x11_session() { # Common login-time plumbing every Wayland compositor wants on a bare install. install_session_prereqs() { # polkit-kde ships the agent (polkit-gnome is orphaned, EPEL-only). - # BUT its autostart file has OnlyShowIn=KDE; — XDG autostart SKIPS it in a - # niri/Hyprland/MangoWC session (VM-proven: package installed, error - # persisted). Copy the .desktop without the OnlyShowIn line so the agent - # starts in every session; the copy shadows the original by name. + # BUT Fedora's autostart .desktop carries X-systemd-skip=true (and a + # OnlyShowIn on some versions): niri starts apps via systemd's + # xdg-desktop-autostart.target, which honors those flags -> agent never + # starts in a niri session (VM-proven twice). Fighting .desktop semantics + # is fragile, so we ship our own user unit bound to + # graphical-session.target, which niri/Hyprland/MangoWC all bring up. install_packages \ xdg-desktop-portal \ polkit \ @@ -95,13 +97,32 @@ install_session_prereqs() { pipewire-pulseaudio \ wireplumber - local src="${POLKIT_AGENT_DESKTOP:-/etc/xdg/autostart/polkit-kde-authentication-agent-1.desktop}" - local dst="${XDG_AUTOSTART_DIR:-/etc/xdg/autostart}/polkit-kde-authentication-agent-1.desktop" - # src and dst are the same file in production — the condition to rewrite - # is "the file still contains OnlyShowIn", not "dst lacks it". - if [[ -f "$src" ]] && grep -q "^OnlyShowIn=" "$src" 2>/dev/null; then - info "Making polkit agent session-agnostic (stripping OnlyShowIn=KDE)..." - sudo mkdir -p "$(dirname "$dst")" - grep -v '^OnlyShowIn=' "$src" | sudo tee "$dst" >/dev/null + local unit_dir="/etc/systemd/user" + if [[ ! -f "$unit_dir/polkit-agent.service" ]]; then + info "Installing polkit-agent user unit (compositor-safe)..." + sudo mkdir -p "$unit_dir" + sudo tee "$unit_dir/polkit-agent.service" >/dev/null <<'UNIT' +[Unit] +Description=PolicyKit Authentication Agent (for bare compositors) +PartOf=graphical-session.target + +[Service] +# polkit-kde's binary on Fedora (kf6 path). Restart in case the agent dies +# before the session settles. +ExecStart=/usr/libexec/kf6/polkit-kde-authentication-agent-1 +Restart=on-failure +RestartSec=2 + +[Install] +WantedBy=graphical-session.target +UNIT + fi + + # Enable per-user: preset-all would also do, but be explicit. This is a + # global unit dir; each user links it at first login via the preset. + if [[ ! -f /etc/systemd/user/graphical-session.target.wants/polkit-agent.service ]]; then + sudo mkdir -p /etc/systemd/user/graphical-session.target.wants + sudo ln -sf ../polkit-agent.service \ + /etc/systemd/user/graphical-session.target.wants/polkit-agent.service fi } -- 2.47.3 From e99c60a0737751a42f993124c3817b10890aea63 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 15:14:22 +0100 Subject: [PATCH 6/7] Session prereqs: libvirt group membership when libvirt is installed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The error CHANGED on the VM: 'no polkit agent' -> 'access denied by policy' — the agent unit works; polkit now denies because the user is not in the libvirt group (fresh run without picking QEMU from the menu, or no re-login after the pick). install_session_prereqs now adds the user to the libvirt group whenever libvirt is installed (idempotent via id -nG check), decoupled from the advanced-menu choice. Applies after re-login. --- lib/session.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/session.sh b/lib/session.sh index 8454b57..421b2d2 100644 --- a/lib/session.sh +++ b/lib/session.sh @@ -125,4 +125,15 @@ UNIT sudo ln -sf ../polkit-agent.service \ /etc/systemd/user/graphical-session.target.wants/polkit-agent.service fi + + # libvirt group: members manage qemu:///system without a polkit prompt. + # Without this, virt-manager dies on "access denied by policy" even with + # a working agent (VM-proven). Idempotent; applies after re-login. + if pkg_installed libvirt; then + local real_user="${SUDO_USER:-$USER}" + if ! id -nG "$real_user" 2>/dev/null | grep -qw libvirt; then + info "Adding $real_user to the libvirt group (re-login to apply)..." + sudo usermod -aG libvirt "$real_user" + fi + fi } -- 2.47.3 From c552b30112a3c127e788cec57932189812dad683 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 15:19:08 +0100 Subject: [PATCH 7/7] Advanced menu libvirt wiring: use SUDO_USER fallback like session prereqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit usermod used $USER directly; under sudo $USER can be root. All other user-scoped calls already use ${SUDO_USER:-$USER} — aligned. No hardcoded usernames anywhere in the repo (verified by grep; only the dotfiles repo URL, which is overridable via DOTFILES_REPO). --- setup.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 06bca69..8437f72 100755 --- a/setup.sh +++ b/setup.sh @@ -541,9 +541,10 @@ install_category_pkgs() { [[ "$item" == *libvirt* || "$item" == *virt-manager* || "$item" == *virt-install* ]] && wants_libvirt=true done if $wants_libvirt; then - info "Enabling libvirtd and adding $USER to the libvirt group..." + local real_user="${SUDO_USER:-$USER}" + info "Enabling libvirtd and adding $real_user to the libvirt group..." sudo systemctl enable --now libvirtd 2>/dev/null || true - sudo usermod -aG libvirt "$USER" || true + sudo usermod -aG libvirt "$real_user" || true warn "libvirt group membership applies after re-login." fi ;; -- 2.47.3