Files
omarchycn/test/acceptance.d/system-test.sh
T
David Heinemeier HanssonandCodex XHigh 24c18df5b7 Temporarily remove automatic printer discovery
cups-browsed is the daemon that watches the network and creates print queues by itself. Hardening it took a root daemon with a predictable cache down to a confined service account, but a daemon that turns anything advertising itself on the network into a print queue is a lot of exposure for a convenience, so it comes out of the default install while that is reworked. Only the discovery half: CUPS itself stays and printing keeps working, with each printer added by hand in Print Settings.

The migration disables the unit before removing the package because that is the only order that works: pacman deletes the unit file but not the enable symlink, and once the unit is gone systemd can no longer resolve it by name to clean that up.

It then removes the queues discovery generated. cups-browsed keeps those when it stops, since KeepGeneratedQueuesOnShutdown defaults to Yes, and they route through its own implicitclass backend, which goes with the package, so they cannot print again. Idle ones go. A queue with jobs on it is left alone and named: implicitclass only needs cups-browsed to choose a destination, so a job already past that point finishes on its own, and deleting the queue would abort it. One printer's job does not hold up the removal. A printer added by hand has an ipp:// or usb:// device and is left where it is.

A queue whose jobs cannot be asked about is left alone rather than assumed idle, including one named so that lpstat would misread it -- "all" is its word for every destination, and a leading dash or a comma reads as another option or a list.

Where CUPS does not answer at all, or a queue will not delete, discovery is still stopped but the package stays and no marker is written. omarchy-migrate records a migration for the user as soon as it exits zero, so that is where the machine stays until someone removes the package by hand, and the message says so rather than implying a retry.

The queue list is read under LC_ALL=C because lpstat translates "device for", and captured rather than piped, so a cupsd it cannot reach is reported instead of reading like a machine with nothing to clean up.

It removes with plain pacman -R rather than omarchy-pkg-drop, which passes -n and would discard /etc/cups/cups-browsed.conf instead of keeping it as a .pacsave. A removal meant to be temporary should not delete the machine's copy of its own configuration. Without -s either, so it only ever removes the package it names: sweeping newly unneeded dependencies is nothing today, but it is not a promise a rolling dependency graph can keep.

Queue names come off the network, since cups-browsed names its queues after what the printer advertised. CUPS allows every printable character but space, tab, / and #, and lpstat and lpadmin take a destination as an option value, so a name with a leading dash or a comma is reported rather than passed to them and guessed at.

Migration state is per user, so a machine-wide marker records the one removal. Without it, an account whose first migration run came after someone deliberately reinstalled discovery would quietly take it back out again.

The install-time override for cups-browsed.conf now waits for cups-browsed rather than for CUPS. Guarding it on a file CUPS still ships would write a configuration file for a package nothing installed, and pacman would later land the package's own copy beside it as a .pacnew.

The hardened configuration stays in the tree. omarchy-settings still ships the cups-browsed.conf override, the sysusers account and the service drop-in, so they are what discovery returns onto.

Co-Authored-By: Codex XHigh <noreply@openai.com>
2026-08-29 17:13:11 +02:00

146 lines
6.1 KiB
Bash

