A real room upgraded to 0.1.45 and came up as stock Debian Plasma with the old Waybar across the top, mako still catching notifications, and a lock screen on an account that has no password. The cause was one line, and it was in the lab: the harness handed the session under test XDG_CONFIG_DIRS by hand, so every result it had ever produced was a result about a machine somebody had already configured. On a machine SDDM starts the session through PAM, PAM does not read /etc/environment.d, and Debian's own plasma-workspace env.sh then set the variable from scratch — so the classroom's settings directory was not in the cascade at all. No layout, no lock policy, no Kiosk restrictions. The settings now arrive the way Plasma delivers them, through a file in /etc/xdg/plasma-workspace/env. Around that: the look and feel is immutable on its own key so a stale profile cannot answer for it; the palette is composed into the package, because naming a colour scheme does not produce one and the dark bar had been coming from a technician's hand; the desktop reset converges another desktop's appearance state and keeps the room's own; and classroom-migrate stops, deactivates and masks the old shell, including the D-Bus activation that brought mako back while the panel was down — found only by killing the panel on a migrated machine. device.conf loses COMPOSITOR and comes off the hyprland channel, which would otherwise have handed the room the experiment back. The lab stops flattering the package: it restarts the machine, lets SDDM actually autologin, and asks a fresh install and a machine upgraded from the Hyprland package the same sixty questions. Both answer identically, twice, and the panel still comes back from eight SIGKILLs. Co-Authored-By: Claude Opus 5 <[email protected]>
237 lines
8.2 KiB
Bash
Executable File
237 lines
8.2 KiB
Bash
Executable File
#!/bin/bash
|
|
# The upgrade that failed, reproduced on purpose.
|
|
#
|
|
# A real classroom does not arrive new, and the clean-install test was
|
|
# passing on a machine that had never been anything else. This builds a
|
|
# machine that has: the Hyprland experiment package actually installed,
|
|
# with sway, waybar and mako behind it, a Waybar activated through
|
|
# graphical-session, an autostart entry, a device.conf still asking for a
|
|
# compositor that is gone, and a Plasma profile belonging to a different
|
|
# desktop. Then it installs the classroom package over the top and asks
|
|
# whether the room converged.
|
|
#
|
|
# tools/lab/dirty-upgrade [NEW.deb] [OLD.deb]
|
|
# CHECK_ARGS=--restart tools/lab/dirty-upgrade ask twice, either side
|
|
# of a logout
|
|
#
|
|
# The container is restarted between the install and the session, because
|
|
# a room takes its upgrade and reboots.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
LAB="$ROOT/tools/lab/lab"
|
|
NAME="${LAB_NAME:-classroom-v2-lab}"
|
|
|
|
NEW="${1:-$(ls -t "$ROOT"/dist/ekklesia-classroom_*_amd64.deb | grep -v '~' | head -1)}"
|
|
OLD="${2:-$ROOT/dist/ekklesia-classroom_0.1.45~hypr3_amd64.deb}"
|
|
|
|
step() { printf '\n\033[1m== %s\033[0m\n' "$1"; }
|
|
|
|
step "a fresh machine"
|
|
"$LAB" up >/dev/null
|
|
|
|
docker exec "$NAME" sh -c '
|
|
printf "#!/bin/sh\nexit 101\n" > /usr/sbin/policy-rc.d
|
|
chmod +x /usr/sbin/policy-rc.d
|
|
apt-get update -qq >/dev/null 2>&1
|
|
# The old package schedules a provisioning run that would go to
|
|
# backports for Hyprland. The lab is not testing that.
|
|
systemctl mask ekklesia-classroom-provision.service >/dev/null 2>&1'
|
|
|
|
step "the old classroom: $(basename "$OLD")"
|
|
docker exec "$NAME" sh -c "
|
|
DEBIAN_FRONTEND=noninteractive dpkg -i '/srv/classroom/${OLD#$ROOT/}' >/dev/null 2>&1
|
|
DEBIAN_FRONTEND=noninteractive apt-get -y -qq -f install >/dev/null 2>&1
|
|
DEBIAN_FRONTEND=noninteractive dpkg --configure ekklesia-classroom >/dev/null 2>&1
|
|
true" || true
|
|
docker exec "$NAME" dpkg-query -W -f=' installed: ${Version}\n' ekklesia-classroom
|
|
|
|
step "and everything a used machine accumulates"
|
|
docker exec -i "$NAME" bash <<'DIRT'
|
|
set -e
|
|
|
|
# Waybar and mako, activated the way the real room had them. Neither
|
|
# package ships a unit in trixie, so the units themselves are part of what
|
|
# somebody added — and one of the three activation directories is the one
|
|
# the broken room actually used.
|
|
for unit in waybar mako; do
|
|
cat > "/etc/systemd/user/$unit.service" <<UNIT
|
|
[Unit]
|
|
Description=$unit (left over from the old classroom shell)
|
|
PartOf=graphical-session.target
|
|
After=graphical-session.target
|
|
|
|
[Service]
|
|
ExecStart=/usr/bin/$unit
|
|
Restart=on-failure
|
|
|
|
[Install]
|
|
WantedBy=graphical-session.target
|
|
UNIT
|
|
done
|
|
|
|
for dir in /etc/systemd/user /etc/xdg/systemd/user \
|
|
/home/classroom/.config/systemd/user; do
|
|
mkdir -p "$dir/graphical-session.target.wants"
|
|
ln -sf /etc/systemd/user/waybar.service \
|
|
"$dir/graphical-session.target.wants/waybar.service"
|
|
ln -sf /etc/systemd/user/mako.service \
|
|
"$dir/graphical-session.target.wants/mako.service"
|
|
done
|
|
|
|
# An autostart entry as well, for a bar that is started two ways.
|
|
mkdir -p /home/classroom/.config/autostart
|
|
cat > /home/classroom/.config/autostart/waybar.desktop <<'ENTRY'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=Waybar
|
|
Exec=waybar
|
|
ENTRY
|
|
|
|
# The room still asking for a compositor that is gone, with a broker
|
|
# password in the same file to prove the migration does not rewrite it.
|
|
sed -i 's/^CHANNEL=.*/CHANNEL=hyprland/' /etc/ekklesia-classroom/device.conf
|
|
{
|
|
echo "COMPOSITOR=hyprland"
|
|
echo "HYPR_APPEARANCE=visual"
|
|
} >> /etc/ekklesia-classroom/device.conf
|
|
sed -i 's/^MQTT_HOST=.*/MQTT_HOST=broker.example.invalid/' /etc/ekklesia-classroom/device.conf
|
|
sed -i 's/^MQTT_PASSWORD=.*/MQTT_PASSWORD=keep-me-exactly/' /etc/ekklesia-classroom/device.conf
|
|
|
|
# A Plasma profile from a different desktop: someone else's palette, in
|
|
# both of the places that outrank the package.
|
|
mkdir -p /home/classroom/.config/kdedefaults
|
|
cat > /home/classroom/.config/kdedefaults/kdeglobals <<'KDE'
|
|
[General]
|
|
ColorScheme=BreezeLight
|
|
|
|
[Icons]
|
|
Theme=breeze
|
|
|
|
[KDE]
|
|
LookAndFeelPackage=org.kde.breeze.desktop
|
|
KDE
|
|
cat > /home/classroom/.config/kdeglobals <<'KDE'
|
|
[General]
|
|
ColorScheme=BreezeLight
|
|
|
|
[Colors:Window]
|
|
BackgroundNormal=239,240,241
|
|
ForegroundNormal=35,38,41
|
|
|
|
[KDE]
|
|
LookAndFeelPackage=org.kde.breeze.desktop
|
|
KDE
|
|
|
|
# And a stock panel, already built, of the kind the broken upgrade made.
|
|
cat > /home/classroom/.config/plasma-org.kde.plasma.desktop-appletsrc <<'PANEL'
|
|
[Containments][1]
|
|
plugin=org.kde.plasma.folder
|
|
|
|
[Containments][2]
|
|
plugin=org.kde.panel
|
|
|
|
[Containments][2][Applets][3]
|
|
plugin=org.kde.plasma.kickoff
|
|
|
|
[Containments][2][Applets][4]
|
|
plugin=org.kde.plasma.pager
|
|
|
|
[Containments][2][Applets][5]
|
|
plugin=org.kde.plasma.icontasks
|
|
|
|
[Containments][2][Applets][5][Configuration][General]
|
|
launchers=applications:systemsettings.desktop,applications:org.kde.discover.desktop,preferred://browser
|
|
|
|
[Containments][2][Applets][6]
|
|
plugin=org.kde.plasma.systemtray
|
|
PANEL
|
|
|
|
# A user-level power profile that would suspend the room.
|
|
cat > /home/classroom/.config/powermanagementprofilesrc <<'POWER'
|
|
[AC][SuspendSession]
|
|
idleTime=1800000
|
|
suspendType=1
|
|
|
|
[AC][DPMSControl]
|
|
idleTime=600
|
|
POWER
|
|
|
|
chown -R classroom:classroom /home/classroom/.config
|
|
echo " dirt in place"
|
|
DIRT
|
|
|
|
step "the new classroom: $(basename "$NEW")"
|
|
docker exec "$NAME" sh -c '
|
|
systemctl unmask ekklesia-classroom-provision.service >/dev/null 2>&1 || true'
|
|
docker exec "$NAME" sh -c "
|
|
DEBIAN_FRONTEND=noninteractive dpkg -i '/srv/classroom/${NEW#$ROOT/}' 2>&1 \
|
|
| grep -E '^\[classroom-migrate\]' || true
|
|
DEBIAN_FRONTEND=noninteractive apt-get -y -qq -f install >/dev/null 2>&1
|
|
DEBIAN_FRONTEND=noninteractive dpkg --configure ekklesia-classroom >/dev/null 2>&1
|
|
rm -f /usr/sbin/policy-rc.d
|
|
true" || true
|
|
docker exec "$NAME" dpkg-query -W -f=' installed: ${Version} ${db:Status-Abbrev}\n' ekklesia-classroom
|
|
|
|
step "and the room reboots"
|
|
"$LAB" reboot
|
|
|
|
step "the session"
|
|
"$LAB" session >/dev/null
|
|
sleep 6
|
|
|
|
step "did it converge?"
|
|
converged=0
|
|
"$ROOT/tools/lab/converged-check" ${CHECK_ARGS:-} || converged=1
|
|
|
|
step "and again, installed a second time over itself"
|
|
# An update that changes nothing must change nothing. The migration runs
|
|
# again here, over a machine that is already converged.
|
|
docker exec "$NAME" sh -c "
|
|
DEBIAN_FRONTEND=noninteractive dpkg -i '/srv/classroom/${NEW#$ROOT/}' >/dev/null 2>&1
|
|
true" || true
|
|
before=$(docker exec "$NAME" sh -c 'cat /etc/ekklesia-classroom/device.conf | sha256sum')
|
|
"$LAB" plasma-down >/dev/null
|
|
"$LAB" plasma-up >/dev/null
|
|
sleep 4
|
|
after=$(docker exec "$NAME" sh -c 'cat /etc/ekklesia-classroom/device.conf | sha256sum')
|
|
[[ "$before" == "$after" ]] \
|
|
&& echo " device.conf unchanged by the second install" \
|
|
|| { echo " DEVICE.CONF CHANGED ON REINSTALL"; converged=1; }
|
|
"$ROOT/tools/lab/converged-check" || converged=1
|
|
|
|
step "and the room's own theme choice survives a logout"
|
|
# Deleting the look and feel defaults every login was measured to make
|
|
# Plasma re-apply the look and feel and throw the room's chosen palette
|
|
# away with it. This is the check that stops that coming back.
|
|
# With the session's own cascade. plasma-apply-colorscheme writes the
|
|
# chosen name into ~/.config/kdedefaults, which is in XDG_CONFIG_DIRS for
|
|
# a session and not for a bare command, so asking without it reports
|
|
# nothing and means nothing.
|
|
theme() {
|
|
local dirs
|
|
dirs=$(docker exec "$NAME" bash -c 'p=$(pgrep -x plasmashell | head -1); tr "\0" "\n" < /proc/$p/environ | grep "^XDG_CONFIG_DIRS=" | cut -d= -f2-')
|
|
docker exec -u classroom -e XDG_RUNTIME_DIR=/run/user/1000 \
|
|
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus \
|
|
-e WAYLAND_DISPLAY=wayland-0 -e "XDG_CONFIG_DIRS=$dirs" "$NAME" \
|
|
/usr/local/bin/classroom-theme "$1" 2>/dev/null | tail -1
|
|
}
|
|
theme light >/dev/null
|
|
"$LAB" plasma-down >/dev/null
|
|
"$LAB" plasma-up >/dev/null
|
|
sleep 4
|
|
chosen=$(theme show)
|
|
if [[ "$chosen" == EkklesiaLight ]]; then
|
|
echo " light survived the logout"
|
|
else
|
|
echo " THE ROOM'S THEME CHOICE WAS LOST: $chosen"
|
|
converged=1
|
|
fi
|
|
theme dark >/dev/null
|
|
echo " back to $(theme show)"
|
|
|
|
step "and it still recovers"
|
|
"$ROOT/tools/lab/recovery-check" || converged=1
|
|
|
|
exit "$converged"
|