fix(wake): #913 installer adoption gaps — _lib dep-check fail-loud + mosaic-wake.service systemd-search-path link+validate
Some checks failed
ci/woodpecker/pr/ci Pipeline was canceled
Some checks failed
ci/woodpecker/pr/ci Pipeline was canceled
Two non-blocking wake-canon adoption gaps surfaced by the dragon-lin pilot in the A10 component installer (wake-install.sh). Both fixes are ADDITIVE per #869: framework-manifest.txt ownership, the install-ordering-guard, and the bash/TS manifest parity contract are all UNCHANGED. (a) DEP-CHECK — wake-install.sh sourced the shared framework-manifest reader (_lib/manifest.sh) unconditionally, so an older host seed that predates that helper aborted with a bare, obscure `source: No such file or directory`. It now checks the library FIRST and FAILS LOUD naming the missing file + the remedy (re-seed the framework, then retry --component wake). The dependency is genuinely required (Gate A cannot be skipped on an enforcement path), so it fails loud rather than degrading. (b) SYSTEMD SEARCH PATH — wi_install copies mosaic-wake.service under mosaic home (systemd/user/, framework-owned) but `systemctl --user` searches ~/.config/systemd/user/, so the unit was invisible and could not be enabled/started. install now LINKS the unit into the user systemd search path (symlink -> the mosaic-home SSOT copy, so upgrades propagate) and post-install VALIDATES it resolves (search-path entry exists, dereferences to a readable, well-formed unit; an opportunistic `systemctl --user cat` probe runs only behind a guard, since the installer may run where no user manager is live). Both steps are idempotent (a re-install neither duplicates nor breaks the link). #869 ADDITIVE: the link target lives OUTSIDE mosaic home, so it is not a framework-manifest path — ownership of the SSOT unit stays systemd/** in the single framework-manifest.txt authority; NO new owned path, NO second authority. Red-first: test-wake-install.sh gains I9 (a: missing _lib/manifest.sh fails loud naming dep + remedy, not a bare source error; positive control installs) and I10 (b: install links the unit into the search path + validate resolves; negative control catches a not-in-path unit; idempotent re-install). Both go RED against the prior code and GREEN after. Wake component manifest.txt bumped 0.6.6 -> 0.6.7 (VERSION metadata only). Closes #913 Part of #892 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0158NZqN2n2ymKFeJAZ4GUCb
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user