deploy.sh no longer starts units a live session already runs
`sync` on a box with a live session on it was unsafe in two independent ways, found by preflighting the run rather than performing it. Refs #44. **`enable --now` would have armed a screen lock mid-session.** The unit loop started every `systemd-user/` unit whose `ExecStart` resolves. `swayidle-lock.service` on blankpad is `enabled`/`inactive` — nothing started it, no swayidle process exists, `autostart.kdl` does not launch one — so one `deploy.sh` would have begun blanking and locking the monitors while the operator was mid-sentence. `live-sync.service` is `linked`, driven by its timer, and `--now` forces a heartbeat commit at an arbitrary moment. A unit is now started only when systemd reports it as nothing-yet (`""`/`disabled`), which is precisely a fresh box; anything already installed is merely `enable`d. The state has to come from the **printed state**: `is-enabled` exits 1 for `linked` exactly as for `disabled`, so exit status cannot distinguish "installed, timer-driven" from "never installed" — the first version of this fix got that wrong and the test caught it. **`--check` output was being read as more than it can mean.** It prints `RELINK` for every path the `zz` tier carries, even when the live link already points at the override (`rules.kdl`, `keybinds.kdl`, `misc.kdl`, `autostart.kdl`, `.zshrc` all did on blankpad), because the walk visits the base package first and reports the intermediate owner change. The sentence committed in #43 — RELINK noise is "the sound of a stale override waiting" — is too strong and is corrected: the line proves a pending change only when `readlink` shows the live target is not already the `zz-$HOST` file, and `actions=0` is the honest summary. The stale-override hazard #43 removed was and is real; the signal for it is the target, not the line. **The dconf dump carried six of its 24 keys from another box**, none of them preferences: a Firefox file-chooser `last-folder-path` of `/home/dank/Downloads`, a nautilus `window-state` section, and `picture-uri`/`picture-uri-dark` pointing at `file:///home/dank/.config/background`. The last five showed no conflict because blankpad's live tree *already* held those `/home/dank` values — an earlier deploy wrote them here — and a foreign value that agrees with live is invisible to any diff while still being wrong. They are dropped; `picture-options='zoom'` stays, because it is a preference. The live wallpaper URIs are cleared on the box as part of landing this (niri draws the wallpaper, noctalia owns it, nothing reads a dead path). `tests/deploy.bats` grows by four, over a stub `systemctl` — the real one on this box is exactly what must not be invoked from a test. Red before: an already-`enabled` unit and a `linked` unit both get `--now`. Green after, including the two directions that keep the change honest: a `disabled` unit is still `enable --now`'d so a fresh box comes up, and a unit whose `ExecStart` is absent here is never touched at all. Verification: `bats tests/` 70/70, `kb-lint.sh omp-docs` 0, `kb-coverage.py` 0. The dump now reconciles against live state with **0 conflicts and no `/home/` values in 18 keys**, proven by key-by-key comparison rather than `diff` — `dconf load` writes only the keys present, so a diff overstates the damage one way and hides it the other.
This commit is contained in:
1 parent
7523ca5c19
commit
ecc089c6ef
5 files changed
+143
-20
No files matched your search
@@ -23,6 +23,24 @@ setup() {
|
||||
export HOME="$TEST_TMP/home"
|
||||
mkdir -p "$HOME"
|
||||
export DEPLOY_REPO="$REPO" DEPLOY_HOST=box
|
||||
|
||||
# systemctl stub: records every call and answers is-enabled from a file. The real
|
||||
# systemctl must never run here — on this box it would start a screen lock.
|
||||
mkdir -p "$TEST_TMP/bin"
|
||||
export STUB_LOG="$TEST_TMP/systemctl.log" UNIT_STATE="$TEST_TMP/unit-state"
|
||||
: > "$STUB_LOG"
|
||||
cat > "$TEST_TMP/bin/systemctl" <<'STUB'
|
||||
#!/usr/bin/env bash
|
||||
echo "systemctl $*" >> "$STUB_LOG"
|
||||
if [ "$2" = is-enabled ]; then
|
||||
state="$(cat "$UNIT_STATE" 2>/dev/null || echo disabled)"
|
||||
printf '%s\n' "$state"
|
||||
case "$state" in disabled | "") exit 1 ;; *) exit 0 ;; esac
|
||||
fi
|
||||
exit 0
|
||||
STUB
|
||||
chmod +x "$TEST_TMP/bin/systemctl"
|
||||
export PATH="$TEST_TMP/bin:$PATH"
|
||||
}
|
||||
|
||||
teardown() { rm -rf "$TEST_TMP"; }
|
||||
@@ -32,6 +50,13 @@ repo_file() { mkdir -p "$(dirname "$REPO/dotfiles/$1")"; printf '%s\n' "$2" > "$
|
||||
# live_file <absolute path under $HOME> <content>
|
||||
live_file() { mkdir -p "$(dirname "$1")"; printf '%s\n' "$2" > "$1"; }
|
||||
|
||||
# systemd_unit <name> <ExecStart> — a unit in the systemd-user package
|
||||
systemd_unit() {
|
||||
mkdir -p "$REPO/dotfiles/systemd-user/.config/systemd/user"
|
||||
printf '[Unit]\nDescription=%s\n[Service]\nExecStart=%s\n[Install]\nWantedBy=default.target\n' "$1" "$2" \
|
||||
> "$REPO/dotfiles/systemd-user/.config/systemd/user/$1"
|
||||
}
|
||||
|
||||
@test "generated theme output is never adopted into a symlink" {
|
||||
repo_file "ghostty/.config/ghostty/themes/noctalia" 'background = "#f43841"'
|
||||
live_file "$HOME/.config/ghostty/themes/noctalia" 'background = "#f43841"'
|
||||
@@ -74,3 +99,40 @@ live_file() { mkdir -p "$(dirname "$1")"; printf '%s\n' "$2" > "$1"; }
|
||||
grep -q 'theme = "tokyo-night"' "$HOME/.config/ghostty/config.ghostty"
|
||||
[ ! -d "$REPO/.quarantine" ]
|
||||
}
|
||||
|
||||
@test "a unit already enabled is enabled but not started" {
|
||||
systemd_unit lock.service /bin/sh
|
||||
printf 'enabled\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"not started"* ]]
|
||||
grep -q 'systemctl --user enable lock.service' "$STUB_LOG"
|
||||
! grep -q -- '--now' "$STUB_LOG"
|
||||
}
|
||||
|
||||
@test "a linked unit is not started either" {
|
||||
# `is-enabled` exits 1 for a linked unit, exactly as it does for a disabled one, so the
|
||||
# printed state is the signal — exit status cannot tell them apart.
|
||||
systemd_unit timer-driven.service /bin/sh
|
||||
printf 'linked\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
! grep -q -- '--now' "$STUB_LOG"
|
||||
}
|
||||
|
||||
@test "a disabled unit is enabled and started, so a fresh box still comes up" {
|
||||
systemd_unit fresh.service /bin/sh
|
||||
printf 'disabled\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
grep -q 'systemctl --user enable --now fresh.service' "$STUB_LOG"
|
||||
}
|
||||
|
||||
@test "a unit whose ExecStart is absent here stays inert" {
|
||||
systemd_unit otherbox.service /nonexistent/daemon
|
||||
printf 'disabled\n' > "$UNIT_STATE"
|
||||
run "$REPO/scripts/deploy.sh"
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"SKIP"*otherbox.service* ]]
|
||||
! grep -q enable "$STUB_LOG"
|
||||
}
|
||||
Reference in new issue
Block a user