Release 3.8.2.1: reliability, UI probe/logs, CI, signing gates.

Clear sysproxy on core death; probe+reconnect; subscription prune;
Best ignores soft UDP; Windows tray; Android protocol gate; CI workflows.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
M4
2026-07-30 02:44:48 +03:00
co-authored by Cursor
parent 6b6c13c933
commit 621c847cb3
39 changed files with 913 additions and 143 deletions
+35 -6
View File
@@ -40,10 +40,22 @@ printf '%s\n' "$FULL" > "$OUT/VERSION"
printf '%s\n' "${VERSION}+${BUILD}" > "$OUT/Navis.version"
# Ad-hoc sign CLI/bin; packmac also signs the .app (honors NAVIS_CODESIGN_IDENTITY).
# Set REQUIRE_CODESIGN=1 for release builds (fails without a real Developer ID identity).
if [[ "${REQUIRE_CODESIGN:-}" == "1" ]]; then
if [[ -z "${NAVIS_CODESIGN_IDENTITY:-}" || "${NAVIS_CODESIGN_IDENTITY}" == "-" ]]; then
echo "REQUIRE_CODESIGN=1 requires NAVIS_CODESIGN_IDENTITY (Developer ID Application: …)" >&2
exit 1
fi
fi
if command -v codesign >/dev/null 2>&1; then
ID="${NAVIS_CODESIGN_IDENTITY:--}"
codesign -s "$ID" --force "$OUT/Navis" || codesign -s - --force "$OUT/Navis"
codesign -s "$ID" --force "$OUT/Navis-cli" || codesign -s - --force "$OUT/Navis-cli"
if [[ -n "${NAVIS_CODESIGN_IDENTITY:-}" && "${NAVIS_CODESIGN_IDENTITY}" != "-" ]]; then
ID="$NAVIS_CODESIGN_IDENTITY"
codesign -s "$ID" --force --options runtime --timestamp "$OUT/Navis"
codesign -s "$ID" --force --options runtime --timestamp "$OUT/Navis-cli"
else
codesign -s - --force "$OUT/Navis" || true
codesign -s - --force "$OUT/Navis-cli" || true
fi
fi
go run ./tools/packmac -bin "$OUT/Navis" -out "$OUT" -version "$VERSION" -build "$FULL" -arch arm64
@@ -65,9 +77,9 @@ h = hashlib.sha256(binp.read_bytes()).hexdigest()
zh = hashlib.sha256(zipp.read_bytes()).hexdigest() if zipp.exists() else ""
dh = hashlib.sha256(dmgp.read_bytes()).hexdigest() if dmgp.exists() else ""
notes = (
f"Navis {ver}+{build}: меньше нагрузки в простое (лёгкий опрос UI, кэш ядер, "
f"список серверов не мигает); быстрее пинг; стабильнее логи и AWG-прокси; "
f"параллельная работа на нескольких ядрах CPU."
f"Navis {ver}+{build}: при падении ядра снимается системный прокси; логи и проверка туннеля в UI; "
f"автопереподключение / connect-on-launch; подписка чистит устаревшие ноды; «Лучший» без soft-ok UDP; "
f"CI и строгая подпись релиза."
)
paths = [
Path('dist/update.json'),
@@ -95,6 +107,23 @@ for p in paths:
'dmg_url',
'https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release/darwin-arm64/Navis.dmg',
)
# Refresh checksums for any other darwin trees present on disk (amd64/universal).
base = 'https://git.evilfox.cc/test2/navi/raw/branch/main/dist/navis-release'
for key in ('darwin-amd64', 'darwin-universal'):
if key not in plats:
continue
plat_dir = Path('dist/navis-release') / key
bin2 = plat_dir / 'Navis'
zip2 = plat_dir / 'Navis.app.zip'
dmg2 = plat_dir / 'Navis.dmg'
if bin2.exists():
plats[key]['sha256'] = hashlib.sha256(bin2.read_bytes()).hexdigest()
if zip2.exists():
plats[key]['zip_sha256'] = hashlib.sha256(zip2.read_bytes()).hexdigest()
plats[key].setdefault('zip_url', f'{base}/{key}/Navis.app.zip')
if dmg2.exists():
plats[key]['dmg_sha256'] = hashlib.sha256(dmg2.read_bytes()).hexdigest()
plats[key].setdefault('dmg_url', f'{base}/{key}/Navis.dmg')
p.write_text(json.dumps(d, ensure_ascii=False, indent=2) + '\n')
print('updated', p, '->', ver, 'bin', h[:12], 'zip', zh[:12] if zh else '-')
PY
+24 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Sync versioninfo.json + build-macos.bat from internal/update/update.go constants."""
"""Sync versioninfo.json, build-macos.bat, Android gradle, UI badge from update.go."""
from __future__ import annotations
import json
@@ -10,6 +10,8 @@ ROOT = Path(__file__).resolve().parents[1]
UPDATE_GO = ROOT / "internal" / "update" / "update.go"
VERSIONINFO = ROOT / "versioninfo.json"
BUILD_BAT = ROOT / "build-macos.bat"
ANDROID_GRADLE = ROOT / "android" / "app" / "build.gradle.kts"
INDEX_HTML = ROOT / "internal" / "appui" / "index.html"
def read_consts() -> tuple[str, int]:
@@ -28,6 +30,8 @@ def main() -> None:
parts.append(0)
major, minor, patch = parts[0], parts[1], parts[2]
full = f"{ver}.{build}"
display = f"{ver}+{build}"
version_code = major * 1_000_000 + minor * 10_000 + patch * 100 + build
data = json.loads(VERSIONINFO.read_text(encoding="utf-8"))
data["FixedFileInfo"]["FileVersion"] = {
@@ -54,6 +58,25 @@ def main() -> None:
else:
print("build-macos.bat already in sync")
if ANDROID_GRADLE.exists():
g = ANDROID_GRADLE.read_text(encoding="utf-8")
g2 = re.sub(r"versionCode\s*=\s*[\d_]+", f"versionCode = {version_code}", g)
g2 = re.sub(r'versionName\s*=\s*"[^"]+"', f'versionName = "{display}"', g2)
if g2 != g:
ANDROID_GRADLE.write_text(g2, encoding="utf-8")
print("updated", ANDROID_GRADLE, "->", display, version_code)
else:
print("android gradle already in sync")
if INDEX_HTML.exists():
h = INDEX_HTML.read_text(encoding="utf-8")
h2 = re.sub(r'(id="badgeVer">)[^<]+', rf"\g<1>{ver}", h, count=1)
if h2 != h:
INDEX_HTML.write_text(h2, encoding="utf-8")
print("updated", INDEX_HTML, "badge ->", ver)
else:
print("index.html badge already in sync")
if __name__ == "__main__":
main()