Telemax/scripts/release.sh
Folist a518a7d408 Headless-мост: веб-панель вырезана, опциональные стикеры (slim/full), подпись обновлений
Вырезана веб-панель целиком (express/ws/react/vite/tailwind, TLS-серт, /api/*, API_KEY, порт 3000) — мост теперь headless: MAX по исходящему сокету, Telegram long-polling, управление и авторизация только в боте (/login, /panel). Убрана поверхность атаки, bundle меньше.

Анимированные стикеры (.tgs) стали опциональными: build-arg STICKERS=full|slim. full (деф.) ставит Chromium+ffmpeg (образ ~1.7 ГБ); slim пропускает их (~0.3 ГБ, быстрая сборка), анимированные уходят статической картинкой (thumbnail). setup.sh спрашивает при установке (30с таймаут, не тормозит).

Подпись обновлений (Phase C): update.sh/release.sh проверяют GPG-подпись релизного тега при наличии pinned-ключа release-signing-key.asc (транспорт GitHub/зеркало недоверенный, важна только подпись мейнтейнера). Активируется после добавления публичного ключа.
2026-08-22 15:32:57 +03:00

79 lines
4.1 KiB
Bash

#!/usr/bin/env bash
# Maintainer-only release ritual. Run from a full clone AFTER bumping package.json's version and
# creating the matching tag (git tag vX.Y.Z). It pushes main + tags to BOTH GitHub (origin) and the
# self-hosted fallback mirror, then refreshes the mirror's latest.json so installs that CAN'T reach
# GitHub (account flagged, or GitHub filtered on their network) still learn about the new version
# and can update from the mirror. See src/bridge/version.ts (checkVersion fallback) and update.sh
# (git pull fallback) for the consuming side.
#
# NOT part of a normal deployment — installs never run this.
#
# Usage: ./scripts/release.sh
# Env: MIRROR_SSH (default root@zergont-gate.duckdns.org)
# MIRROR_REPO_PATH (default /opt/telemax-mirror/web/Telemax.git)
# MIRROR_WEB_PATH (default /opt/telemax-mirror/web)
set -euo pipefail
cd "$(dirname "$0")/.."
VERSION=$(node -p "require('./package.json').version")
TAG="v${VERSION}"
MIRROR_SSH="${MIRROR_SSH:-root@zergont-gate.duckdns.org}"
MIRROR_REPO_PATH="${MIRROR_REPO_PATH:-/opt/telemax-mirror/web/Telemax.git}"
MIRROR_WEB_PATH="${MIRROR_WEB_PATH:-/opt/telemax-mirror/web}"
MIRROR_GIT_URL="ssh://${MIRROR_SSH}${MIRROR_REPO_PATH}"
# Public HTTP base of the mirror — used to read back the current latest.json so the per-version
# changelog map accumulates across releases (see scripts/build-latest-json.mjs).
MIRROR_HTTP_URL="${MIRROR_HTTP_URL:-http://zergont-gate.duckdns.org:3200}"
echo ">> Releasing ${TAG}"
# The tag must already exist (coordinate the tag first, then run this).
if ! git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "!! Tag ${TAG} not found. Create it first: git tag -s ${TAG} then re-run." >&2
exit 1
fi
# Signed-release trust (v0.4): once the maintainer's public key is pinned in the repo
# (release-signing-key.asc), refuse to publish a tag that isn't validly signed by it — so neither
# GitHub nor the mirror can ever carry code that update.sh's verify-tag would (correctly) reject.
# Create signed tags with: git tag -s vX.Y.Z (needs the private key + gpg on this machine).
if [ -f release-signing-key.asc ]; then
VERIFY_HOME=$(mktemp -d)
GNUPGHOME="$VERIFY_HOME" gpg --quiet --import release-signing-key.asc >/dev/null 2>&1 || true
if ! GNUPGHOME="$VERIFY_HOME" git -c gpg.program=gpg verify-tag "${TAG}" >/dev/null 2>&1; then
rm -rf "$VERIFY_HOME"
echo "!! Tag ${TAG} is not validly signed by the pinned release key. Sign it: git tag -s -f ${TAG}" >&2
exit 1
fi
rm -rf "$VERIFY_HOME"
echo ">> release signature OK: ${TAG}"
fi
echo ">> [1/4] push to GitHub (origin)"
git push origin main
git push origin "${TAG}"
echo ">> [2/4] push to mirror (${MIRROR_GIT_URL})"
git push "${MIRROR_GIT_URL}" "+refs/heads/main:refs/heads/main" "+refs/tags/*:refs/tags/*"
echo ">> [3/4] build latest.json (cumulative per-version changelog)"
PREV_TAG=$(git describe --tags --abbrev=0 "${TAG}^" 2>/dev/null || echo "")
RANGE="${TAG}"
[ -n "${PREV_TAG}" ] && RANGE="${PREV_TAG}..${TAG}"
# This version's notes: commit subjects since the previous tag, minus the release-bump commit itself.
NEW_NOTES_JSON=$(git log --format='%s' "${RANGE}" | grep -viE '^Релиз |^Release ' \
| node -e "const l=require('fs').readFileSync(0,'utf8').split('\n').filter(Boolean); process.stdout.write(JSON.stringify(l))")
# Accumulate into the map already published on the mirror so multi-version jumps keep every release.
EXISTING_JSON=$(curl -fsS "${MIRROR_HTTP_URL}/latest.json" 2>/dev/null || echo '{}')
LATEST_JSON=$(node scripts/build-latest-json.mjs "${VERSION}" "${TAG}" "${NEW_NOTES_JSON}" "${EXISTING_JSON}")
echo " ${LATEST_JSON}"
echo ">> [4/4] upload latest.json + install.sh to mirror + refresh dumb-http index"
ssh "${MIRROR_SSH}" "cat > ${MIRROR_WEB_PATH}/latest.json" <<<"${LATEST_JSON}"
# Serve the bootstrap script from the mirror too, so a fresh install works while GitHub is down:
# curl -fsSL http://<mirror>/install.sh | bash
scp -q install.sh "${MIRROR_SSH}:${MIRROR_WEB_PATH}/install.sh"
ssh "${MIRROR_SSH}" "cd ${MIRROR_REPO_PATH} && git update-server-info"
echo ">> Done. Released ${TAG} to GitHub + mirror."