diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index fd9631a..1af3d60 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -37,9 +37,15 @@ jobs: steps: - uses: actions/checkout@v4 - name: Prepare release + id: prepare shell: bash run: | set -euo pipefail + backend_version="$(sed -n 's/^BACKEND_VERSION = "\(.*\)"$/\1/p' app/version.py)" + case "$backend_version" in + ''|*[!0-9.]*) exit 1 ;; + esac + echo "backend_version=$backend_version" >> "$GITHUB_OUTPUT" tar --exclude=.git --exclude=.env -cf "$RUNNER_TEMP/$RELEASE_NAME" . printf '%s\n' "$PROD_SSH_KEY" > "$RUNNER_TEMP/deploy_key" printf '%s\n' "$PROD_KNOWN_HOSTS" > "$RUNNER_TEMP/known_hosts" @@ -67,10 +73,13 @@ jobs: -o BatchMode=yes \ -o UserKnownHostsFile="$RUNNER_TEMP/known_hosts" \ "$PROD_USER@$PROD_HOST" \ - "PROD_PATH='$PROD_PATH' RELEASE_NAME='$RELEASE_NAME' bash -s" <<'REMOTE' + "PROD_PATH='$PROD_PATH' RELEASE_NAME='$RELEASE_NAME' EXPECTED_BACKEND_VERSION='$EXPECTED_BACKEND_VERSION' bash -s" <<'REMOTE' set -euo pipefail cd "$PROD_PATH" release="$HOME/$RELEASE_NAME" + test -f "$release" + archive_version="$(tar -xOf "$release" ./app/version.py | sed -n 's/^BACKEND_VERSION = "\(.*\)"$/\1/p')" + test "$archive_version" = "$EXPECTED_BACKEND_VERSION" mkdir -p "$HOME/backups/miem_workers" backup="$HOME/backups/miem_workers/miem_workers-$(date +%Y%m%d-%H%M%S).sql" docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > "$backup" @@ -79,7 +88,13 @@ jobs: -v "$PROD_PATH":/dst \ alpine:3.20 sh -c 'tar -xf /src/release.tar -C /dst' docker compose up -d --build - curl --fail --silent --show-error http://127.0.0.1:8000/api/health + runtime_version="$(docker compose exec -T api python -c 'from app.version import BACKEND_VERSION; print(BACKEND_VERSION)')" + test "$runtime_version" = "$EXPECTED_BACKEND_VERSION" + health="$(curl --fail --silent --show-error http://127.0.0.1:8000/api/health)" + case "$health" in + *"\"status\":\"ok\""*"\"backend_version\":\"$EXPECTED_BACKEND_VERSION\""*) ;; + *) echo "Unexpected health response: $health" >&2; exit 1 ;; + esac find "$HOME/backups/miem_workers" -maxdepth 1 -type f -name 'miem_workers-*.sql' ! -path "$backup" -delete docker compose ps rm -f "$release" @@ -87,3 +102,4 @@ jobs: env: PROD_HOST: ${{ secrets.PROD_HOST }} PROD_USER: ${{ secrets.PROD_USER }} + EXPECTED_BACKEND_VERSION: ${{ steps.prepare.outputs.backend_version }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 361b1b3..3253066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## 0.8.12 + +- Передача версии в production deploy ограничена безопасным форматом. + +## 0.8.11 + +- CSS-ассеты админки получают версию в URL и обновляются после релиза без ручной очистки кэша браузера. + +## 0.8.10 + +- Production deploy проверяет совпадение версии release-архива и запущенного API. + ## 0.8.9 - Контейнеры API, worker и PostgreSQL автоматически перезапускаются после остановки или перезагрузки хоста. diff --git a/README.md b/README.md index 00c16ad..40f0eaa 100644 --- a/README.md +++ b/README.md @@ -135,4 +135,4 @@ node --check app/static/admin.js Тесты с данными используют временную SQLite; отдельные API smoke-тесты запускают приложение с его текущей конфигурацией. Браузерная проверка: `pip install playwright`, `python -m playwright install chromium`, затем `python tests/browser_admin.py`. Она проверяет реальный рендеринг страниц, клавиатуру, диалог, фильтры и восстановление прогресса после ошибки. Скриншоты сохраняются во временную папку; путь выводится в конце. -Версия сервиса: `0.8.9`. Админка всегда показывает версии backend и frontend в footer. +Версия сервиса: `0.8.12`. Админка всегда показывает версии backend и frontend в footer. diff --git a/app/templates/base.html b/app/templates/base.html index c7c70e7..bf76f81 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -4,7 +4,7 @@