Перейти к содержанию

Десктопные приложения — сборка, подпись, канал загрузки (ops)

Инфраструктура для сборки, подписи и публикации в /download/ десктопных клиентов для macOS и Windows. Обзор кода: macOS desktop, Windows desktop.

Инфраструктура сборки — self-hosted раннеры

WinUI/MSIX не собирается на macOS, а Xcode не работает на Windows, поэтому для каждой платформы используется свой выделенный self-hosted раннер GitHub Actions:

Раннер Хост Метки Workflow
win11-build Windows 11 Pro (38.180.136.249) self-hosted, Windows, X64, windows-signing .github/workflows/windows-app.yml (job selfhosted)
imacpro-macos iMac Pro (macOS 14, Intel) self-hosted, macOS .github/workflows/macos-app.yml

Раннеры работают как службы (автозапуск при перезагрузке) от пользователя deploy. Инструментарий (.NET 8, git, Xcode, xcodegen) установлен на хосте; makeappx/signtool для MSIX берутся из NuGet (Microsoft.Windows.SDK.BuildTools[.MSIX]), поэтому системный Windows SDK не требуется.

Раннер офлайн

Запущенная задача требует, чтобы её раннер был онлайн — если он офлайн, задача ставится в очередь. Статус раннеров: gh api repos/OWNER/REPO/actions/runners.

Канал загрузки — /download/

Деплой использует SSH с forced-command (только ci-deploy.sh), поэтому scp на сервер невозможен. Следовательно, бинарные файлы попадают на сервер только через git-репозиторий (deploy/downloads/):

раннер: сборка + подпись → deploy/downloads/{eid-mongolia.dmg, eid-mongolia-setup.msix, *.cer}
        → git commit + push (main)
staging ci-deploy: git reset --hard origin/main → force-recreate nginx
nginx (deploy/nginx/staging.conf, location ^~ /download/) → /srv/download (монтирование)

Кнопки загрузки на сайте: web/src/components/landing/DesktopAppSection.tsx, web/src/app/solutions/page.tsx.

Размер git-репозитория

Файл .msix (~37 МБ) попадает в историю git при каждой публикации. При частых публикациях переходите на Git LFS (.gitattributes: deploy/downloads/*.msix,*.dmg filter=lfs). На сервере должен быть установлен git-lfs (иначе nginx будет отдавать файл-указатель).

Повторная публикация

Windows: GitHub → Actions → «Windows desktop» → Run workflow (либо gh workflow run windows-app.yml). Job selfhosted выполняет сборку + подпись + публикацию.

macOS: GitHub → Actions → «macOS desktop» → Run workflow (либо gh workflow run macos-app.yml). При workflow_dispatch публикуется .dmg.

Продуктивная подпись

Сейчас: macOS .dmgadhoc (без подписи), Windows .msixсамоподписанный dev-сертификат. Оба устанавливаются, но ОС выводит предупреждение. Для «чистого» публичного распространения:

macOS — Apple Developer ID + нотаризация

Apple Team: CQTHTD6YJQ (Gerege Systems LLC) — тот же, что и для iOS. Добавление следующих GitHub secrets заставит macos-app.yml автоматически подписывать и нотаризовать:

Secret Значение
MACOS_SIGN_IDENTITY Developer ID Application: Gerege Systems LLC (CQTHTD6YJQ)
MACOS_CERT_P12_BASE64 base64 файла .p12 Developer ID Application (base64 -i cert.p12)
MACOS_CERT_PASSWORD пароль от .p12
MACOS_NOTARY_KEY_BASE64 base64 ключа .p8 из App Store Connect API
MACOS_NOTARY_KEY_ID ID ключа API
MACOS_NOTARY_ISSUER_ID Issuer ID

Получение сертификата: developer.apple.com → Certificates → Developer ID Application → экспортировать .p12 из Keychain. Ключ API: App Store Connect → Users and Access → Keys.

Windows — EV/OV сертификат подписи кода

Укажите в -PfxPath скрипта tools/pack-msix.ps1 путь к реальному сертификату (или используйте Azure Trusted Signing), заменив шаг New-DevCert в windows-app.yml. Subject DN сертификата должен в точности совпадать со значением Publisher в Package.appxmanifest (CN=Gerege Systems LLC, O=Gerege Systems LLC, C=MN). С 2023 года сертификат должен храниться на аппаратном токене/HSM, поэтому для CI наиболее удобен вариант Azure Trusted Signing (~$10 в месяц).

Автообновление (ещё не настроено)

  • macOS: Sparkle (SUFeedURL: e-id.mn/download/appcast.xml) — требует scripts/gen_appcast.sh и ключ EdDSA (SPARKLE_ED_PRIVATE_KEY).
  • Windows: .appinstaller (tools/publish-appinstaller.ps1) — положите подписанный .msix и .appinstaller вместе в /download/.