0f96019714ce9517adf170caa8d0f76547b015d7
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
30d2d99230 |
fix: a hidden Wi-Fi survives the hand-over, and a failed one leaves an owner
The prayer-room laptop's 0.2.5 migration built a NetworkManager connection, could not bring it up, rolled back, and left the wireless adapter belonging to nobody. Four separate defects, each of which would have been enough on its own. THE HIDDEN FLAG WAS THROWN AWAY. The stanza said wpa-scan-ssid 1 and the parser read it — into options, where the only accessor ignored it. The profile came out with 802-11-wireless.hidden: no, and NetworkManager will not associate with an SSID it has not seen in a scan. A hidden one is never in a scan. credentials() returned a pair; profile() now returns the whole network, and add() writes the flag in BOTH directions rather than only when true, because a default that happens to be right is not the same as an answer. IFDOWN RAN AFTER THE STANZA WAS COMMENTED OUT. ifupdown reads /etc/network/interfaces to find out how to bring an interface down; with the stanza gone it says "Ignoring unknown interface" and does nothing. So ifupdown's own wpa_supplicant and DHCP client were still holding the radio when NetworkManager was asked to associate with it, which is a fight NetworkManager loses. Down first, while the file still says how; rewrite the file second. THE ROLLBACK LEFT THE ADAPTER UNMANAGED. restore() ended with `device set <dev> managed no`, which is right while ifupdown can bring the interface up and is a radio nobody owns when ifup has failed too. That is the state the laptop was found in, and why `nmcli device set wlp2s0 managed yes` was a manual recovery step. It now escalates: if ifupdown cannot get the network back either, the interface goes to NetworkManager rather than to neither, and it says so loudly. A '#' IN A PASSWORD WAS SILENTLY TRUNCATED. The parser cut every line at its first '#'. interfaces(5) is explicit that only whole-line comments exist, so a pre-shared key containing one became a prefix of itself — and the only symptom is an association failing exactly the way a wrong password fails. Two smaller ones went with them. The rollback un-comments its own marked lines in place rather than copying the backup over the whole file, so a wired change made between the migration and the rollback is no longer silently reverted. And nmcli terse output is split on its own escaping rules under LC_ALL=C, so a network whose name contains a colon cannot make a successful migration look like a failed one. --adopt now also refuses a network it cannot recreate before taking the interface away from ifupdown to find out, and reports an unmanaged-devices line in NetworkManager's configuration, which survives the stanza going away. Verified against a real NetworkManager 1.52.1: the keyfile carries hidden=true, the SSID keeps its space, and a psk containing '#' is intact, at 0600 root:root with no connection.permissions. The new test drives the whole hand-over against stubbed tools and asserts the ordering, the rollback and the managed state — including that a machine already migrated, which is the laptop, is not migrated again. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
fe08363534 |
fix: a machine with no ifupdown configuration is not an error
The release validator caught it: in a container there is no /etc/network/interfaces at all, and a missing file was being treated as a read failure, so --check printed nothing and said nothing was wrong rather than saying there was nothing to do. A machine with no ifupdown configuration is the ordinary case for a fresh install, and the answer is simply that this command has no work. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
35e3bdcbbd |
fix: give a Wi-Fi the installer set up to NetworkManager, by hand
The Bible study laptop had working internet and a panel that said there
was no connection. Both were true, and one thing caused both.
Measured on the machine:
nmcli device status wlp2s0 wifi unmanaged
nmcli networking connectivity none while curl fetched fine
nmcli device wifi list nothing, with the radio enabled
/run/network/ifstate wlp2s0=wlp2s0
a second wpa_supplicant, -i wlp2s0, with no -c config file
dhcpcd holding the lease
/etc/network/interfaces 0600 root:root
Debian's installer had been given the Wi-Fi, so it wrote it into
/etc/network/interfaces and ifupdown brings it up. NetworkManager ships
with plugins=ifupdown and [ifupdown] managed=false, so an interface named
in that file is UNMANAGED — which is why the applet had nothing to report
and why scanning found nothing. An unmanaged device is not a radio
NetworkManager will scan with. rfkill was ruled out separately: the radio
is enabled.
managed=false stays; it is what keeps a tower's static Ethernet where an
administrator put it. Only a wireless interface is moved.
classroom-wifi grows --check, --adopt (with --dry-run) and --rollback.
--adopt builds a NetworkManager SYSTEM connection from the SSID and key
already in that root-only file, so the password never leaves the machine
and never reaches a human or a log; it lands in a 0600 root file with
psk-flags=0, the same shape 0.2.4 established, and the polkit rules
protecting it are untouched.
Deliberately NOT run by the upgrade. It moves a machine's only link
between managers and the machine it could strand is a laptop in a locked
room, so classroom-migrate only looks and prints what it found. An
administrator runs it over SSH while watching.
Two things this learned from testing the rollback rather than from
reading the code, and both are why the rollback is worth testing:
* ifdown was missing in the lab, subprocess raised FileNotFoundError,
and the exception escaped AFTER the stanza was commented out. No
rollback ran. Every hand-over command now goes through a runner that
tolerates a missing binary, and the whole hand-over is inside a guard
that restores the file on any failure at all.
* it now refuses to start when ifdown or ifup are absent, because
without them the hand-over would be a one-way door.
Success also requires the interface itself to be carrying the connection,
not merely that the machine is online — a machine with a second link
would otherwise report a failed migration as a success.
Verified in the lab against real NetworkManager with a real ifupdown
file: --check and --dry-run leave it byte-identical, a failed --adopt
rolls back byte-identically, and --rollback restores a half-migrated
machine byte-identically and exits 0. The one thing no lab can do is the
hand-over succeeding, which needs the laptop's radio.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
a31fa75d55 |
fix: the bar keeps its order when an application opens
On the laptop the browser jumped behind the disc player the moment it was
opened. 0.2.4 caused that, and the cause is two lines of the stock applet:
main.qml:153 hideActivatedLaunchers: tasks.iconsOnly || ...
main.qml:155 launchInPlace: tasks.iconsOnly && sortingStrategy === 1
For an icons-only bar the first is always true — a launcher is hidden the
instant its application starts — and the second is what puts the running
window back where the launcher was. It only does that at sortingStrategy
1. 0.2.4 set it to 0 to stop teachers dragging the icons about, so the
launcher vanished and the window was appended after the others.
Reproduced in the lab with a real Chrome window before changing anything,
and the bar read off the screen: Wonder Ink, the player, then the
browser. With 1 it is Wonder Ink, the browser, the player, through
opening, a second window, another application opening beside it, and
every close.
The launcher identity was suspected and cleared: only one browser button
appears, because google-chrome.desktop already carries Chrome's own file
name and StartupWMClass for exactly this reason.
THE COST, AND IT IS REAL. Manual sorting is also the only mode in which
MouseHandler.qml accepts a reordering drop, so a teacher who knows to drag
can rearrange the bar again. There is no value that gives both and no
Kiosk key that separates them. classroom-desktop-reset already rebuilds
the bar from the package at every login, so a drag never outlives the
session. docs/testing.md states the trade rather than burying it, and the
configuration escape is written down there too as still open.
tools/lab/order-check is the test this needed and did not have. 0.2.4
passed a full set of configuration assertions while the bar did something
else, so this one opens real application windows and reads the panel
strip as pixels — there is no image library in the lab, so it captures
PPM and names each icon by colour. Six checks, all of them behaviour.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
bf7b959893 |
feat: the room may use the church Wi-Fi and may not read its password
These are shared computers in rooms full of people, and in a stock Plasma
desktop "use the network" and "read the network's password" are much
closer together than they look.
Measured on Debian 13 with NetworkManager 1.52 and Plasma 6.3:
* org.freedesktop.NetworkManager.settings.modify.own ships as "yes" for
an active session — no prompt, no administrator. It covers any
connection whose connection.permissions names that user, and a Wi-Fi
network added from the desktop is created exactly that way. So a
password a teacher types in is readable by the next person to sit
down.
* the applet offers "Show Network's QR Code" on every saved wireless
connection, and the QR code contains the pre-shared key.
* that action, and the "Configure…" beside it, are contextual actions in
ConnectionItem.qml and do NOT consult
authorizeControlModule("kcm_networkmanagement"). The Kiosk key gates
the toolbar button only. Hiding buttons was never going to be the
answer.
Every one of those paths ends at NetworkManager's GetSecrets, so that is
where this is answered. A polkit rule refuses settings.modify.own,
settings.modify.system, both wifi.share actions and the machine-wide
settings, for the classroom user by name.
Deliberately NOT refused: network-control, wifi.scan and the
enable/disable actions. None returns a secret, and they are what
connecting and seeing a network are made of. Automatic reconnection does
not go through polkit at all — NetworkManager does it as root — so nothing
here can stop the room coming back on the network after a reboot, which is
the property that matters most on a Sunday.
An administrator's account and root are untouched, and the override route
is the same one the sleep rule has.
classroom-wifi is the other half, and it is a requirement rather than a
convenience: it provisions the church Wi-Fi as a SYSTEM connection, with
no connection.permissions, psk-flags=0 and a 0600 root:root file. A
connection the machine owns is one nobody in the room can read. Verified
against real NetworkManager in the lab — the classroom account gets
"Permission denied" on the file, "--" from nmcli and "Insufficient
privileges" from GetSecrets, while autoconnect stays on.
There is deliberately no teacher-facing join dialog. Anything that lets
the room add a connection lets the room own it, and an owned connection is
a readable one; docs/networking.md says so rather than leaving it to be
rediscovered.
The rule is plain JavaScript, so the test evaluates it with polkit's
objects stubbed and asserts both halves: which actions come back NO, and
which are left alone. What it cannot test is the last mile — polkit
resolves a subject through logind and a container has no graphical seat
session, so every check there is denied for reasons unrelated to this
rule. That one is a physical check, and it is written down as one.
Co-Authored-By: Claude Opus 5 <[email protected]>
|