#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
status=0
verify_core_packages() {
local package
local -a missing=()
while IFS= read -r package; do
[[ -z $package || $package == \#* ]] && continue
pacman -Q "$package" >/dev/null 2>&1 || missing+=("$package")
done <"$OMARCHY_PATH/install/omarchy-base.packages"
(( ${#missing[@]} == 0 )) || fail "all Omarchy core packages are installed" "missing packages: ${missing[*]}"
pass "all Omarchy core packages are installed (${#missing[@]} missing)"
}
verify_defaults() {
[[ $(omarchy-default-browser) == "chromium" ]] || fail "Chromium is the default browser"
pass "Chromium is the default browser"
[[ $(omarchy-default-terminal) == "foot" ]] || fail "Foot is the default terminal"
pass "Foot is the default terminal"
[[ $(omarchy-default-editor) == "nvim" ]] || fail "Neovim is the default editor"
pass "Neovim is the default editor"
[[ $(omarchy-theme-current) != "Unknown" ]] || fail "a current theme is configured"
pass "a current theme is configured"
[[ $(omarchy-theme-bg-current) != "Unknown" ]] || fail "a current background is configured"
pass "a current background is configured"
[[ -n $(omarchy-font-current) ]] || fail "a monospace font is configured"
pass "a monospace font is configured"
[[ $(xdg-mime query default x-scheme-handler/http) == "chromium.desktop" ]] || fail "HTTP MIME handling uses Chromium"
[[ $(xdg-mime query default inode/directory) == "org.gnome.Nautilus.desktop" ]] || fail "directory MIME handling uses Nautilus"
pass "desktop MIME handlers are configured"
}
verify_services() {
local unit
for unit in \
avahi-daemon.service cups.service docker.socket \
NetworkManager.service power-profiles-daemon.service sddm.service \
systemd-resolved.service ufw.service; do
systemctl is-enabled --quiet "$unit" || fail "core system services are enabled" "$unit is not enabled"
done
pass "core system services are enabled"
for unit in NetworkManager.service systemd-resolved.service ufw.service; do
systemctl is-active --quiet "$unit" || fail "critical system services are running" "$unit is not active"
done
pass "critical system services are running"
systemctl --user is-active --quiet pipewire.service pipewire-pulse.service wireplumber.service ||
fail "user audio services are running"
pass "user audio services are running"
}
verify_printing_security() {
local lpinfo_output
! pacman -Q cups-pdf >/dev/null 2>&1 || fail "CUPS-PDF is absent"
pass "the root CUPS-PDF backend is not installed"
# Automatic discovery is temporarily out of the default install: a daemon that
# turns anything advertising itself on the network into a print queue is more
# exposure than the convenience is worth while it is reworked. CUPS itself
# stays, so what a stock machine proves here is that printing runs and that
# the desktop user still cannot administer it without authenticating.
! pacman -Q cups-browsed >/dev/null 2>&1 || fail "automatic printer discovery is not installed"
! systemctl is-enabled --quiet cups-browsed.service 2>/dev/null ||
fail "no discovery service is enabled"
! systemctl is-active --quiet cups-browsed.service 2>/dev/null ||
fail "no discovery service is running"
pass "automatic printer discovery is absent from a stock install"
systemctl is-active --quiet cups.service || fail "CUPS is running"
if lpinfo_output=$(LC_ALL=C timeout 10 lpinfo -v </dev/null 2>&1); then
fail "the desktop user cannot administer CUPS without authentication"
elif [[ $lpinfo_output != *"Forbidden"* ]]; then
fail "CUPS explicitly denies unauthenticated desktop administration" "$lpinfo_output"
fi
pass "CUPS runs with passwordless desktop administration still denied"
}
verify_runtime_tools() {
# Docker access is intentionally NOT granted to the desktop user: the docker
# group is root-equivalent, so a rogue process running as the user could
# otherwise `docker run -v /:/host` its way to passwordless root. The daemon is
# still enabled (docker.socket, checked in verify_services) and reached through
# a polkit/sudo prompt; opting into sudoless Docker is a separate, warned step.
command -v docker >/dev/null 2>&1 || fail "Docker CLI is installed"
! id -nG | grep -qw docker || fail "desktop user must not be in the docker group"
# The group name being absent is not sufficient — a world-writable socket or an
# ACL would still hand the user the root daemon. Prove it is actually
# unreachable without elevation.
if timeout 10 docker info >/dev/null 2>&1; then
fail "desktop user must not reach the Docker daemon without elevation"
fi
pass "Docker is installed but unreachable by the desktop user without elevation"
nvim --headless '+qa' >/dev/null 2>&1 || fail "Neovim starts headlessly"
pass "Neovim starts headlessly"
timeout 10 fastfetch --pipe false >/dev/null 2>&1 || fail "Fastfetch can read system information"
pass "Fastfetch can read system information"
git --version >/dev/null || fail "Git is installed and runnable"
tmux -V >/dev/null || fail "Tmux is installed and runnable"
mise --version >/dev/null || fail "Mise is installed and runnable"
pass "core terminal tools are runnable"
}
verify_user_setup() {
local directory
for directory in DESKTOP DOCUMENTS DOWNLOAD PICTURES; do
[[ -d $(xdg-user-dir "$directory") ]] || fail "XDG user directories exist" "$directory is missing"
done
pass "XDG user directories exist"
[[ -e $HOME/.local/state/omarchy/current/theme ]] || fail "current theme state exists"
[[ -e $HOME/.local/state/omarchy/current/background ]] || fail "current background state exists"
[[ -s $HOME/.config/omarchy/shell.json ]] || fail "shell configuration exists"
jq empty "$HOME/.config/omarchy/shell.json" || fail "shell configuration is valid JSON"
pass "Omarchy user state and shell configuration exist"
}
for check in verify_core_packages verify_defaults verify_services verify_printing_security verify_runtime_tools verify_user_setup; do
if ! ("$check"); then
status=1
fi
done
exit $status