release: restore ZUPT and harden source-only 5.2.2

This commit is contained in:
Cristian Cezar Moisés 2026-08-31 14:14:36 -03:00
commit ff99770bd0
205 changed files with 19627 additions and 13215 deletions

133
scripts/test-installed-zupt.sh Executable file
View file

@ -0,0 +1,133 @@
#!/usr/bin/env bash
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (c) 2026 Cristian Cezar Moisés
set -Eeuo pipefail
umask 077
export LC_ALL=C
die() {
printf 'FAIL: %s\n' "$*" >&2
exit 1
}
pass() {
printf 'PASS: %s\n' "$1"
}
hash_tree() {
local tree=$1
(
cd -- "$tree"
if command -v sha256sum >/dev/null 2>&1; then
find . -type f -exec sha256sum {} \; | LC_ALL=C sort
elif command -v shasum >/dev/null 2>&1; then
find . -type f -exec shasum -a 256 {} \; | LC_ALL=C sort
else
die 'sha256sum or shasum is required'
fi
)
}
# ZUPT_BIN is the public override. VAPTVUPT_BIN remains a compatibility
# fallback for existing automation during the package-name transition.
candidate=${1:-${ZUPT_BIN:-${VAPTVUPT_BIN:-zupt}}}
if [[ $candidate == */* ]]; then
[[ -x $candidate ]] || die "executable not found: $candidate"
binary=$(cd -- "$(dirname -- "$candidate")" && pwd -P)/$(basename -- "$candidate")
else
binary=$(command -v -- "$candidate" || true)
[[ -n $binary ]] || die "executable not found on PATH: $candidate"
fi
test_root=$(mktemp -d "${TMPDIR:-/tmp}/zupt-installed.XXXXXX")
trap 'chmod -R u+rwX "$test_root" 2>/dev/null || true; rm -rf -- "$test_root"' EXIT HUP INT TERM
input=$test_root/input
plain_out=$test_root/plain-out
password_out=$test_root/password-out
escape_out=$test_root/escape-out
outside=$test_root/outside
mkdir -p "$input/subdir" "$plain_out" "$password_out" "$escape_out" "$outside"
printf 'ZUPT installed smoke test\nsecond line\n' > "$input/text file.txt"
printf 'conteúdo UTF-8\n' > "$input/subdir/café-安全.txt"
: > "$input/empty file"
dd if=/dev/urandom of="$input/subdir/random.bin" bs=4096 count=8 2>/dev/null
printf 'do-not-overwrite\n' > "$outside/sentinel"
"$binary" --version > "$test_root/version.log" 2>&1
grep -q '^zupt ' "$test_root/version.log" || die "--version did not identify zupt"
pass '--version'
"$binary" --help > "$test_root/help.log" 2>&1
grep -q '^Usage:' "$test_root/help.log" || die "--help did not contain Usage"
pass '--help'
if "$binary" --definitely-invalid-option > "$test_root/invalid.log" 2>&1; then
die 'invalid option returned success'
fi
pass 'invalid option returns failure'
plain_archive=$test_root/plain.zupt
"$binary" compress "$plain_archive" "$input" > "$test_root/plain-compress.log" 2>&1
"$binary" test "$plain_archive" > "$test_root/plain-test.log" 2>&1
"$binary" extract -o "$plain_out" "$plain_archive" > "$test_root/plain-extract.log" 2>&1
extracted_markers=()
while IFS= read -r -d '' marker; do
extracted_markers[${#extracted_markers[@]}]=$marker
done < <(find "$plain_out" -type f -name 'text file.txt' -print0)
[[ ${#extracted_markers[@]} -eq 1 ]] || die 'extracted tree is missing or ambiguous'
extracted_input=$(dirname -- "${extracted_markers[0]}")
[[ -f $extracted_input/subdir/café-安全.txt && -f $extracted_input/empty\ file ]] || \
die 'extracted tree is incomplete'
diff -r -- "$input" "$extracted_input" > "$test_root/plain-diff.log" || die 'plain round-trip differs'
hash_tree "$input" > "$test_root/original.sha256"
hash_tree "$extracted_input" > "$test_root/extracted.sha256"
cmp -- "$test_root/original.sha256" "$test_root/extracted.sha256" || die 'round-trip SHA-256 manifests differ'
pass 'text, random, empty, nested, spaces and UTF-8 round-trip'
password='ZUPT-test-password-2026!'
password_archive=$test_root/password.zupt
"$binary" compress -p "$password" "$password_archive" "$input/text file.txt" > "$test_root/password-compress.log" 2>&1
"$binary" test -p "$password" "$password_archive" > "$test_root/password-test.log" 2>&1
"$binary" extract -p "$password" -o "$password_out" "$password_archive" > "$test_root/password-extract.log" 2>&1
password_markers=()
while IFS= read -r -d '' marker; do
password_markers[${#password_markers[@]}]=$marker
done < <(find "$password_out" -type f -name 'text file.txt' -print0)
[[ ${#password_markers[@]} -eq 1 ]] || die 'password extraction is missing or ambiguous'
cmp -- "$input/text file.txt" "${password_markers[0]}" || die 'password round-trip differs'
if "$binary" extract -p 'incorrect-password' -o "$test_root/wrong-password-out" "$password_archive" > "$test_root/wrong-password.log" 2>&1; then
die 'incorrect password returned success'
fi
pass 'password round-trip and incorrect-password rejection'
archive_size=$(wc -c < "$plain_archive")
(( archive_size > 32 )) || die 'archive unexpectedly small'
head -c "$((archive_size - 17))" "$plain_archive" > "$test_root/corrupt.zupt"
if "$binary" test "$test_root/corrupt.zupt" > "$test_root/corrupt.log" 2>&1; then
die 'truncated archive returned success'
fi
pass 'corrupt archive rejection'
archive_input_rel=${extracted_input#"$plain_out"/}
[[ $archive_input_rel != "$extracted_input" && $archive_input_rel != /* ]] || \
die 'cannot determine the archive extraction path'
mkdir -p -- "$escape_out/$(dirname -- "$archive_input_rel")"
ln -s -- "$outside" "$escape_out/$archive_input_rel"
"$binary" extract -o "$escape_out" "$plain_archive" > "$test_root/escape.log" 2>&1 || true
[[ $(<"$outside/sentinel") == 'do-not-overwrite' ]] || die 'extraction overwrote outside sentinel'
[[ ! -e "$outside/text file.txt" && ! -e "$outside/subdir" ]] || die 'extraction escaped through a destination symlink'
pass 'no write outside extraction destination'
if [[ $(id -u) -eq 0 ]]; then
printf 'SKIP: unprivileged execution (test process is root)\n'
else
[[ -r $plain_archive && -x $binary ]] || die 'unprivileged process cannot read archive or execute binary'
pass 'execution as an unprivileged user'
fi
printf 'PASS: installed ZUPT functional test suite\n'