From d64957dfcd1d47d267d41a1530bd69c97e4e985a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D1=80=D0=BD=D0=B0=D1=82=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Wed, 10 Jun 2026 05:39:50 +0300 Subject: [PATCH] Publish Android 1.3.9 and repair Windows autostart --- Android/qsferaApp/build.gradle | 4 +- PRODUCTION_READINESS.md | 19 ++++---- scripts/repair-windows-autostart.ps1 | 69 ++++++++++++++++++++++++++++ scripts/verify-production-state.ps1 | 6 +-- 4 files changed, 84 insertions(+), 14 deletions(-) create mode 100644 scripts/repair-windows-autostart.ps1 diff --git a/Android/qsferaApp/build.gradle b/Android/qsferaApp/build.gradle index a338266b..170fcad2 100644 --- a/Android/qsferaApp/build.gradle +++ b/Android/qsferaApp/build.gradle @@ -135,8 +135,8 @@ android { testInstrumentationRunner "eu.qsfera.android.utils.OCTestAndroidJUnitRunner" - versionCode = 36 - versionName = "1.3.8" + versionCode = 37 + versionName = "1.3.9" buildConfigField "String", gitRemote, "\"" + getGitOriginRemote() + "\"" buildConfigField "String", commitSHA1, "\"" + getLatestGitHash() + "\"" diff --git a/PRODUCTION_READINESS.md b/PRODUCTION_READINESS.md index bc8a14aa..da222c58 100644 --- a/PRODUCTION_READINESS.md +++ b/PRODUCTION_READINESS.md @@ -22,9 +22,9 @@ Date: 2026-06-08. ## Completed In This Pass - Android release builds now fail fast when release signing variables are missing, so unsigned release artifacts cannot be published by accident. -- Android version was raised to `1.3.8` with `versionCode` `36`. +- Android version was raised to `1.3.9` with `versionCode` `37`. - Android now has QSfera-specific Argus publishing scripts: local upload-keystore generation, signed APK staging, APK metadata verification, debug-certificate rejection, and Argus upload. -- Android `1.3.8`/`36` was published to Argus as `qsfera-mobile` on 2026-06-09. Argus upload returned release id `404c0beb-d5ee-4f17-8f80-c59eb267117f`, package size `12225996`, and SHA-256 `872959380cfbfd858c11f388d430f8ce82ae8a9289a1e40bc8fa5b8d7c3897d8`. +- Android `1.3.9`/`37` was published to Argus as `qsfera-mobile` on 2026-06-10. Argus upload returned release id `53ecc24e-106b-43a5-a39e-ffacd72a43f8`, package size `12226572`, and SHA-256 `cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017`. - Android auto-upload source paths are normalized and new/first source folders start from timestamp `0`, so existing media is eligible for initial backup. - Android auto-upload validates persisted read permission and `DocumentFile.canRead()` before scanning SAF folders. - Android immediate auto-upload scheduling no longer blocks the caller while waiting for WorkManager state. @@ -40,8 +40,9 @@ Date: 2026-06-08. - Windows/Desktop update channel defaults now match the build channel: stable builds default to `stable`, beta builds default to `beta`. - Windows/Desktop CI now validates production release invariants before Windows packaging and requires signing variables for stable tag releases. - Windows/Desktop now has a configured HTTPS update feed at `https://qsfera.kusoft.xyz/desktop/updates/stable.xml`; the feed returned HTTP `200` on 2026-06-08 and contains the XML elements parsed by `Desktop/src/gui/updater/updateinfo.cpp`. +- Windows local autostart was repaired on 2026-06-10 with `scripts/repair-windows-autostart.ps1 -Launch`: the HKCU Run key `QSfera` points to the Craft runtime `bin\qsfera.exe`, required Qt6 runtime DLLs are present there, and `qsfera.exe` started from that path. - Added `scripts/verify-production-state.ps1` as a repeatable live production endpoint gate for the public server status, Android Argus manifest/download, and Desktop update feed. -- `scripts/verify-production-state.ps1 -VerifyAndroidDownload` passed on 2026-06-09: server `edition=stable`/`productversion=7.0.0`, Android `1.3.8`/`36`, downloaded APK size `12225996`, APK SHA-256 `872959380cfbfd858c11f388d430f8ce82ae8a9289a1e40bc8fa5b8d7c3897d8`, and valid Desktop no-update feed. +- `scripts/verify-production-state.ps1 -VerifyAndroidDownload` passed on 2026-06-10: server `edition=stable`/`productversion=7.0.0`, Android `1.3.9`/`37`, downloaded APK size `12226572`, APK SHA-256 `cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017`, and valid Desktop no-update feed. - Added `Server/scripts/verify-rpi-production.sh`, declared a loopback-only Pi metrics port in `Server/docker-compose.rpi5.yml`, and expanded the Raspberry Pi Docker runbook with local/public status checks, container/image checks, Prometheus metrics verification, backup/restore drill steps, and Docker data-root/retention planning. - Added systemd monitoring units for the Pi: `Server/systemd/qsfera-rpi-production-check.service`, `Server/systemd/qsfera-rpi-production-check.timer`, `Server/systemd/qsfera-rpi-production-check-alert@.service`, `Server/systemd/rpi-production-check.env.example`, plus installer `Server/scripts/install-rpi-production-monitoring.sh` and alert helper `Server/scripts/alert-rpi-production-check-failure.sh`. - Deployed the Pi metrics/checker update on 2026-06-09. Before upload, `/mnt/data/qsfera/cloud-server/src/docker-compose.rpi5.yml` was backed up to `/mnt/data/qsfera/backups/docker-compose.rpi5.yml-20260609-181614.bak`; `docker compose -f docker-compose.rpi5.yml up -d` recreated and started `qsfera-cloud-server`; `docker compose ps` reported loopback ports `127.0.0.1:9200->9200/tcp` and `127.0.0.1:9205->9205/tcp`. @@ -62,17 +63,17 @@ Date: 2026-06-08. ## Android Argus Publication Check -- Current public Argus manifest for `https://argus.kusoft.xyz/api/apps/qsfera-mobile/manifest?platform=android&channel=stable` reports release id `404c0beb-d5ee-4f17-8f80-c59eb267117f`, version `1.3.8`, channel `stable`, platform `android`, package kind `apk`, `androidVersionCode` `36`, package size `12225996`, and SHA-256 `872959380cfbfd858c11f388d430f8ce82ae8a9289a1e40bc8fa5b8d7c3897d8`. -- Independent download verification of `https://argus.kusoft.xyz/api/apps/qsfera-mobile/download/latest?platform=android&channel=stable` produced a `12225996` byte APK with the same SHA-256 `872959380cfbfd858c11f388d430f8ce82ae8a9289a1e40bc8fa5b8d7c3897d8`. +- Current public Argus manifest for `https://argus.kusoft.xyz/api/apps/qsfera-mobile/manifest?platform=android&channel=stable` reports release id `53ecc24e-106b-43a5-a39e-ffacd72a43f8`, version `1.3.9`, channel `stable`, platform `android`, package kind `apk`, `androidVersionCode` `37`, package size `12226572`, and SHA-256 `cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017`. +- Independent download verification of `https://argus.kusoft.xyz/api/apps/qsfera-mobile/download/latest?platform=android&channel=stable` produced a `12226572` byte APK with the same SHA-256 `cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017`. - The previously published `1.3.5`/`33` APK matched Argus SHA-256 `b7d5bdcb49527c00983a15849252fa42189dee4287754803c46cf2f32e2130f3`, but `apksigner` reported `CN=Android Debug` with certificate SHA-256 `b86d745cecb01ca24bda03092fe94ca7801678513b97edd1175bcabfdea4e941`. -- The new `1.3.8`/`36` APK is signed by `CN=QSfera Argus Upload, O=QSfera, C=RU` with certificate SHA-256 `ea5c304c78ee333f6586f54c933d986c1f865da9c4e3595f8fe0df274c1ab877`. -- `AppUpdateManager` validates downloaded APK package name, greater `versionCode`, Argus `androidVersionCode`, and signer digest against the installed app signature. Because of that local code path, devices that installed debug-signed `1.3.5` should be treated as needing reinstall or an explicit migration plan before they can move to the production-signed `1.3.8`. +- The new `1.3.9`/`37` APK is signed by `CN=QSfera Argus Upload, O=QSfera, C=RU` with certificate SHA-256 `ea5c304c78ee333f6586f54c933d986c1f865da9c4e3595f8fe0df274c1ab877`. +- `AppUpdateManager` validates downloaded APK package name, greater `versionCode`, Argus `androidVersionCode`, and signer digest against the installed app signature. Because of that local code path, devices that installed debug-signed `1.3.5` should be treated as needing reinstall or an explicit migration plan before they can move to the production-signed `1.3.9`. ## Remaining P0 -- Back up the gitignored Android release signing files created under `Android/signing/` and `Android/argus-signing.local.properties` in a secure external secret store. Without this key material, future in-place Android updates from the production-signed `1.3.8` cannot be signed with the same certificate. +- Back up the gitignored Android release signing files created under `Android/signing/` and `Android/argus-signing.local.properties` in a secure external secret store. Without this key material, future in-place Android updates from the production-signed `1.3.9` cannot be signed with the same certificate. - Provide CI/Argus signing secrets derived from the same release key: `QSFERA_RELEASE_KEYSTORE`, `QSFERA_RELEASE_KEYSTORE_PASSWORD`, `QSFERA_RELEASE_KEY_ALIAS`, and `QSFERA_RELEASE_KEY_PASSWORD`. -- Decide the rollout policy for any devices that installed the debug-signed Argus `1.3.5` APK. The production-signed `1.3.8` APK is the correct current release, but installed debug-signed clients will not satisfy the app's own signer-digest check for an in-place update. +- Decide the rollout policy for any devices that installed the debug-signed Argus `1.3.5` APK. The production-signed `1.3.9` APK is the correct current release, but installed debug-signed clients will not satisfy the app's own signer-digest check for an in-place update. - Fill production domains, ACME email, admin passwords, Keycloak passwords, and storage secrets from a secret manager. Do not commit real values. - Run `./validate-production-env.sh .env` and then `docker compose config` for `Server/devtools/deployments/qsfera_full` with a filled production `.env`; Docker CLI is not available in this local environment, so compose rendering is not locally verified. - Provide real Windows signing secrets in CI: `QSFERA_DESKTOP_SIGN_PACKAGE=True` and `QSFERA_DESKTOP_CODESIGN_CERTIFICATE` with the Craft-compatible signing certificate reference. diff --git a/scripts/repair-windows-autostart.ps1 b/scripts/repair-windows-autostart.ps1 new file mode 100644 index 00000000..b3386b3c --- /dev/null +++ b/scripts/repair-windows-autostart.ps1 @@ -0,0 +1,69 @@ +param( + [string]$RuntimeRoot = "$env:USERPROFILE\craft\CraftMaster\windows-cl-msvc2022-x86_64", + [string]$AppName = "QSfera", + [switch]$Launch +) + +$ErrorActionPreference = "Stop" + +function Fail([string]$Message) { + Write-Error $Message + exit 1 +} + +$runtimeBin = Join-Path $RuntimeRoot "bin" +$runtimeExe = Join-Path $runtimeBin "qsfera.exe" + +if (-not (Test-Path -LiteralPath $runtimeExe)) { + Fail "QSfera executable was not found: $runtimeExe" +} + +$requiredDlls = @( + "Qt6Core.dll", + "Qt6Gui.dll", + "Qt6Widgets.dll", + "Qt6Network.dll", + "Qt6Qml.dll", + "Qt6Quick.dll", + "qt6keychain.dll", + "kdsingleapplication-qt6.dll" +) + +foreach ($dll in $requiredDlls) { + $dllPath = Join-Path $runtimeBin $dll + if (-not (Test-Path -LiteralPath $dllPath)) { + Fail "Required runtime DLL is missing: $dllPath" + } +} + +$runKey = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" +New-ItemProperty -Path $runKey -Name $AppName -PropertyType String -Value $runtimeExe -Force | Out-Null +$actualValue = (Get-ItemProperty -Path $runKey).$AppName + +if ($actualValue -ne $runtimeExe) { + Fail "Autostart registry value was not updated. Expected '$runtimeExe', got '$actualValue'." +} + +Write-Output "OK: $AppName autostart points to $runtimeExe" +Write-Output "OK: required Qt6 runtime DLLs are present in $runtimeBin" + +if ($Launch) { + Get-Process -Name "qsfera" -ErrorAction SilentlyContinue | + Where-Object { $_.Path -ne $runtimeExe } | + Stop-Process -Force -ErrorAction SilentlyContinue + + if (-not (Get-Process -Name "qsfera" -ErrorAction SilentlyContinue | Where-Object { $_.Path -eq $runtimeExe })) { + Start-Process -FilePath $runtimeExe -WorkingDirectory $runtimeBin -WindowStyle Hidden + Start-Sleep -Seconds 5 + } + + $process = Get-Process -Name "qsfera" -ErrorAction SilentlyContinue | + Where-Object { $_.Path -eq $runtimeExe } | + Select-Object -First 1 + + if (-not $process) { + Fail "QSfera did not start from $runtimeExe" + } + + Write-Output "OK: QSfera is running from $($process.Path) with PID $($process.Id)" +} diff --git a/scripts/verify-production-state.ps1 b/scripts/verify-production-state.ps1 index e94da1ac..991370dd 100644 --- a/scripts/verify-production-state.ps1 +++ b/scripts/verify-production-state.ps1 @@ -6,12 +6,12 @@ param( [string]$AndroidManifestUrl = "https://argus.kusoft.xyz/api/apps/qsfera-mobile/manifest?platform=android&channel=stable", [string]$ExpectedAndroidSlug = "qsfera-mobile", [string]$ExpectedAndroidPackageName = "eu.qsfera.android", - [string]$ExpectedAndroidVersion = "1.3.8", - [int]$ExpectedAndroidVersionCode = 36, + [string]$ExpectedAndroidVersion = "1.3.9", + [int]$ExpectedAndroidVersionCode = 37, [string]$ExpectedAndroidChannel = "stable", [string]$ExpectedAndroidPlatform = "android", [string]$ExpectedAndroidPackageKind = "apk", - [string]$ExpectedAndroidSha256 = "872959380cfbfd858c11f388d430f8ce82ae8a9289a1e40bc8fa5b8d7c3897d8", + [string]$ExpectedAndroidSha256 = "cbd2c25328e395ea4da4e0f582feac39dec18d2d47b3e105d344904d8a24f017", [string]$AndroidDownloadUrl = "https://argus.kusoft.xyz/api/apps/qsfera-mobile/download/latest?platform=android&channel=stable", [switch]$VerifyAndroidDownload,