144 lines
5.8 KiB
Shell
Executable file
144 lines
5.8 KiB
Shell
Executable file
#!/bin/bash
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
# Copyright (c) 2025-2026 Cristian Cezar Moisés
|
|
#
|
|
# Regression test for ZUPT GUI branding + licensing.
|
|
#
|
|
# History: in v3.0.0 the GUI shipped with two documentation/code bugs:
|
|
# 1. The about panel described the current GUI simply as MIT even though the
|
|
# current source carried AGPL-3.0-or-later notices. Published earlier MIT
|
|
# grants remain valid for the exact historical material covered by them.
|
|
# 2. A version-string parser using `replace("zupt ", "")` which
|
|
# matched the wrong substring after the v3.0.0 rename. The
|
|
# version banner became `vaptvupt 3.0.0 (formerly zupt;
|
|
# renamed in v3.0.0 — INPI Brasil trademark)` and that
|
|
# `replace` chewed up "zupt " inside the parenthetical too.
|
|
#
|
|
# This test keeps the current about-panel statement aligned with current SPDX
|
|
# notices without denying the historical license record, and covers the parser.
|
|
|
|
set -u
|
|
PASS=0; FAIL=0
|
|
P() { echo " ✓ $1"; PASS=$((PASS+1)); }
|
|
F() { echo " ✗ $1"; FAIL=$((FAIL+1)); }
|
|
|
|
GUI=gui/src/zupt_gui.py
|
|
[ ! -f "$GUI" ] && { echo "ERROR: $GUI missing — run from repo root"; exit 2; }
|
|
|
|
echo "GUI branding + licensing"
|
|
|
|
# ─── Current and historical license checks ───
|
|
# The current about-panel implementation must not advertise the current GUI as
|
|
# MIT-only. Historical license information belongs in the license notice.
|
|
if grep -nE '"MIT"|"MIT [Ll]icense"| MIT[^A-Za-z]' "$GUI" >/dev/null 2>&1; then
|
|
F "GUI source advertises the current GUI as MIT"
|
|
grep -nE '"MIT"|"MIT [Ll]icense"| MIT[^A-Za-z]' "$GUI" | sed 's/^/ /'
|
|
else
|
|
P "GUI source does not advertise the current GUI as MIT"
|
|
fi
|
|
|
|
# The GUI's own LICENSE-GUI file must be AGPL (or pointed to AGPL).
|
|
if [ -f gui/LICENSE-GUI ]; then
|
|
if grep -q "GNU AFFERO GENERAL PUBLIC LICENSE\|AGPL" gui/LICENSE-GUI; then
|
|
P "gui/LICENSE-GUI is AGPL-licensed"
|
|
else
|
|
F "gui/LICENSE-GUI is not AGPL — got: $(head -1 gui/LICENSE-GUI)"
|
|
fi
|
|
# The current notice starts with AGPL, while retaining the factual erratum.
|
|
if head -1 gui/LICENSE-GUI | grep -qE "^MIT License"; then
|
|
F "gui/LICENSE-GUI presents MIT as the current license"
|
|
else
|
|
P "gui/LICENSE-GUI presents AGPL as the current license"
|
|
fi
|
|
if grep -q 'd4660e6539c8b6eeba81751c018217d978fdd618' gui/LICENSE-GUI &&
|
|
grep -q 'v2.2.2' gui/LICENSE-GUI &&
|
|
grep -q 'does not revoke or reinterpret a historical grant' gui/LICENSE-GUI; then
|
|
P "gui/LICENSE-GUI preserves the evidenced historical MIT grant"
|
|
else
|
|
F "gui/LICENSE-GUI is missing the factual historical-license erratum"
|
|
fi
|
|
fi
|
|
|
|
# ─── SPDX header check ───
|
|
# The .py source's SPDX header must be AGPL-3.0-or-later.
|
|
if head -5 "$GUI" | grep -q "SPDX-License-Identifier: AGPL-3.0-or-later"; then
|
|
P "GUI SPDX header is AGPL-3.0-or-later"
|
|
else
|
|
F "GUI SPDX header is missing or wrong"
|
|
fi
|
|
|
|
# ─── Version-parsing bug check ───
|
|
# The buggy pattern was `ZUPT_VER_SHORT.replace("zupt ", ...)`.
|
|
# That regex must not appear in CODE — it produces garbage on v3.0.x
|
|
# version strings. The explanatory comment in _get_version that
|
|
# documents the historical fix is fine.
|
|
if grep -nE 'replace\("zupt ' "$GUI" | grep -vE '^[0-9]+:#' >/dev/null 2>&1; then
|
|
F "GUI uses the broken replace(\"zupt \", ...) version parser"
|
|
grep -nE 'replace\("zupt ' "$GUI" | grep -vE '^[0-9]+:#' | sed 's/^/ /'
|
|
else
|
|
P "GUI does not use the broken replace(\"zupt \", ...) parser (in code)"
|
|
fi
|
|
|
|
# A proper version regex must be present.
|
|
if grep -qE '_VERSION_RE\s*=\s*re\.compile|re\.match.*vaptvupt' "$GUI"; then
|
|
P "GUI defines a strict anchored version regex"
|
|
else
|
|
F "GUI is missing the anchored version regex (_VERSION_RE)"
|
|
fi
|
|
|
|
# ─── Brand-string check ───
|
|
# Release 5.2.2 restores the original ZUPT identity in every current panel.
|
|
if grep -q 'QLabel("ZUPT")' "$GUI" &&
|
|
! grep -q 'QLabel("VAPTVUPT")' "$GUI"; then
|
|
P "GUI uses ZUPT in current QLabel headers"
|
|
else
|
|
F "GUI current headers are not consistently branded ZUPT"
|
|
fi
|
|
|
|
# Crypto stack should include Argon2id (the default since v2.4.1).
|
|
if grep -q 'Argon2id' "$GUI"; then
|
|
P "GUI about-panel crypto stack includes Argon2id"
|
|
else
|
|
F "GUI about-panel crypto stack is missing Argon2id"
|
|
fi
|
|
|
|
# Crypto stack should include the VaptVupt codec attribution.
|
|
if grep -q 'VaptVupt LZ + ANS\|VaptVupt LZ' "$GUI"; then
|
|
P "GUI about-panel mentions the VaptVupt codec"
|
|
else
|
|
F "GUI about-panel doesn't mention the VaptVupt codec"
|
|
fi
|
|
|
|
# Commercial-licensing contact must be visible.
|
|
if grep -q 'sac@securityops.co' "$GUI"; then
|
|
P "GUI shows the commercial-licensing contact (sac@securityops.co)"
|
|
else
|
|
F "GUI is missing the commercial-licensing contact"
|
|
fi
|
|
|
|
# ─── Functional check ───
|
|
# If the CLI binary is available, exercise _VERSION_RE end-to-end.
|
|
BIN=${1:-${ZUPT_BIN:-./zupt}}
|
|
if [ -x "$BIN" ]; then
|
|
OUT=$("$BIN" version 2>&1 | head -1)
|
|
EXTRACTED=$(python3 -c "
|
|
import re, sys
|
|
s = sys.argv[1]
|
|
m = re.match(r'^(?:vaptvupt|zupt)\s+(\d+\.\d+\.\d+(?:[._A-Za-z0-9-]*)?)', s)
|
|
print(m.group(1) if m else 'NONE')
|
|
" "$OUT")
|
|
EXPECTED=$(grep -E '^#define ZUPT_VERSION_STRING' include/zupt.h | awk -F'"' '{print $2}')
|
|
if [ "$EXTRACTED" = "$EXPECTED" ]; then
|
|
P "version regex extracts $EXTRACTED (matches include/zupt.h)"
|
|
else
|
|
F "version regex extracted '$EXTRACTED', expected '$EXPECTED'"
|
|
fi
|
|
else
|
|
echo " - skipped: ZUPT binary not built — skipping functional version test"
|
|
fi
|
|
|
|
echo ""
|
|
echo " ───────────────────────────────────────"
|
|
echo " GUI branding + licensing: $PASS passed, $FAIL failed"
|
|
echo " ───────────────────────────────────────"
|
|
[ "$FAIL" = 0 ] || exit 1
|