Some Wonder Ink lesson links are a download rather than a page: the server sends the PDF as an attachment, so there is nothing for a tab to show and the file lands on disk. In this room that is the same as it not arriving. There is no file manager, no application launcher and no downloads bar, on purpose, and a teacher is not going to open a maintenance terminal to print a Christmas tree. 0.2.1 downloaded the worksheet, said so in a notification, and left it somewhere unreachable. Found on the canary machine with a real lesson. So a download that completes, and really is a PDF, opens as another tab. Rendering is the engine's own viewer — the same PDFium Chrome uses — so there is no second rendering library and no separate application. That was verified against a completed local file rather than assumed from the remote case: PdfViewerEnabled was already on, and a local file: URL is a different question. WHAT IS REFUSED. A completed download is not a usable worksheet. HTML that a server called .pdf, an empty file, an unreadable one: all refused on the first five bytes rather than on the name, because the alternative is a blank tab that says nothing. An interrupted download says it did not finish and to try again — and that needed stateChanged rather than isFinishedChanged, which is not emitted for an interrupted download at all. Connected to the obvious signal, this said nothing whatsoever about a worksheet that failed to arrive, which is the one case a teacher most needs told about. Measured. WHICH LOCAL FILES. Exactly the ones the window opened itself. Opening a worksheet adds one resolved path to a list, and the page's acceptNavigationRequest refuses every file: URL that is not on it. Chromium already refuses to let a remote page reach file: — verified with a link, a location.href, and a link to a worksheet that had been downloaded but not opened by the shell, all refused — so this is the second lock rather than the only one. It is here because the first one is somebody else's. Two Qt defaults are turned off beside it: LocalContentCanAccessFileUrls, which is on by default and would let a local document read other local documents, and its remote counterpart. Print to File is removed from the print dialog, because choosing it enables a path with a "..." button, which is a file chooser, in a room whose whole design is that there is no file chooser. The PDF viewer's own menus were audited: two-page view, annotations, present, properties, and nothing that opens or saves anywhere a teacher chooses. AND THE BROWSER IS NOT INVOLVED. The handler is connected to Wonder Ink's own profile, so it only ever sees downloads that started in a Wonder Ink tab. Nothing inspects a filename, nothing watches a directory, and Chrome — a separate application with a separate profile — is untouched: classroom-browser and the Chrome policies are byte-identical to stable 0.2.0. Worksheets go to ~/Downloads/Wonder Ink, which is tidiness and mostly the security argument: it is the only place one can come from. Only PDFs. Anything else downloads, says so, and is still unreachable; that limitation and two small follow-ups are written down rather than built, and nothing downloaded is ever executed. Measured from the package on a rebooted machine, and again on one upgraded from the published 0.2.1: the click-to-tab workflow end to end, a name with spaces and brackets, multi-page navigation, printing to Elmer, closing the worksheet without closing the lesson, and the four refusals. 120 convergence checks and 24 worksheet checks pass on both. Cookies are still session-only, the Present-view autoplay fix still works, fullscreen still comes back maximised, and there is still no address bar and no new-tab button. Co-Authored-By: Claude Opus 5 <[email protected]>
71 lines
3.0 KiB
Bash
Executable File
71 lines
3.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# The whole thing, from nothing, the way a classroom would get it: a fresh
|
|
# machine, the built .deb, and the session started from what it installed.
|
|
# No developer install script anywhere in the path.
|
|
set -euo pipefail
|
|
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
LAB="$ROOT/tools/lab/lab"
|
|
DEB="${1:-$(ls -t "$ROOT"/dist/ekklesia-classroom_*_amd64.deb | head -1)}"
|
|
NAME="${LAB_NAME:-classroom-v2-lab}"
|
|
|
|
echo "installing $(basename "$DEB")"
|
|
"$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'
|
|
|
|
docker exec "$NAME" sh -c "
|
|
DEBIAN_FRONTEND=noninteractive dpkg -i '/srv/classroom/${DEB#$ROOT/}' \
|
|
>/dev/null 2>&1 || 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"
|
|
|
|
state=$(docker exec "$NAME" dpkg-query -W -f='${db:Status-Abbrev}' ekklesia-classroom)
|
|
echo "package state: $state"
|
|
|
|
# And then the machine is restarted, the way a room takes an update: a
|
|
# new PID 1, a new user manager, SDDM autologging the classroom in. The
|
|
# session environment, the logind drop-in and the user services are all
|
|
# things that are only read at boot.
|
|
"$LAB" reboot
|
|
|
|
"$LAB" session >/dev/null
|
|
sleep 8
|
|
|
|
check() { printf ' %-46s %s\n' "$1" "$2"; }
|
|
env_dirs=$(docker exec -u classroom -e XDG_RUNTIME_DIR=/run/user/1000 \
|
|
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus "$NAME" \
|
|
systemctl --user show-environment 2>/dev/null | grep '^XDG_CONFIG_DIRS=' || true)
|
|
|
|
check "package installed" "$state"
|
|
check "session config path" "${env_dirs:-NOT SET}"
|
|
check "plasmashell" "$(docker exec "$NAME" pgrep -c -x plasmashell || echo 0)"
|
|
check "kwin" "$(docker exec "$NAME" pgrep -c -x kwin_wayland || echo 0)"
|
|
check "panel applets" "$(docker exec "$NAME" sh -c 'grep -c "^plugin=" /home/classroom/.config/plasma-org.kde.plasma.desktop-appletsrc' || echo 0)"
|
|
check "panel restart policy" "$(docker exec -u classroom -e XDG_RUNTIME_DIR=/run/user/1000 \
|
|
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus "$NAME" \
|
|
systemctl --user show plasma-plasmashell.service -p Restart --value)"
|
|
check "audio policy" "$(docker exec -u classroom -e XDG_RUNTIME_DIR=/run/user/1000 \
|
|
-e DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus "$NAME" \
|
|
systemctl --user is-active ekklesia-classroom-audio.service || true)"
|
|
|
|
# The same list of properties the upgraded machine has to satisfy. A
|
|
# fresh install and a migrated one are supposed to be indistinguishable
|
|
# from a teacher's chair, so they are asked the same questions.
|
|
"$ROOT/tools/lab/converged-check" ${CHECK_ARGS:-}
|
|
converged=$?
|
|
|
|
# And the one part of Wonder Ink that is a behaviour rather than a
|
|
# property: which local files it will open. Run against the command the
|
|
# package installed, not against the repository.
|
|
echo
|
|
echo "Wonder Ink, worksheets and local files"
|
|
"$ROOT/tools/lab/pdf-check"
|
|
pdf=$?
|
|
|
|
exit $(( converged | pdf ))
|