#!/usr/bin/env bash # Contract for server/bin/reset-tailscale-clone.sh. Runs anywhere: the guard # prefixes every path with GUARD_ROOT, so the branch that removes # /var/lib/tailscale can be exercised against a scratch tree rather than only # on a machine booted from a snapshot. set -uo pipefail HERE=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) GUARD="$HERE/../server/bin/reset-tailscale-clone.sh" [[ -x "$GUARD" ]] || { echo "error: $GUARD is not executable" >&2; exit 1; } pass=0; fail=0 ok() { printf 'ok %s\n' "$1"; pass=$((pass+1)); } bad() { printf 'FAIL %s\n %s\n' "$1" "$2"; fail=$((fail+1)); } # run — builds a scratch root, runs the # guard against it, and prints " ". run() { local recorded=$1 live=$2 root rc root=$(mktemp -d) || return 1 mkdir -p "$root/var/lib/flit" "$root/var/lib/tailscale" "$root/sys/class/dmi/id" printf 'nodekey\n' >"$root/var/lib/tailscale/tailscaled.state" printf 'dev.tail.ts.net\n' >"$root/var/lib/flit/tailscale-up" [[ "$recorded" == '-' ]] || printf '%s\n' "$recorded" >"$root/var/lib/flit/server-serial" [[ "$live" == '-' ]] || printf '%s\n' "$live" >"$root/sys/class/dmi/id/product_serial" GUARD_ROOT="$root" FLIT_NAME=flit "$GUARD" >/dev/null 2>&1 rc=$? printf '%s %s %s\n' \ "$([[ -d "$root/var/lib/tailscale" ]] && echo present || echo gone)" \ "$([[ -f "$root/var/lib/flit/tailscale-up" ]] && echo present || echo gone)" \ "$rc" rm -rf "$root" } # An ordinary reboot of the imaged server itself must keep its identity — # a guard that wiped on every boot would deauthenticate production nightly. r=$(run 158986157 158986157) [[ "$r" == 'present present 0' ]] \ && ok 'serial unchanged: identity and marker survive' || bad 'serial unchanged' "got: $r" # The defect this exists for: a server created from the golden snapshot boots # holding the imaged server's node key and displaces it on the tailnet. r=$(run 158986157 999999999) [[ "$r" == 'gone gone 0' ]] \ && ok 'serial changed: identity and marker removed' || bad 'serial changed' "got: $r" # Absence of a recorded serial is not evidence of a clone: it is also every # boot before 30-tailscale.sh has run once. r=$(run - 158986157) [[ "$r" == 'present present 0' ]] \ && ok 'no recorded serial: nothing removed' || bad 'no recorded serial' "got: $r" # Unreadable DMI must not be read as "different". The guard runs before the # network exists; it cannot afford to guess. r=$(run 158986157 -) [[ "$r" == 'present present 0' ]] \ && ok 'serial unreadable: nothing removed' || bad 'serial unreadable' "got: $r" # Ordered Before=tailscaled.service, so a non-zero exit would fail the boot # transaction that starts tailscaled. Every path above must exit 0. printf '%d passed, %d failed\n' "$pass" "$fail" [[ $fail -eq 0 ]]