Skip to content

Runbook — релиз и публикация APK

Audience: operator. Описывает текущий ручной поток. Механизация пайплайна ведётся отдельно (GitLab issue #11) — здесь именно то, что делается руками сегодня.

Подписной keystore — секрет; см. runbook секретов. Никогда не печатать пароль keystore.

Поток (сборка → подпись → публикация)

plantuml Diagram

1. Сборка (на worker)

APK собирается на воркере по проверенному рецепту: JDK21 + bindgen-sysroot env-переменные (нужны для aws-lc-sys). Раскладка Tauri: backend/ + фронт frontend/ (nx). Debug-артефакт ~684 MB → strip → ~32 MB. (Детальный build-рецепт — во внутренней памяти команды android-apk-build-recipe; здесь — операционный обзор.)

2. Подпись

С версии 0.5.1 действует РОТИРОВАННЫЙ ключ (release-key-v2, issue #90). Источник подписи для 0.5.1 и новееrelease-key-v2.jks.age + release-key-v2.creds.age (alias + пароль) из kontinuum/secrets. Старый release-key.jks.ageтолько архив для воспроизводимости 0.5.0; в репозитории kontinuum-app ключа больше нет.

bash
cd ~/secrets-repo
age -d -i ~/.git-key release-key-v2.jks.age > /tmp/release-key.jks
# alias + пароль (НЕ печатать в лог):
ALIAS=$(age -d -i ~/.git-key release-key-v2.creds.age | sed -n 's/^alias=//p')
PASS=$(age -d -i ~/.git-key release-key-v2.creds.age | sed -n 's/^storepass=//p')
# подписать собранный APK этим keystore (apksigner --ks /tmp/release-key.jks
# --ks-key-alias "$ALIAS" --ks-pass "pass:$PASS"), затем:
unset PASS
shred -u /tmp/release-key.jks

РОТАЦИЯ ЛОМАЕТ IN-PLACE ОБНОВЛЕНИЕ (0.5.0 → 0.5.1)

Подписной серт у 0.5.1 другой (новый ключ). Android требует совпадения подписи для in-place апдейта, поэтому пользователи 0.5.0 один раз переустановят приложение при переходе на 0.5.1 (self-update не сработает — клиент отклонит APK с чужой подписью). Отметь это явно в release notes 0.5.1. Начиная с 0.5.1 и далее in-place обновление снова работает (ключ стабилен).

signing key = crown jewel

Ключ подписи = возможность выпускать обновления для установленной базы. Потеря или утечка боевого ключа = невозможность апдейтить эту базу. Боевой ключ хранится только зашифрованным в kontinuum/secrets (release-key-v2.jks.age); копия приватного age-ключа (~/.git-key) off-machine = его страховка. В git-репозитории приложения ключа нет (был утечкой со слабым паролем — issue #90, закрыт #29).

3. sha256

bash
sha256sum kontinuum-<ver>-arm64.apk

4. Публикация (на aruba1)

Скопировать APK на update-endpoint и записать latest.json:

bash
scp kontinuum-<ver>-arm64.apk root@94.177.204.91:<updates-static-root>/
# затем на aruba1 записать latest.json (схема ниже)

latest.json (текущая схема, живой пример):

json
{
  "versionCode": 4000,
  "versionName": "0.4.0",
  "url": "https://updates.kontinuum.cloud/kontinuum-0.4.0-arm64.apk",
  "sha256": "<sha256 опубликованного APK>",
  "notes": "<человекочитаемые release notes>",
  "minSdk": 24
}

5. Проверка

bash
curl -s https://updates.kontinuum.cloud/latest.json     # видна новая версия?
# приложение само сверяет sha256 при self-update — sha256 в json ОБЯЗАН
# совпадать с опубликованным APK, иначе клиент отклонит обновление.

Инфраструктура канала

Раздачей занимается kontinuum-updates-static.service (python static 127.0.0.1:8088) за cloudflared.service на aruba1 — см. runbook туннелей §2. Если latest.json не виден снаружи — сначала проверить эти два юнита.

Чек-лист релиза

  • [ ] APK собран на worker (JDK21 + bindgen env), stripped.
  • [ ] Подписан release-key-v2 (0.5.1+); расшифрованная копия shred-нута.
  • [ ] (если первый релиз на новом ключе) release notes явно предупреждают о переустановке.
  • [ ] sha256 посчитан.
  • [ ] APK + latest.json (с верным sha256) опубликованы на aruba1.
  • [ ] curl latest.json снаружи показывает новую версию.
  • [ ] Установка self-update на устройстве проходит (sha256 совпал).