mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-28 13:32:23 +00:00
147 lines
6.2 KiB
Bash
147 lines
6.2 KiB
Bash
#!/usr/bin/env bash
|
|
# Regression test for the issue #3224 hardening in
|
|
# strip-appimage-graphics-libs.sh:
|
|
# 1. sanitize_elf_rpaths — strips /home/runner|/__w build-machine
|
|
# RPATHs from bundled ELFs, rewriting to
|
|
# $ORIGIN-relative.
|
|
# 2. validate_appimage_required_libs — hard-fails when libxdo.so.* is missing
|
|
# from a sharun AppDir.
|
|
#
|
|
# Linux-only: needs `patchelf` and a host ELF to mutate. Skips cleanly (exit 0)
|
|
# on macOS / any host without patchelf so it is a no-op on dev boxes and a real
|
|
# gate in CI (where build-desktop.yml already apt-installs patchelf).
|
|
#
|
|
# Usage: bash scripts/release/test-strip-appimage-rpaths.sh
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
TARGET="$SCRIPT_DIR/strip-appimage-graphics-libs.sh"
|
|
|
|
skip() {
|
|
echo "[test-rpaths] SKIP: $1"
|
|
exit 0
|
|
}
|
|
|
|
[ -f "$TARGET" ] || { echo "[test-rpaths] FAIL: $TARGET not found" >&2; exit 1; }
|
|
command -v patchelf >/dev/null 2>&1 || skip "patchelf not installed (expected on non-Linux dev boxes)"
|
|
|
|
# Find a small host ELF we can copy + mutate.
|
|
HOST_ELF=""
|
|
for cand in /bin/true /usr/bin/true /bin/echo; do
|
|
if [ -f "$cand" ] && [ "$(LC_ALL=C head -c 4 "$cand" 2>/dev/null || true)" = $'\177ELF' ]; then
|
|
HOST_ELF="$cand"
|
|
break
|
|
fi
|
|
done
|
|
[ -n "$HOST_ELF" ] || skip "no host ELF available to build a fixture"
|
|
|
|
# Source the target so we can call its functions in isolation. The
|
|
# sourced-vs-executed guard at the bottom of the script keeps main() from
|
|
# running here.
|
|
# shellcheck source=/dev/null
|
|
source "$TARGET"
|
|
|
|
WORK="$(mktemp -d)"
|
|
trap 'rm -rf "$WORK"' EXIT
|
|
|
|
fail() { echo "[test-rpaths] FAIL: $1" >&2; exit 1; }
|
|
|
|
# --- Case 1: sanitize_elf_rpaths strips a CI build-machine RPATH ------------
|
|
APPDIR="$WORK/squashfs-root"
|
|
mkdir -p "$APPDIR/usr/lib" "$APPDIR/shared/lib"
|
|
|
|
# An ELF that mimics libcef.so with an absolute build-runner RUNPATH plus a
|
|
# legitimate $ORIGIN entry — only the absolute one should be dropped.
|
|
FAKE_CEF="$APPDIR/usr/lib/libcef.so"
|
|
cp "$HOST_ELF" "$FAKE_CEF"
|
|
patchelf --set-rpath '/home/runner/.cache/tauri-cef/x/shared/lib:$ORIGIN/../shared/lib' "$FAKE_CEF"
|
|
|
|
# A clean ELF whose RPATH must be left byte-for-byte untouched (idempotency).
|
|
CLEAN_SO="$APPDIR/shared/lib/libclean.so"
|
|
cp "$HOST_ELF" "$CLEAN_SO"
|
|
patchelf --set-rpath '$ORIGIN' "$CLEAN_SO"
|
|
clean_before="$(patchelf --print-rpath "$CLEAN_SO")"
|
|
|
|
if ! sanitize_elf_rpaths "$APPDIR"; then
|
|
fail "sanitize_elf_rpaths reported no change but a CI RPATH was present"
|
|
fi
|
|
|
|
cef_after="$(patchelf --print-rpath "$FAKE_CEF")"
|
|
case "$cef_after" in
|
|
*"/home/runner/"*|*"/__w/"*) fail "CI RPATH survived: '$cef_after'" ;;
|
|
esac
|
|
case "$cef_after" in
|
|
*'$ORIGIN'*) ;;
|
|
*) fail "expected an \$ORIGIN-relative RPATH after sanitize, got: '$cef_after'" ;;
|
|
esac
|
|
echo "[test-rpaths] ok: libcef.so RPATH rewritten to '$cef_after'"
|
|
|
|
clean_after="$(patchelf --print-rpath "$CLEAN_SO")"
|
|
[ "$clean_before" = "$clean_after" ] || fail "clean ELF RPATH was mutated: '$clean_before' -> '$clean_after'"
|
|
echo "[test-rpaths] ok: clean ELF left untouched ('$clean_after')"
|
|
|
|
# Idempotency: a second pass must find nothing to do.
|
|
if sanitize_elf_rpaths "$APPDIR"; then
|
|
fail "sanitize_elf_rpaths was not idempotent — rewrote on a clean second pass"
|
|
fi
|
|
echo "[test-rpaths] ok: second pass is a no-op (idempotent)"
|
|
|
|
# --- Case 1b: pure-absolute CI RPATH → depth-aware fallback ------------------
|
|
# This is the issue #3224 scenario: libcef.so carries ONLY an absolute
|
|
# build-machine RPATH, no surviving $ORIGIN entry. The fallback MUST reach the
|
|
# bundle's top-level shared/lib from usr/lib, i.e. `$ORIGIN/../../shared/lib`
|
|
# (two hops), NOT the naive `$ORIGIN/../shared/lib` which resolves to
|
|
# usr/shared/lib.
|
|
ABS_DIR="$WORK/abs"
|
|
mkdir -p "$ABS_DIR/usr/lib"
|
|
ABS_CEF="$ABS_DIR/usr/lib/libcef.so"
|
|
cp "$HOST_ELF" "$ABS_CEF"
|
|
patchelf --set-rpath '/home/runner/.cache/tauri-cef/x/shared/lib' "$ABS_CEF"
|
|
sanitize_elf_rpaths "$ABS_DIR" || fail "sanitize_elf_rpaths reported no change on a pure-absolute RPATH"
|
|
abs_after="$(patchelf --print-rpath "$ABS_CEF")"
|
|
[ "$abs_after" = '$ORIGIN:$ORIGIN/../../shared/lib' ] \
|
|
|| fail "usr/lib fallback wrong: expected '\$ORIGIN:\$ORIGIN/../../shared/lib', got '$abs_after'"
|
|
echo "[test-rpaths] ok: usr/lib pure-absolute RPATH → depth-aware fallback '$abs_after'"
|
|
|
|
# A lib one level deep (lib/) needs only one hop.
|
|
mkdir -p "$ABS_DIR/lib"
|
|
ABS_LIB="$ABS_DIR/lib/libfoo.so"
|
|
cp "$HOST_ELF" "$ABS_LIB"
|
|
patchelf --set-rpath '/__w/openhuman/openhuman/shared/lib' "$ABS_LIB"
|
|
sanitize_elf_rpaths "$ABS_DIR" >/dev/null || true
|
|
lib_after="$(patchelf --print-rpath "$ABS_LIB")"
|
|
[ "$lib_after" = '$ORIGIN:$ORIGIN/../shared/lib' ] \
|
|
|| fail "lib/ fallback wrong: expected '\$ORIGIN:\$ORIGIN/../shared/lib', got '$lib_after'"
|
|
echo "[test-rpaths] ok: lib/ pure-absolute RPATH → depth-aware fallback '$lib_after'"
|
|
|
|
# --- Case 2: validate_appimage_required_libs guards libxdo -------------------
|
|
# Build a minimal sharun AppDir. uses_sharun_launcher only inspects *ELF* entry
|
|
# binaries (is_executable_elf) and greps them for the literal
|
|
# "Interpreter not found!" string, mirroring the real sharun launcher binary.
|
|
# So the fixture must be an executable ELF with that marker appended (a shell
|
|
# AppRun would be skipped as non-ELF and the guard would no-op).
|
|
GUARD_DIR="$WORK/guard"
|
|
mkdir -p "$GUARD_DIR/shared/lib"
|
|
cp "$HOST_ELF" "$GUARD_DIR/sharun"
|
|
printf 'Interpreter not found!' >> "$GUARD_DIR/sharun"
|
|
chmod +x "$GUARD_DIR/sharun"
|
|
# Sanity: the fixture must actually register as a sharun launcher, else the
|
|
# guard's early return would make this case vacuously pass.
|
|
uses_sharun_launcher "$GUARD_DIR" || fail "fixture did not register as sharun launcher"
|
|
|
|
# 2a — libxdo absent → must exit non-zero.
|
|
if ( validate_appimage_required_libs "$GUARD_DIR" ) 2>/dev/null; then
|
|
fail "validate_appimage_required_libs passed despite missing libxdo.so.*"
|
|
fi
|
|
echo "[test-rpaths] ok: guard fails when libxdo.so.* is absent"
|
|
|
|
# 2b — libxdo present → must pass.
|
|
: > "$GUARD_DIR/shared/lib/libxdo.so.3"
|
|
if ! ( validate_appimage_required_libs "$GUARD_DIR" ) 2>/dev/null; then
|
|
fail "validate_appimage_required_libs failed despite libxdo.so.3 present"
|
|
fi
|
|
echo "[test-rpaths] ok: guard passes when libxdo.so.3 is present"
|
|
|
|
echo "[test-rpaths] PASS"
|