diff --git a/docs/templates/ci-box/install.sh b/docs/templates/ci-box/install.sh index 4210676..ed73aa6 100755 --- a/docs/templates/ci-box/install.sh +++ b/docs/templates/ci-box/install.sh @@ -77,7 +77,12 @@ fetch_and_verify_sha256() { printf 'checksum verified (%s)\n' "$got" } -BIN=/usr/local/bin/forgejo-runner +# CIBOX_BIN is a TEST-ONLY override, in the same spirit as bootstrap-undo.sh's +# RIG_FORGEJO_RUNNER_DIR: the production default is the only path the mechanism +# ever uses, but test/cli.sh must be able to drive this script on a box that +# already has a real runner installed. Without it the early-exit below fires +# against the host and the checksum checks silently test nothing (#136). +BIN="${CIBOX_BIN:-/usr/local/bin/forgejo-runner}" if [ -x "$BIN" ]; then exit 0 diff --git a/test/cli.sh b/test/cli.sh index 4846778..6d4220f 100644 --- a/test/cli.sh +++ b/test/cli.sh @@ -156,8 +156,9 @@ UNDO_FIX="$(mktemp -d)" UNDO_BIN="$UNDO_FIX/bin" UNDO_MARKER="$UNDO_FIX/role" UNDO_RUNNER="$UNDO_FIX/runner" +UNDO_FJRUNNER="$UNDO_FIX/fjrunner" UNDO_CALLS="$UNDO_FIX/tailscale.calls" -mkdir -p "$UNDO_BIN" "$UNDO_RUNNER" +mkdir -p "$UNDO_BIN" "$UNDO_RUNNER" "$UNDO_FJRUNNER" cat > "$UNDO_BIN/tailscale" <<'SH' #!/usr/bin/env bash printf '%s\n' "$*" >> "$UNDO_CALLS" @@ -169,8 +170,13 @@ if [ "${1:-}" = -u ]; then printf '0\n'; else exec /usr/bin/id "$@"; fi SH chmod +x "$UNDO_BIN/tailscale" "$UNDO_BIN/id" undo() { + # RIG_FORGEJO_RUNNER_DIR is as load-bearing as RIG_RUNNER_DIR: without it + # bootstrap-undo.sh scans /home/*/forgejo-runner/.runner and the systemd unit + # on the REAL box, so these checks fail on any machine that has actually been + # drilled or used as a ci-box — which is the machine that matters (#136). env PATH="$UNDO_BIN:$PATH" UNDO_CALLS="$UNDO_CALLS" \ RIG_ROLE_MARKER="$UNDO_MARKER" RIG_RUNNER_DIR="$UNDO_RUNNER" \ + RIG_FORGEJO_RUNNER_DIR="$UNDO_FJRUNNER" \ "$ROOT/bin/rig" bootstrap --undo } undo_untouched() { @@ -196,7 +202,8 @@ rm -f "$UNDO_RUNNER/.runner" check "bootstrap --undo: failed logout is loud" \ 1 "role marker kept" env TAILSCALE_LOGOUT_FAIL=1 PATH="$UNDO_BIN:$PATH" \ UNDO_CALLS="$UNDO_CALLS" RIG_ROLE_MARKER="$UNDO_MARKER" \ - RIG_RUNNER_DIR="$UNDO_RUNNER" "$ROOT/bin/rig" bootstrap --undo + RIG_RUNNER_DIR="$UNDO_RUNNER" RIG_FORGEJO_RUNNER_DIR="$UNDO_FJRUNNER" \ + "$ROOT/bin/rig" bootstrap --undo check "bootstrap --undo: failed logout preserves the marker" 0 "" test -e "$UNDO_MARKER" : > "$UNDO_CALLS" check "bootstrap --undo: proven rig join succeeds" 0 "tailnet join removed" undo @@ -3276,10 +3283,45 @@ cibox_src_matches_install() { # shellcheck source=/dev/null . "$ROOT/commands/lib/templates.sh" template_parse_env "$dir/template.env" >/dev/null || return 2 - grep -qF "BIN=$TPL_CLI_SRC" "$dir/install.sh" + # BIN carries a test-only override (#136), so the agreement this asserts is + # with the DEFAULT — the only path the mechanism itself ever uses. + grep -qF "CIBOX_BIN:-$TPL_CLI_SRC" "$dir/install.sh" } check "ci-box: CLI_SRC is the path its install.sh installs" 0 "" cibox_src_matches_install +# codex/kimi on !137: the two wiring lines this change exists to add could be +# deleted tomorrow and the suite stayed 786/786 on any host without a real +# Forgejo runner — hermetic today, unpinned. #136's task list names the guard +# verbatim: "a check that fails if either group can see host state". +# +# These assert on the SUITE's own helpers, not the production knobs — the knobs +# are already covered above. What must go red is a deletion on the test side, +# because that is the regression that silently reintroduces host dependence. +undo_is_sealed() { + sed -n '/^undo() {/,/^}/p' "$0" | grep -q 'RIG_FORGEJO_RUNNER_DIR=' +} +cibox_run_is_sealed() { + sed -n '/^cibox_run() {/,/^}/p' "$0" | grep -q 'CIBOX_BIN=' +} +check "hermetic: undo() seals the Forgejo-runner host scan" 0 "" undo_is_sealed +check "hermetic: cibox_run() seals the real /usr/local/bin lookup" 0 "" cibox_run_is_sealed +# The failed-logout check builds its own env rather than calling undo(), so it +# needs the same seal — and it is the one that was missed first time round. +inline_undo_is_sealed() { + # Locate the REAL check by line number and read only its own block. Anchoring + # on a string and grepping the whole file cannot work here: any pattern this + # function searches for necessarily appears inside this function, so the + # search matches itself and can never fail. kimi caught the first version of + # that on !137; the anchored second version had the identical flaw for the + # identical reason. head -1 takes the real check (~:202), never this body. + local start end + start="$(grep -n 'failed logout is loud' "$0" | head -1 | cut -d: -f1)" + [ -n "$start" ] || return 1 + end=$((start + 5)) + sed -n "${start},${end}p" "$0" | grep -q RIG_FORGEJO_RUNNER_DIR +} +check "hermetic: the hand-rolled undo invocation is sealed too" 0 "" inline_undo_is_sealed + # Registration holds a credential, so it must NOT be in the definition: a # tenant install is creds-free by contract — box auto-runs it at mint, holding # nothing. Registration is the operator's separate, out-loud act. @@ -3460,7 +3502,7 @@ chmod +x "$CBSTUB/install" cibox_run() { # cibox_run [VAR=val ...] — the REAL template install.sh, stubbed rm -f "$CBW/installed" - env PATH="$CBSTUB:$PATH" \ + env PATH="$CBSTUB:$PATH" CIBOX_BIN="$CBW/bin-under-test" \ CB_REDIRECT=https://code.forgejo.org/forgejo/runner/releases/tag/v9.9.9 \ CB_PAYLOAD="$CBW/payload" "$@" bash "$CIBOX" }