#!/bin/sh # Self-contained test for the Linux package scripts (preinst/postinst/postrm). # # Simulates an old HashiCorp Boundary layout in a temporary directory (fake # /etc/boundary.d, a "boundary" user, a running boundary.service) using the # THRESHOLD_PKG_ROOT prefix and fake id/useradd/userdel/systemctl commands. # Needs neither root nor systemd. # # Usage: .release/linux/test/test-package-scripts.sh set -eu HERE=$(cd "$(dirname "$0")" && pwd) PKG_DIR=$(cd "$HERE/.." && pwd) PREINST="$PKG_DIR/preinst" POSTINST="$PKG_DIR/postinst" POSTRM="$PKG_DIR/postrm" SH=${TEST_SH:-sh} WORK=$(mktemp -d) trap 'rm -rf "$WORK"' EXIT INT TERM FAILS=0 PASSES=0 pass() { PASSES=$((PASSES + 1)); } fail() { FAILS=$((FAILS + 1)) echo "FAIL: $*" >&2 } assert() { # assert DESC cmd... _d=$1 shift if "$@"; then pass; else fail "$_d"; fi } refute() { # refute DESC cmd... _d=$1 shift if "$@"; then fail "$_d"; else pass; fi } file_has() { grep -qF -- "$2" "$1"; } file_eq() { [ "$(cat "$1")" = "$2" ]; } # --- fake commands ------------------------------------------------------------ BIN="$WORK/bin" mkdir -p "$BIN" cat >"$BIN/id" <<'EOF' #!/bin/sh # fake id: id -u NAME | id -gn NAME ; users in $FAKE/users as name:group mode=$1 name=$2 line=$(grep "^$name:" "$FAKE/users" 2>/dev/null) || exit 1 case "$mode" in -u) echo 1000 ;; -gn) echo "${line#*:}" ;; esac EOF cat >"$BIN/useradd" <<'EOF' #!/bin/sh for a in "$@"; do name=$a; done echo "$name:$name" >>"$FAKE/users" echo "useradd $name" >>"$FAKE/calls" EOF cat >"$BIN/userdel" <<'EOF' #!/bin/sh grep -v "^$1:" "$FAKE/users" >"$FAKE/users.new" || true mv "$FAKE/users.new" "$FAKE/users" echo "userdel $1" >>"$FAKE/calls" EOF cat >"$BIN/systemctl" <<'EOF' #!/bin/sh # fake systemctl backed by files in $FAKE (state) and $THRESHOLD_PKG_ROOT resolve() { if [ -L "$THRESHOLD_PKG_ROOT/etc/systemd/system/$1" ]; then _t=$(readlink "$THRESHOLD_PKG_ROOT/etc/systemd/system/$1") echo "${_t##*/}" else echo "$1" fi } echo "systemctl $*" >>"$FAKE/calls" case "$1" in show) u=$(resolve "$4") case "$3" in Id) echo "Id=$u" ;; LoadState) if [ -f "$THRESHOLD_PKG_ROOT/usr/lib/systemd/system/$u" ]; then echo "LoadState=loaded" else echo "LoadState=not-found" fi ;; esac ;; is-enabled) u=$(resolve "$3"); [ -e "$FAKE/enabled/$u" ] ;; is-active) u=$(resolve "$3"); [ -e "$FAKE/active/$u" ] ;; enable) u=$(resolve "$2"); : >"$FAKE/enabled/$u" ;; disable) u=$(resolve "$2"); rm -f "$FAKE/enabled/$u" ;; start) u=$(resolve "$2") [ -e "$FAKE/fail_start/$u" ] && exit 1 : >"$FAKE/active/$u" ;; stop) u=$(resolve "$2"); rm -f "$FAKE/active/$u" ;; daemon-reload) : ;; esac exit $? EOF chmod 755 "$BIN"/* # --- scenario helpers ----------------------------------------------------------- new_root() { # new_root NAME -> sets ROOT and FAKE, creates skeleton ROOT="$WORK/$1/root" FAKE="$WORK/$1/fake" mkdir -p "$ROOT/etc" "$ROOT/usr/bin" "$ROOT/usr/lib/systemd/system" \ "$ROOT/etc/systemd/system" "$ROOT/run/systemd/system" \ "$FAKE/enabled" "$FAKE/active" "$FAKE/fail_start" : >"$FAKE/users" : >"$FAKE/calls" # What the package itself would have unpacked. : >"$ROOT/usr/bin/threshold" echo "[Service]" >"$ROOT/usr/lib/systemd/system/threshold.service" export THRESHOLD_PKG_ROOT="$ROOT" FAKE } run_script() { # run_script SCRIPT [ARGS...] _s=$1 shift PATH="$BIN:$PATH" "$SH" "$_s" "$@" >"$WORK/out.log" 2>&1 } add_legacy_layout() { mkdir -p "$ROOT/etc/boundary.d/tls" echo 'controller { name = "mine" }' >"$ROOT/etc/boundary.d/boundary.hcl" echo 'BOUNDARY_POSTGRES_URL=secret' >"$ROOT/etc/boundary.d/boundary.env" echo 'worker { name = "w" }' >"$ROOT/etc/boundary.d/worker.hcl" echo 'KEY' >"$ROOT/etc/boundary.d/tls/server.key" chmod 600 "$ROOT/etc/boundary.d/tls/server.key" echo "boundary:boundary" >>"$FAKE/users" echo "[Service]" >"$ROOT/usr/lib/systemd/system/boundary.service" } # ============================================================================== echo "== scenario 1: upgrade from Boundary (running + enabled), existing threshold.hcl" new_root s1 add_legacy_layout : >"$FAKE/enabled/boundary.service" : >"$FAKE/active/boundary.service" mkdir -p "$ROOT/etc/threshold.d" echo 'USER-OWNED' >"$ROOT/etc/threshold.d/threshold.hcl" assert "preinst succeeds" run_script "$PREINST" install assert "threshold.hcl NOT clobbered" file_eq "$ROOT/etc/threshold.d/threshold.hcl" "USER-OWNED" assert "boundary.env migrated to threshold.env" file_has "$ROOT/etc/threshold.d/threshold.env" "BOUNDARY_POSTGRES_URL=secret" assert "worker.hcl copied under same name" file_has "$ROOT/etc/threshold.d/worker.hcl" 'name = "w"' assert "subdirectory copied" file_has "$ROOT/etc/threshold.d/tls/server.key" "KEY" assert "originals kept: boundary.hcl" test -f "$ROOT/etc/boundary.d/boundary.hcl" assert "originals kept: boundary.env" test -f "$ROOT/etc/boundary.d/boundary.env" refute "no duplicate threshold user created" grep -q '^useradd' "$FAKE/calls" refute "no boundary.hcl name left in threshold.d" test -e "$ROOT/etc/threshold.d/boundary.hcl" assert "postinst succeeds" run_script "$POSTINST" configure assert "drop-in written" file_has "$ROOT/etc/systemd/system/threshold.service.d/10-legacy-boundary-user.conf" "User=boundary" assert "drop-in group" file_has "$ROOT/etc/systemd/system/threshold.service.d/10-legacy-boundary-user.conf" "Group=boundary" assert "boundary command symlink" test -L "$ROOT/usr/bin/boundary" assert "boundary symlink target is threshold" test "$(readlink "$ROOT/usr/bin/boundary")" = "threshold" assert "boundary.service alias symlink" test -L "$ROOT/etc/systemd/system/boundary.service" assert "legacy service stopped" test ! -e "$FAKE/active/boundary.service" assert "threshold enabled" test -e "$FAKE/enabled/threshold.service" assert "threshold started" test -e "$FAKE/active/threshold.service" refute "legacy unit not left enabled as itself" grep -q 'enable boundary.service' "$FAKE/calls" : >"$FAKE/calls" assert "postinst idempotent (2nd run)" run_script "$POSTINST" configure refute "2nd run does not stop/start anything" grep -qE 'systemctl (stop|start|enable|disable)' "$FAKE/calls" assert "preinst idempotent (2nd run)" run_script "$PREINST" upgrade assert "threshold.hcl still not clobbered" file_eq "$ROOT/etc/threshold.d/threshold.hcl" "USER-OWNED" echo "== scenario 1b: postrm remove/purge cleans only generated pieces" assert "postrm remove" run_script "$POSTRM" remove refute "boundary command symlink removed" test -L "$ROOT/usr/bin/boundary" refute "alias symlink removed" test -L "$ROOT/etc/systemd/system/boundary.service" refute "drop-in removed" test -e "$ROOT/etc/systemd/system/threshold.service.d/10-legacy-boundary-user.conf" assert "user config untouched after remove" test -f "$ROOT/etc/boundary.d/boundary.hcl" assert "migrated config untouched after remove" test -f "$ROOT/etc/threshold.d/threshold.env" assert "postrm purge (no threshold user: no userdel)" run_script "$POSTRM" purge refute "boundary user never deleted" grep -q 'userdel boundary' "$FAKE/calls" # ============================================================================== echo "== scenario 2: fresh install, no Boundary" new_root s2 assert "preinst succeeds" run_script "$PREINST" install assert "threshold user created" grep -q '^useradd threshold' "$FAKE/calls" refute "no /etc/threshold.d created by migration" test -e "$ROOT/etc/threshold.d" assert "postinst succeeds" run_script "$POSTINST" configure refute "no drop-in" test -e "$ROOT/etc/systemd/system/threshold.service.d" refute "no boundary.service alias on fresh install" test -L "$ROOT/etc/systemd/system/boundary.service" assert "boundary command symlink still provided" test -L "$ROOT/usr/bin/boundary" refute "threshold not auto-enabled on fresh install" test -e "$FAKE/enabled/threshold.service" assert "postrm purge deletes threshold user" run_script "$POSTRM" purge assert "userdel threshold called" grep -q '^userdel threshold' "$FAKE/calls" # ============================================================================== echo "== scenario 3: boundary service enabled but threshold start fails -> rollback" new_root s3 add_legacy_layout : >"$FAKE/enabled/boundary.service" : >"$FAKE/active/boundary.service" : >"$FAKE/fail_start/threshold.service" assert "preinst succeeds" run_script "$PREINST" install assert "postinst still exits 0" run_script "$POSTINST" configure assert "legacy service running again" test -e "$FAKE/active/boundary.service" assert "legacy service enabled again" test -e "$FAKE/enabled/boundary.service" refute "threshold left disabled" test -e "$FAKE/enabled/threshold.service" refute "alias removed on rollback" test -L "$ROOT/etc/systemd/system/boundary.service" assert "rollback explained" file_has "$WORK/out.log" "rolling back" # ============================================================================== echo "== scenario 4: enabled but stopped boundary service is only carried over" new_root s4 add_legacy_layout : >"$FAKE/enabled/boundary.service" assert "preinst" run_script "$PREINST" install assert "postinst" run_script "$POSTINST" configure assert "threshold enabled" test -e "$FAKE/enabled/threshold.service" refute "threshold not started" test -e "$FAKE/active/threshold.service" # ============================================================================== echo "== scenario 5: custom regular-file /etc/systemd/system/boundary.service is left alone" new_root s5 add_legacy_layout : >"$FAKE/enabled/boundary.service" : >"$FAKE/active/boundary.service" echo "CUSTOM" >"$ROOT/etc/systemd/system/boundary.service" assert "preinst" run_script "$PREINST" install assert "postinst" run_script "$POSTINST" configure assert "custom unit untouched" file_eq "$ROOT/etc/systemd/system/boundary.service" "CUSTOM" assert "legacy service still running" test -e "$FAKE/active/boundary.service" refute "threshold not started" test -e "$FAKE/active/threshold.service" # ============================================================================== echo "== scenario 6: old boundary package binary present is not replaced" new_root s6 add_legacy_layout echo "OLDBIN" >"$ROOT/usr/bin/boundary" assert "preinst" run_script "$PREINST" install assert "postinst" run_script "$POSTINST" configure refute "boundary binary not turned into symlink" test -L "$ROOT/usr/bin/boundary" assert "boundary binary content kept" file_eq "$ROOT/usr/bin/boundary" "OLDBIN" assert "postrm remove does not delete the old binary" run_script "$POSTRM" remove assert "old binary still there" test -f "$ROOT/usr/bin/boundary" # ============================================================================== echo "== scenario 7: threshold user already exists alongside boundary -> no drop-in" new_root s7 add_legacy_layout echo "threshold:threshold" >>"$FAKE/users" assert "preinst" run_script "$PREINST" install assert "postinst" run_script "$POSTINST" configure refute "no drop-in when threshold user exists" test -e "$ROOT/etc/systemd/system/threshold.service.d" # ============================================================================== echo echo "passed: $PASSES, failed: $FAILS" [ "$FAILS" -eq 0 ]