From 32003bf8dd638f2cfa589ecacc258e1db9bf6029 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20Bene=C5=A1?= Date: Fri, 7 Aug 2026 14:09:15 +0200 Subject: [PATCH] An installer that moved a channel nobody asked it to The channel lives in two places -- lembas.env, which the page reads, and the systemd unit, which the button obeys -- and a re-run keeps the env file while rewriting the unit. Defaulting to stable therefore meant a re-run for some unrelated reason silently moved one half and not the other, leaving a host whose page named edge and whose button deployed stable. That mismatch already had an alert. An installer that causes the thing it detects is the wrong end to be detecting it from, so it defaults to what the host already follows. Parsed rather than sourced: that file holds the secret key. Found by running it. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 6 ++++++ deploy/install.sh | 18 +++++++++++++++++- tests/test_updates.py | 24 ++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8e713..7e5a24e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,12 @@ and did not. ownership boundary through a field that looks like a tag. - Fixed: a `"` typed into the share panel's search box silently stopped every checkbox in the panel from doing anything. +- Fixed: **re-running the installer moved the update channel to `stable`** even + on a host following `edge`. The channel lives in two places — the environment + file the page reads and the systemd unit the button obeys — and a re-run kept + the first while rewriting the second, so an install for some unrelated reason + left the page naming one channel and the button deploying another. It now + defaults to what the host already follows. ## 0.9.11 diff --git a/deploy/install.sh b/deploy/install.sh index a02cd53..bb62287 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -30,7 +30,23 @@ BRANCH="${LEMBAS_BRANCH:-main}" # (the branch tip). Stable by default, because a branch tip is not a release -- # following one means deploying whatever was pushed five minutes ago, which is # right for whoever builds this and wrong for whoever runs it. -CHANNEL="${LEMBAS_CHANNEL:-stable}" +# On a **re-run**, default to what this host already follows rather than to +# `stable`. The channel lives in two places -- `lembas.env`, which the page +# reads, and the systemd unit, which the button obeys -- and a re-run keeps the +# env file ("keeping it, and its secret key") while rewriting the unit. So a +# re-run to fix something unrelated silently moved one half and not the other, +# and left the host with a page naming one channel and a button deploying +# another. That mismatch has an alert of its own; an installer that *causes* it +# is the wrong end to be detecting it from. +# +# Parsed, not sourced -- `lembas.env` holds the secret key, and there is no +# reason for this to have it in a variable. +_installed_channel="" +if [[ -f "$PREFIX/lembas.env" ]]; then + _installed_channel=$(sed -n 's/^LEMBAS_UPDATE_CHANNEL=\([a-z]\{1,16\}\)$/\1/p' \ + "$PREFIX/lembas.env" | tail -1) +fi +CHANNEL="${LEMBAS_CHANNEL:-${_installed_channel:-stable}}" # Whether to install the units that let the web interface update this host. # Off, and off on a re-run that does not ask for it: it grants anybody who can # administer the web UI the ability to deploy the branch, as root. See the diff --git a/tests/test_updates.py b/tests/test_updates.py index ce88436..ada2057 100644 --- a/tests/test_updates.py +++ b/tests/test_updates.py @@ -483,3 +483,27 @@ def test_the_container_runs_as_a_real_account(): assert "USER lembas" in dockerfile assert dockerfile.index("USER lembas") > dockerfile.index("COPY . .") + + +def test_a_reinstall_does_not_move_the_channel_by_itself(): + """The channel lives in two places -- `lembas.env`, which the page reads, + and the systemd unit, which the button obeys -- and a re-run keeps the env + file while rewriting the unit. Defaulting to `stable` therefore meant a + re-run for some unrelated reason silently moved one half and not the other, + leaving a host whose page named one channel and whose button deployed + another. + + That mismatch has an alert of its own, and an installer that *causes* the + thing it detects is the wrong end to be detecting it from. + """ + from pathlib import Path + + import lembas + + root = Path(lembas.__file__).resolve().parents[2] + install = (root / "deploy/install.sh").read_text() + + assert "LEMBAS_UPDATE_CHANNEL=" in install, "it has to read the installed value" + assert 'CHANNEL="${LEMBAS_CHANNEL:-${_installed_channel:-stable}}"' in install + # Parsed rather than sourced: that file holds the secret key. + assert ". $PREFIX/lembas.env" not in install