fix(wake): #913 installer adoption gaps — _lib dep-check fail-loud + mosaic-wake.service systemd-search-path link+validate (#930)
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful

Co-authored-by: jason.woltje <jason@diversecanvas.com>
Co-committed-by: jason.woltje <jason@diversecanvas.com>
This commit was merged in pull request #930.
This commit is contained in:
2026-07-26 12:37:29 +00:00
committed by Mos
parent 347c1d57c1
commit 0ea41e848b
3 changed files with 232 additions and 6 deletions

View File

@@ -43,6 +43,12 @@ command -v jq >/dev/null 2>&1 || { echo "SKIP: jq not available" >&2; exit 0; }
TMP_ROOT="$(mktemp -d)"
trap 'rm -rf "$TMP_ROOT"' EXIT
# Isolation default: no group may ever touch the operator's REAL user systemd dir
# (~/.config/systemd/user). The (b/#913) search-path link step defaults there, so
# pin an isolated per-run dir here; groups that need their own re-export it.
export WAKE_SYSTEMD_USER_DIR="$TMP_ROOT/systemd-user-default"
mkdir -p "$WAKE_SYSTEMD_USER_DIR"
FAILFILE="$TMP_ROOT/failures"
: >"$FAILFILE"
pass=0
@@ -248,6 +254,67 @@ else
) && ok
fi
# ── (a #913) missing _lib/manifest.sh dependency — FAIL LOUD, not a bare source error ──
echo "== I9: dep-check — a host seed missing _lib/manifest.sh FAILS LOUD (names dep + remedy), not a bare source error =="
(
# Simulate an OLDER host seed that predates the shared manifest reader: copy the
# framework tree the installer needs, but OMIT tools/_lib/manifest.sh. Running the
# copied wake-install.sh reproduces the adoption gap on a not-yet-updated host.
FAKE="$(fresh i9-fw)"
mkdir -p "$FAKE/tools/wake" "$FAKE/tools/_lib" "$FAKE/systemd/user"
cp "$FRAMEWORK_ROOT/tools/wake/"* "$FAKE/tools/wake/" 2>/dev/null || true
# Copy _lib EXCEPT manifest.sh — the exact file older seeds lack.
for f in "$FRAMEWORK_ROOT/tools/_lib/"*; do
[ -e "$f" ] || continue
case "$(basename "$f")" in manifest.sh) continue ;; esac
cp "$f" "$FAKE/tools/_lib/" 2>/dev/null || true
done
cp "$FRAMEWORK_ROOT/systemd/user/mosaic-wake.service" "$FAKE/systemd/user/" 2>/dev/null || true
cp "$FRAMEWORK_ROOT/framework-manifest.txt" "$FAKE/" 2>/dev/null || true
[ ! -e "$FAKE/tools/_lib/manifest.sh" ] || fail_msg "I9: fixture setup — manifest.sh must be absent to simulate an older seed"
WI_FAKE="$FAKE/tools/wake/wake-install.sh"
TGT="$(fresh i9-target)"
out="$(WAKE_INSTALL_SOURCE="$FAKE" WAKE_INSTALL_TARGET="$TGT" bash "$WI_FAKE" install 2>&1)"; rc=$?
[ "$rc" -ne 0 ] || fail_msg "I9: install MUST fail when _lib/manifest.sh is missing (rc=$rc)"
echo "$out" | grep -qi 'manifest.sh' || fail_msg "I9: the failure must NAME the missing library (manifest.sh) [$out]"
echo "$out" | grep -qiE 'REMEDY|mosaic update|re-seed|framework install' \
|| fail_msg "I9: the failure must give an actionable REMEDY, not just an error [$out]"
# It must be a CLEAR fail-loud, NOT the obscure bare `source: No such file or directory`.
echo "$out" | grep -qi 'No such file or directory' \
&& fail_msg "I9: must not fail with a bare source error (obscure) [$out]"
# Positive control: with the helper present (real framework root) install succeeds.
TGT_OK="$(fresh i9-target-ok)"
WAKE_INSTALL_SOURCE="$FRAMEWORK_ROOT" WAKE_INSTALL_TARGET="$TGT_OK" \
bash "$WI" install >/dev/null 2>&1 || fail_msg "I9: with _lib/manifest.sh present the install must succeed"
) && ok
# ── (b #913) mosaic-wake.service lands IN the user systemd search path + validates ──
echo "== I10: systemd search-path — install links mosaic-wake.service into the search path; validate catches a miss; idempotent =="
(
TGT="$(fresh i10-target)"
UD="$(fresh i10-systemd)" # isolated stand-in for ~/.config/systemd/user
export WAKE_INSTALL_SOURCE="$FRAMEWORK_ROOT"
export WAKE_INSTALL_TARGET="$TGT"
export WAKE_SYSTEMD_USER_DIR="$UD"
bash "$WI" install >/dev/null 2>&1 || fail_msg "I10: install must succeed"
# (a) the unit is resolvable in the user systemd search path.
[ -e "$UD/mosaic-wake.service" ] || fail_msg "I10: mosaic-wake.service must be linked into the user systemd search path ($UD)"
out="$(bash "$WI" validate-systemd-path 2>&1)"; rc=$?
[ "$rc" -eq 0 ] || fail_msg "I10: post-install validate must confirm the unit resolves (rc=$rc) [$out]"
# (b) NEGATIVE CONTROL: not-in-search-path is CAUGHT (fail loud, names the miss).
rm -f "$UD/mosaic-wake.service"
out2="$(bash "$WI" validate-systemd-path 2>&1)"; rc2=$?
[ "$rc2" -ne 0 ] || fail_msg "I10: validate must FAIL when the unit is not in the search path (rc=$rc2) [$out2]"
echo "$out2" | grep -qi 'search path' || fail_msg "I10: validate failure must name the search-path miss [$out2]"
# (c) idempotent re-install: exactly one search-path entry, still resolvable.
bash "$WI" install >/dev/null 2>&1 || fail_msg "I10: re-run install must succeed"
n="$(find "$UD" -maxdepth 1 -name 'mosaic-wake.service' | grep -c .)"
[ "$n" -eq 1 ] || fail_msg "I10: re-install must not duplicate the search-path entry (found $n)"
bash "$WI" validate-systemd-path >/dev/null 2>&1 || fail_msg "I10: re-install must keep the unit resolvable"
) && ok
echo
if [ -s "$FAILFILE" ]; then
echo "wake install harness: FAILED ($(grep -c . "$FAILFILE") assertion(s))" >&2