mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-07 18:57:14 +00:00
8daf1d844d
- Replace the mktemp+cp snapshot with a same-filesystem mv of bin/ aside: an unchecked mktemp failure previously made the very next line copy bin/'s contents into "/" (empty custom_bin_backup + trailing slash), and a silently-ignored cp failure (stderr redirected, exit code never checked) could leave a truncated custom geo file that gets "restored" as if it were intact. A rename is atomic and needs no extra disk space, removing both failure modes at once; if it fails, back off cleanly and say so instead of proceeding as if a backup exists. - Add a trap so an interrupted update (Ctrl-C, signal) between the backup and the restore doesn't leave the snapshot (which contains bin/config.json and every mtproto client's FakeTLS secret) sitting around indefinitely; the two exit-path cleanups this replaces are gone since the trap now covers those exits too. - Move the restore below the arm arch-rename/chmod block instead of before it, so xray-linux-arm32/mtg-linux-arm already exist under their final names and don't get needlessly restored-then-overwritten and misreported as "custom". - Exclude bin/config.json and bin/mtproto/*.toml from the restore: those are the panel's own generated runtime state (internal/xray/process.go, internal/mtproto/manager.go), not admin-placed files, and restoring a stale one only resurrects dead state or recreates bin/mtproto/ with the wrong (more permissive) directory mode. - Match symlinks in the restore's find, not just plain files -- cp -a already preserves them in the snapshot, but the restore loop was silently dropping them, which is exactly the failure mode (a geo file symlinked in from elsewhere) this PR set out to fix. - Quote the two new xui_folder expansions. - Extend the non-interactive smoke test to reinstall over an existing install with a sentinel file in bin/, asserting it survives and that the bundled geoip.dat is still the release's own copy -- the update path this PR touches had no CI coverage at all before this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
112 lines
4.9 KiB
Bash
112 lines
4.9 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# smoke-noninteractive.sh — verify the non-interactive install path.
|
|
#
|
|
# Runs install.sh inside an Ubuntu container with NO TTY (piped) and
|
|
# XUI_NONINTERACTIVE=1, then asserts:
|
|
# * /etc/x-ui/install-result.env exists (mode 600) with random, non-default creds
|
|
# * the panel reports hasDefaultCredential: false (no admin/admin remains)
|
|
# * the panel HTTP server actually serves on the generated port/base path
|
|
# * with a [version] argument: the installed binary reports exactly that version
|
|
#
|
|
# Requires Docker and network access (install.sh downloads the released binary).
|
|
# Usage: bash deploy/test/smoke-noninteractive.sh [version]
|
|
# With no argument install.sh resolves releases/latest. Pass an explicit tag
|
|
# (e.g. v3.4.2) to verify that exact release — the tag-triggered CI run does
|
|
# this so it cannot silently validate the previous release (#5756).
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
IMAGE="${SMOKE_IMAGE:-ubuntu:24.04}"
|
|
XUI_SMOKE_VERSION="${1:-}"
|
|
|
|
if ! command -v docker > /dev/null 2>&1; then
|
|
echo "ERROR: docker is required for this smoke test." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "== non-interactive install smoke test (image: $IMAGE, version: ${XUI_SMOKE_VERSION:-latest}) =="
|
|
|
|
docker run --rm \
|
|
-v "${REPO_ROOT}/install.sh:/root/install.sh:ro" \
|
|
-e XUI_NONINTERACTIVE=1 \
|
|
-e XUI_SSL_MODE=none \
|
|
-e XUI_SMOKE_VERSION="$XUI_SMOKE_VERSION" \
|
|
-e DEBIAN_FRONTEND=noninteractive \
|
|
"$IMAGE" bash -euo pipefail -c '
|
|
apt-get update -qq
|
|
apt-get install -y -qq curl tar openssl ca-certificates > /dev/null
|
|
|
|
echo "--- running install.sh piped (no TTY), version: ${XUI_SMOKE_VERSION:-latest} ---"
|
|
# Piping guarantees stdin is not a TTY, exercising the auto non-interactive path.
|
|
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
|
|
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
|
|
else
|
|
cat /root/install.sh | bash
|
|
fi
|
|
|
|
echo "--- assertions ---"
|
|
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
|
|
installed=$(/usr/local/x-ui/x-ui -v)
|
|
[ "$installed" = "${XUI_SMOKE_VERSION#v}" ] \
|
|
|| { echo "FAIL: installed version $installed, want ${XUI_SMOKE_VERSION#v}"; exit 1; }
|
|
fi
|
|
|
|
RESULT=/etc/x-ui/install-result.env
|
|
test -f "$RESULT" || { echo "FAIL: $RESULT missing"; exit 1; }
|
|
|
|
perms=$(stat -c %a "$RESULT")
|
|
[ "$perms" = "600" ] || { echo "FAIL: $RESULT perms=$perms (want 600)"; exit 1; }
|
|
|
|
# shellcheck disable=SC1090
|
|
. "$RESULT"
|
|
[ -n "${XUI_USERNAME:-}" ] && [ "$XUI_USERNAME" != "admin" ] \
|
|
|| { echo "FAIL: username missing or still admin"; exit 1; }
|
|
[ -n "${XUI_PASSWORD:-}" ] && [ "$XUI_PASSWORD" != "admin" ] \
|
|
|| { echo "FAIL: password missing or still admin"; exit 1; }
|
|
[ -n "${XUI_PANEL_PORT:-}" ] || { echo "FAIL: port missing"; exit 1; }
|
|
|
|
# No default admin in the DB.
|
|
/usr/local/x-ui/x-ui setting -show | grep -q "hasDefaultCredential: false" \
|
|
|| { echo "FAIL: hasDefaultCredential is not false"; exit 1; }
|
|
|
|
echo "--- verifying the panel serves HTTP ---"
|
|
cd /usr/local/x-ui
|
|
./x-ui > /tmp/xui.log 2>&1 &
|
|
xpid=$!
|
|
for _ in $(seq 1 15); do
|
|
code=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
"http://127.0.0.1:${XUI_PANEL_PORT}/${XUI_WEB_BASE_PATH}/" 2>/dev/null || true)
|
|
case "$code" in 200|301|302|307|308) break ;; esac
|
|
sleep 1
|
|
done
|
|
kill "$xpid" 2>/dev/null || true
|
|
echo "panel HTTP status: ${code:-none}"
|
|
case "${code:-}" in
|
|
200|301|302|307|308) : ;;
|
|
*) echo "FAIL: panel did not serve (status ${code:-none})"; tail -n 30 /tmp/xui.log; exit 1 ;;
|
|
esac
|
|
|
|
echo "--- verifying a second install preserves custom bin/ files ---"
|
|
echo "custom-sentinel" > /usr/local/x-ui/bin/geoip_custom.dat
|
|
geoip_sum_before=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
|
|
|
|
if [ -n "${XUI_SMOKE_VERSION:-}" ]; then
|
|
cat /root/install.sh | bash -s -- "$XUI_SMOKE_VERSION"
|
|
else
|
|
cat /root/install.sh | bash
|
|
fi
|
|
|
|
test -f /usr/local/x-ui/bin/geoip_custom.dat \
|
|
|| { echo "FAIL: custom bin/ file did not survive a second install"; exit 1; }
|
|
[ "$(cat /usr/local/x-ui/bin/geoip_custom.dat)" = "custom-sentinel" ] \
|
|
|| { echo "FAIL: custom bin/ file content changed across a second install"; exit 1; }
|
|
geoip_sum_after=$(sha256sum /usr/local/x-ui/bin/geoip.dat | cut -d" " -f1)
|
|
[ "$geoip_sum_after" = "$geoip_sum_before" ] \
|
|
|| { echo "FAIL: bundled geoip.dat changed across a same-version reinstall"; exit 1; }
|
|
|
|
echo "SMOKE_PASS: user=$XUI_USERNAME port=$XUI_PANEL_PORT path=$XUI_WEB_BASE_PATH"
|
|
'
|
|
|
|
echo "== non-interactive smoke test PASSED =="
|