diff --git a/README.md b/README.md index 0b06f6c..46e20c9 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ A custom webhook is also supported. Telegram forwarding is one possible workflow app does not depend on Telegram. **Status:** development preview with notification/SMS capture, a persistent encrypted outbox, -background delivery, automatic retries and a delivery journal. Webhook requests require a Bearer token, stored encrypted on the device. Signed APK release automation is configured; see [Releases](docs/en/releases.md) and [release automation](docs/en/release-automation.md). +background delivery, automatic retries and a delivery journal. Webhook requests require a Bearer token, stored encrypted on the device. Signed APK release automation is configured; see [Releases](docs/en/releases.md) and [release automation](docs/en/release-automation.md), and [release testing](docs/en/release-testing.md). ## Getting started @@ -127,7 +127,7 @@ Fastlane's `debug_artifact` lane builds only the debug APK. `checks` runs JVM/Ro debug/release lint, and builds debug and unsigned release APKs under `app/build/outputs/apk/`. PR CI has no release signing credentials and does not require an emulator. -For signed APK releases, see [Releases](docs/en/releases.md) and [release automation](docs/en/release-automation.md). +For signed APK releases, see [Releases](docs/en/releases.md) and [release automation](docs/en/release-automation.md), and [release testing](docs/en/release-testing.md). Store graphics and their provenance are documented in [Branding](assets/branding/README.md). See the [project context](docs/en/project-context.md) for remaining product decisions. diff --git a/docs/en/release-automation.md b/docs/en/release-automation.md index bbd5fe7..97b2992 100644 --- a/docs/en/release-automation.md +++ b/docs/en/release-automation.md @@ -7,6 +7,8 @@ Run workflow**, choose `main` and enter a new version without `v`. This authoriz squash merge after full CI, and a tag on the verified merged commit. **Release Android artifacts** then signs and publishes the APK. Merging the implementation does not itself release a version. +This flow does not replace [device release acceptance](release-testing.md). + ## One-time manual setup In [Settings → Secrets and variables → Actions](https://github.com/andre487/AndroidMessage487/settings/secrets/actions), add: diff --git a/docs/en/release-testing.md b/docs/en/release-testing.md new file mode 100644 index 0000000..9fcf410 --- /dev/null +++ b/docs/en/release-testing.md @@ -0,0 +1,228 @@ +# Message487 release testing + +[English](release-testing.md) | [Русский](../ru/release-testing.md) + +Test an identified signed release candidate, followed by the published artifact. Green CI, +a successful dry run and a connection test do not replace Android capture testing. +This is a procedure, not a record of completed tests. + +## Results and evidence + +Each scenario on each device receives **PASS**, **FAIL**, **BLOCKED**, **NOT TESTED** or **N/A**. +N/A needs a product/platform reason; missing time or equipment is NOT TESTED. Source review +and JVM tests do not fill device-test cells. Describe exactly what passed in a partial result. + +Record scenario ID, UTC time, commit/APK SHA-256, device/OS, preconditions, action, +expected/actual results, evidence paths, verdict and restoration. Correlate a synthetic marker +and `event_id` across **Journal**, the HTTP request/response and **n8n Executions**. +Negative tests require working controls before and after. Reproduce significant authentication +failures, leaks and data loss twice with fresh markers. + +An accepted ACK confirms the webhook; generic HTTP 2xx confirms only HTTP success. +Neither proves Telegram/downstream delivery. Test downstream separately. Losing the response +may cause multiple executions with the same event ID; exactly-once delivery is not promised. +The fixture/downstream needs ID deduplication where the scenario requires it. + +Keep raw database/UI dumps, logs, captures and n8n executions local in a 0700 directory, +sensitive files 0600. Webhook URLs may contain secrets. Commit only reviewed sanitized +excerpts and synthetic fixtures. Ordinary testing does not authorize sending diagnostic email, +uploading to VirusTotal, publishing issues/releases or modifying an external F-Droid MR. + +## Preparation + +| ID | Procedure and evidence | +| --- | --- | +| A01 | Record candidate commit, changes since the previous release, versionName/code, SDKs, dependency/toolchain versions and APK origin. Read versions from `app/build.gradle.kts`, expected signing identity from `scripts/build-release-apk.sh`. Preserve existing changes; do not change production versionCode just for a test. | +| A02 | Run `bundle exec fastlane android checks`, `PYTHON=.venv/bin/python bundle exec fastlane android python_checks` and, with local n8n running, `bundle exec fastlane android server_tests`. Retain results and CI links for the candidate. PR checks receive no signing configuration. See [Tests and CI](testing.md). | +| A03 | Run `bundle exec fastlane android release_artifacts` or obtain signed artifacts from a build-only mode. Retain SHA256SUMS, `apksigner verify --verbose --print-certs`, `aapt dump badging`, permissions and merged manifest. Verify release/non-debuggable, package/version and existing signing key. Debug builds do not replace this step. | +| A04 | Reconcile source/merged manifest, exported components, FileProvider, backup/data extraction, HTTP restrictions, dependency permissions/licenses. Explain RECEIVE_SMS, notification listener, POST_NOTIFICATIONS, REQUEST_INSTALL_PACKAGES and scheduler components. SMS history/default SMS role, Accessibility and QUERY_ALL_PACKAGES are unnecessary. Match store description/PRIVACY to behavior. | +| A05 | Describe two phones and two dedicated emulators: model, OS/API/OEM build/patch, ABI/page size, display/font/language, package/version/signer/installer, permissions, battery, network, VPN/Private DNS. Emulators cover minimum supported API and a modern API. Without Samsung hardware, its OEM check remains NOT TESTED. | +| A06 | Preserve phone settings and data; use only synthetic SMS and selected probe apps, never personal apps/OTP. Do not uninstall or clear existing data. Reboots, network/PIN changes and destructive checks need applicable authorization; start on dedicated emulators. | +| A07 | Prepare a private HTTPS fixture with a trusted certificate, separate tokens and controlled responses; prove it works directly. [DevServer](../../DevServer/README.md) is an HTTP/debug fixture, so release testing needs HTTPS ingress. Do not expose its public development credentials. Inventory created resources for cleanup. | + +## Execution order + +1. Select the candidate commit and previous signed release for migration. Record + `git status`, `git rev-parse HEAD` and the diff; use a separate clean checkout when + existing work is present. Before publication, test the signed candidate rather than + the latest published APK at the stable URL. +2. Prepare JDK 21, Ruby/Bundler, the Android SDK declared in Gradle, Platform Tools, + Python and Docker. Configure the SDK through `ANDROID_HOME` or `local.properties`. + Run `python3 -m venv .venv`, + `.venv/bin/python -m pip install -r requirements-dev.txt` and `bundle install`. +3. Start fixtures with + `docker compose -f DevServer/compose.yaml up -d --wait --wait-timeout 300` and run A02. + For signed release testing, add private HTTPS ingress with a certificate trusted by + the device and separate authentication; the HTTP fixture alone is insufficient. +4. Build via A03 with the existing key and signing configuration: + `MESSAGE487_KEYSTORE_PATH`, `MESSAGE487_KEY_PASSWORD_FILE`, `MESSAGE487_KEY_ALIAS`. + Never print passwords. Verify `dist/release/SHA256SUMS` and associate every result + with the installed artifact hash. For the F-Droid channel, run the separate official + build below and identify its artifact. +5. Record each device serial/settings. Use `adb -s SERIAL install -r /path/to/candidate.apk`; + fresh installs belong only on empty test devices/profiles. Record + `adb -s SERIAL shell pm path life.andre.message487`, pull the returned path with + `adb -s SERIAL pull` and verify SHA-256. For migration, first install the old signed + APK and create its synthetic pending queue. +6. In **Connection**, enter the full published webhook URL, token without the `Bearer ` + prefix and synthetic device code. Enable n8n confirmation only for the ACK contract + below. Save/send test and correlate Journal/server execution IDs. Then separately + grant SMS/notification access and select only probe apps; run I/C/Q/L/D/U and record + the per-device matrix. +7. After each negative test, restore the working fixture and prove delivery with a fresh + marker. Finally restore devices and complete the report/decision. R01/R02 do not + publish; R03 requires separately authorized publication. + +### Test-server contract + +Accept POST with `Content-Type: application/json` and +`Authorization: Bearer `. JSON includes `schema_version`, `event_id`, +`device_id`, `device_code`, `message_type`, `occurred_at`, `source`, `source_name`, `text`; +notifications add `title`, SMS adds `sender`. Retain these fields and receipt time in +private fixture logs. Use a fresh synthetic marker for each probe. + +With n8n confirmation enabled, return HTTP 2xx and +`{"status":"accepted","event_id":"ID_FROM_REQUEST"}`. The workflow must implement this ACK; +n8n does not supply it automatically. Without confirmation, 2xx is sufficient. Prepare +controlled modes for correct ACK, 500, 401/403, wrong event ID, malformed JSON, a delay +exceeding client timeout and request acceptance with a lost response. A successful +execution without checking the HTTP response does not prove client acceptance. + +Use endpoints A/B with separate tokens to test destination preservation. Positive +controls must use the app, not only curl. Emulator SMS broadcast can be probed with +`adb -s SERIAL emu sms send +15551234567 'Message487 synthetic RUN-ID'`. +The primary notification probe is a normal app with known fields and its own UID; +shell/root is supplemental. Both paths need actual server-request evidence. + +## F-Droid and artifact provenance + +Select the candidate build block for `life.andre.message487` in official +[fdroiddata](https://gitlab.com/fdroid/fdroiddata), recording recipe hash, upstream SHA, +fdroiddata/fdroidserver revisions and any `Binaries`/`AllowedAPKSigningKeys` configuration. +Inspect an external MR's current state and review invitation when conducting an independent +review. A published recipe can also be the target; do not substitute an imagined new build block. + +Use `registry.gitlab.com/fdroid/fdroidserver:buildserver`, recording its actual digest/platform, +supported build user and fdroiddata configuration. In a separate checkout, run applicable +commands supported by the selected official fdroidserver version: + +```sh +fdroid readmeta +fdroid lint life.andre.message487 +fdroid fetchsrclibs life.andre.message487:VERSION_CODE --verbose +fdroid build --verbose --test --scan-binary --on-server --no-tarball life.andre.message487:VERSION_CODE +``` + +Replace VERSION_CODE with the selected recipe's code. Explain necessary supported command +variations. Retain exit codes, source/binary scanner results and APK paths. Never edit the +recipe to obtain PASS. Investigate warnings, including updater/APK downloads, dependencies, +binary assets and applicable [Inclusion Policy](https://f-droid.org/docs/Inclusion_Policy/). + +For reproducible builds, use official binary comparison/signature-copy verification with the +exact upstream APK and allowed certificate. Gradle alone or SHA-256 comparison of differently +signed APKs does not establish reproducibility. See [F-Droid guidance](https://f-droid.org/docs/Reproducible_Builds/). +If the matching upstream APK is not published, record BLOCKED/NOT TESTED; do not publish just +to satisfy a test or claim reproducibility prematurely. + +Install the verified signed artifact for runtime. A local unsigned APK cannot update a signed +installation. Identify F-Droid signing separately when applicable. Read back the installed APK +using `pm path`/`adb pull` and compare its hash on each device. Real F-Droid-client installation +is required to test its update-source path; ADB installation does not prove that path. + +## Device matrix + +Run applicable scenarios on all four devices. Never substitute emulator PASS for a missing phone +result. Destructive database/Keystore failures, APK/time manipulation, process kills, Doze and +artificial responses start on dedicated fixtures. A phone without SMS capability can be N/A with +a reason; emulator SMS does not establish carrier delivery. + +### Installation, permissions and UI + +| ID | Action → expected result | +| --- | --- | +| I01 | Fresh installation on an empty emulator/test profile; two cold starts. Capture off, no apps selected, no personal-data transmission without configuration. Account separately for default automatic update checks. | +| I02 | Upgrade the previous signed release containing synthetic credentials/device code, selections and pending events. Preserve installation ID, settings, pause, queue and original destinations; deliver old and new events. Reinstalling the same version is not migration. | +| I03 | Deny/grant/revoke SMS permission and notification access. Disabled sources cannot capture; no crash/false success; regrant captures only new events. Ordinary notification permission controls update reminders, not listener access. | +| I04 | Exercise restricted settings and notification access after APK install. Samsung: Auto Blocker during installation/upgrade and restore protection. Follow [APK installation](apk-installation.md); unknown-source permission does not resolve every block. | +| I05 | All main screens, Back/Home/rotation, narrow display, large font, EN/RU, light/dark, keyboard and foldable inner/outer screens. Actions/dialogs remain usable. Test colored/themed icons through the actual launcher switch where supported. | + +### Capture and source controls + +| ID | Action → expected result | +| --- | --- | +| C01 | A normal probe app with its own UID posts selected notifications; correlate title/text/time/package/source_name at the server. Unselected app: no event. Shell notification is supplemental, not a normal-UID substitute. | +| C02 | Plain/big text, InboxStyle, empty content, ongoing/group summary, text update. Excluded ongoing/summary/self notifications stay excluded. Existing notifications are not replayed when access is granted. Do not promise content Android redacts. | +| C03 | Select/unselect, manually add launcherless packages, search and Select all. Bulk selection covers the whole list and preserves manual entries; newly installed apps are not automatically selected. Persist across restart; avoid downstream apps that create feedback loops. | +| C04 | Receive synthetic SMS from an authorized test number on a phone. Verify sender/text/time and source `android`; no historical import, default-SMS role or reply. Test multipart, Cyrillic/Unicode and distinct SMS; record actual segmentation/timestamps. | +| C05 | Deduplication on/off/on, restart and upgrade. Identity is package + original timestamp + exact text; a changed timestamp is a new event. Title/sender changes alone do not change identity. Use controlled fixtures/JVM evidence and separate available runtime controls; two commands with different timestamps do not prove suppression. | +| C06 | Disable source/pause during capture/delivery. No new captures; pause also delays queue. An in-flight request may finish. Resume delivers queued events without importing events missed while paused. Repeated manual connection tests are not message-deduplicated. | + +### Webhook, authentication and outbox + +| ID | Action → expected result | +| --- | --- | +| Q01 | Save/test and actual captured events over HTTPS: Bearer header, JSON contract, event ID and matching ACK. Device code persists, installation ID stable. Journal hides bodies. Manual test success does not prove Android capture. | +| Q02 | Correct/wrong/missing/invalid/restored token. Invalid input is not saved; server rejects wrong credentials without client acceptance. Wrong CA/hostname, untrusted self-signed and release HTTP fail. Redirect must not forward body/Authorization. Working before/after controls required. | +| Q03 | Wrong/missing ACK ID/status, malformed/oversized JSON and generic mode without ACK. Invalid ACK with 2xx blocks for manual retry; generic 2xx yields HTTP_SUCCESS. A successful n8n error execution is not accepted delivery. | +| Q04 | Network/timeout and HTTP 408/425/429/5xx retry; other HTTP failures need correction/manual retry. Preserve event ID/body/original URL/token/ACK after recovery. Lost response may duplicate server receipt with the same ID. No exact WorkManager retry-time promise. | +| Q05 | Queue offline events for endpoint A, then switch settings to B. Old events retain A and its credentials; new events use B. UI token rotation does not repair old encrypted envelopes. Use synthetic endpoints; explicitly delete unwanted old events instead of silently rerouting. | +| Q06 | Retry now, delete test records, repeated actions and details during state change. No duplicate local event/lost queue; in-flight entries are not freely deletable. Acceptance removes payload from active records while bounded metadata remains. Logical deletion is not forensic erasure. | +| Q07 | Offline enqueue, process death/rotation/relaunch, network restoration; preserve encrypted payload and delivery, including previous-version queue. Keystore/storage failures on isolated fixtures: no garbage transmission or silent deletion, visible error. Robolectric success does not prove real Keystore. | + +### Lifecycle and background + +| ID | Action → expected result | +| --- | --- | +| L01 | Home/lock/task removal/return with actual capture and server evidence. Two unavailable/available server and offline/online cycles; real phone Wi-Fi/mobile/Wi-Fi separately. ADB reverse and virtual cellular do not prove carrier handover. | +| L02 | Separately exercise process death and `am force-stop` on a dedicated emulator. Force-stop is not a crash. Reopen to recover persisted queue; do not promise events while Android keeps the package stopped. Real LMKD/OOM is separate. | +| L03 | Reboot online/offline, unlock, new SMS/notification; delivery recovery and update preferences/jobs persist. Pre-unlock work is not promised: components are not directBootAware. RUNNING_LOCKED probes are separate from post-unlock results. | +| L04 | Forced Doze/OEM battery restrictions and restoration; pending survives and delivery resumes. Record idle/exemption/network/duration. Forced jobs do not prove natural daily scheduling. Foreground/background soak: at least 15 minutes and several events; longer/day-long tests separate. | +| L05 | Upgrade while queue/capture enabled, then while paused. Preserve decryptability/destination/state; pause/source choices do not change automatically. Test new captures and listener reconnect after installation. | + +### Privacy and diagnostics + +| ID | Action → expected result | +| --- | --- | +| D01 | Synthetic markers in bodies/title/sender/URL/token/device code/IDs/responses; search app/crash/ZIP and available system logs for excluded fields. Some private preferences/metadata lack additional encryption; match PRIVACY rather than promise universal encryption. Database/Keystore inspection only on authorized fixtures. | +| D02 | Refresh/clear/ZIP/mail chooser, cancellation/no mail app. Clearing diagnostics preserves queue. Temporary read-only attachment grants without arbitrary private-data/write access. Stop at the email editor without sending. | +| D03 | Isolated app crash/relaunch: prompt, crash file and ZIP. Debug injection does not establish release-candidate handling; use a reproducible release mechanism if available. Java handler does not cover ANR/native crash/kill. Correlate logcat, exit reason and action. | +| D04 | Normal probe APK tests external intents/broadcasts/provider access: no secrets, private update control or forged SMS receiver access. Verify BIND_NOTIFICATION_LISTENER_SERVICE/BROADCAST_SMS/BIND_JOB_SERVICE and merged components. Shell/root does not prove normal-app isolation. | + +### Updates and release automation + +| ID | Action → expected result | +| --- | --- | +| U01 | Real official/alternative F-Droid client, browser/file-manager and unknown-installer installations; manual choice. Source follows installer/repository capability; choice persists. Merely installed F-Droid does not change browser origin. 404/offline does not switch source. Installer spoofing is only simulation. | +| U02 | New/same/old/malformed metadata, consent/cancel, failed/interrupted APK and size/digest/package/version/signer checks. No download without consent; metadata checks do not depend on download consent. Invalid APKs first in JVM/isolated emulator. Never publish fixture versions or bump production code for tests. | +| U03 | GitHub download then separate Install; deny/grant unknown-source permission, return from Settings, cancel/succeed, rotate/background. Read back APK/version/signer and confirm delivery after upgrade. F-Droid opens its page; client installs. Different signers cannot upgrade one another; uninstall is not the first remedy. | +| U04 | Reminder permission/channel, Open/Skip/Disable, manual after Skip, disable in-flight job, reboot. Simulate time on an emulator for weekly repeats/no early repeats. Forced jobs/time simulation are not natural daily/weekly results. | +| R01 | Dry-run with an explicit proposed version: reads/generates EN/RU without release files/branch/PR/merge/tag/Release. Empty CI input runs normal CI. Compare refs/PRs/releases before/after; label mock and live checks separately. Dry run does not prove writing/signing/ruleset acceptance. | +| R02 | Read EN/RU notes, version/code, history and changed files before release. Gate requires full exact head/base CI; old/skipped CI cannot satisfy it, changed main/head stops merge. Test rejection locally with mocks, not by breaking production rules. | +| R03 | Only after separately authorized publication, verify actual merged commit/tag/tree, published APK provenance/checksum/signer, stable/versioned URLs and both notes. Compare with tested candidate; different artifacts require investigation/retest. F-Droid build/publication remains separate. | + +## Completion and release decision + +Prioritize artifact identity, test/SMS/notification delivery on each device, negative auth/ACK, +offline recovery and migration, followed by lifecycle, updater, privacy and OEM/UI. Reduced +coverage keeps NOT TESTED. A focused follow-up must explain the diff, adjacent regressions and +scope; old phone results never become new-version results simply because UI is unchanged. + +Stop only created fixtures/captures; remove only owned ADB forwards/reverses, probes and synthetic +events. Restore networks, permissions, update source/automatic checks, battery, display/font/language, +Auto Blocker and original app settings. Preserve others' workflows/volumes and personal messages. +Local deletion does not remove n8n/downstream copies; clean synthetic executions separately. +Record leftovers and verify devices after restoration. + +Do not recommend release with queue/secret loss, wrong signing, auth bypass, excluded-data leaks, +unexplained crashes or broken capture/delivery on supported devices. A critical untested migration +or blocked gate means **RELEASE NOT VERIFIED**. State GitHub/F-Droid readiness separately. +Fixes use a minimal separate branch, reproduction/regression test, new APK and affected/adjacent +retests; the old FAIL remains until retest. + +Save a sanitized `docs/reviews/release-YYYY-MM-DD.md` with candidate commit/version/code/hash/signer, +artifact origin, devices, command/CI/F-Droid evidence, scenario/device/verdict matrix, findings and +controls, retest identity, restoration/leftovers and channel-specific decision/blockers/gaps. +Raw material stays local. Test the signed release-PR candidate before publication; configure +human review in [release automation](release-automation.md) to inspect notes before merge. +R03 is additional post-publication verification, not permission to release untested APKs. +No device tests were performed while writing this procedure. diff --git a/docs/en/releases.md b/docs/en/releases.md index 4fcc59c..b421185 100644 --- a/docs/en/releases.md +++ b/docs/en/releases.md @@ -7,6 +7,8 @@ Installing on a phone? See [APK installation and Android restrictions](apk-insta Use [release automation](release-automation.md) to prepare the version and EN/RU changelog. The guide covers manual secret setup and release dispatch. +Before publication, complete [release testing](release-testing.md) on the signed candidate. + Run `bundle exec fastlane android release_artifacts` with JDK 21 and Android SDK 36. The lane runs Android JVM/Compose tests and debug/release lint, then builds a signed release APK. It checks the APK certificate, package/version and non-debuggable flag. diff --git a/docs/en/testing.md b/docs/en/testing.md index b94f701..2725f54 100644 --- a/docs/en/testing.md +++ b/docs/en/testing.md @@ -7,14 +7,15 @@ Run the same suites locally and in GitHub Actions: | Suite | Command | Coverage | | --- | --- | --- | | Android | `bundle exec fastlane android checks` | JVM logic, MockWebServer HTTP integration, Robolectric database/preferences/provider integration, Compose interactions, localization, manifest security, light/dark contrast, debug/release lint and APK builds, unsigned release verification | -| Python | `PYTHON=.venv/bin/python bundle exec fastlane android python_checks` | DevServer HTTP test-client behavior against a local HTTP server; pinned Black/isort style checks | +| Python | `PYTHON=.venv/bin/python bundle exec fastlane android python_checks` | DevServer HTTP test-client behavior against a local HTTP server, release automation with mocked APIs/local Git, pinned Black/isort style checks | | n8n | `bundle exec fastlane android server_tests` | Live receive/validation, notification/SMS/test payloads, HTTP failure, invalid ACK and timeout | For Python, create `.venv` with `python3 -m venv .venv` and install `requirements-dev.txt`. For n8n, first run `docker compose -f DevServer/compose.yaml up -d --wait --wait-timeout 300`. The server suite uses synthetic data and retains it in the development execution history. -`.github/workflows/ci.yml` runs all three jobs on pull requests, main pushes and manual dispatch. +`.github/workflows/ci.yml` runs the three main jobs on pull requests, main pushes and manual dispatch. +Manual dispatch with `release_dry_run_version` runs only the release dry run and skips these suites. Android XML/HTML test and lint reports are uploaded even if a check fails. Successful Android jobs also publish a debug APK and unsigned release APK files. These checks never sign release artifacts. Local success does not establish a GitHub run result for uncommitted/unpushed changes. @@ -25,7 +26,8 @@ The applicable categories match MegaProxy: JVM logic and Android integration, Co under Robolectric, resource/security/UI contracts, Python tests and formatting, lint and builds. Message487 also has a live Docker/n8n integration suite. MegaProxy's Go race tests and optional native-parser fuzz lane apply to its Go/JNI networking core; Message487 has no native core. -MegaProxy's Python CI-history tests target scripts that Message487 does not have. +Message487 has its own release-automation Python tests, but no MegaProxy change classifier +or ancestor-check history lookup. Compose tests use the real navigation, screens, ViewModel and preferences with a test Application that suppresses startup workers and process-wide crash-handler installation. An explicit ViewModel @@ -38,3 +40,5 @@ an Android emulator, following MegaProxy's approach to unreliable KVM availabili Signed release verification runs the Android test/lint suite separately with signing inputs. PR checks reject those inputs and remain unsigned. See [release automation](releases.md). + +For signed candidates, F-Droid and device checks, follow [Release testing](release-testing.md). diff --git a/docs/ru/release-automation.md b/docs/ru/release-automation.md index c2f7162..75833f3 100644 --- a/docs/ru/release-automation.md +++ b/docs/ru/release-automation.md @@ -7,6 +7,8 @@ делает squash merge и ставит тег на слитый коммит. **Release Android artifacts** собирает, подписывает и публикует APK. Само слияние реализации не выпускает новую версию. +Этот флоу не заменяет [приёмку релиза на устройствах](release-testing.md). + ## Что настроить вручную один раз 1. В [Settings → Secrets and variables → Actions](https://github.com/andre487/AndroidMessage487/settings/secrets/actions) diff --git a/docs/ru/release-testing.md b/docs/ru/release-testing.md new file mode 100644 index 0000000..3cc51b7 --- /dev/null +++ b/docs/ru/release-testing.md @@ -0,0 +1,250 @@ +# Проверка релиза Message487 + +[English](../en/release-testing.md) | [Русский](release-testing.md) + +Проверяется конкретный подписанный APK-кандидат, затем опубликованный артефакт. +Зелёный CI, успешный dry-run и тест подключения не заменяют проверку захвата на Android. +Это регламент, а не отчёт о выполненных проверках. + +## Доказательства и статусы + +Каждый сценарий на каждом устройстве получает **PASS**, **FAIL**, **BLOCKED**, +**NOT TESTED** или **N/A**. N/A требует причины, связанной с продуктом или платформой; +отсутствие устройства/времени — NOT TESTED. JVM-тест и анализ исходников не заполняют +ячейку проверки на устройстве. Для частичного результата укажите, что именно выполнено. + +Запись: ID сценария, время UTC, commit и SHA-256 APK, устройство/ОС, предусловия, +действие, expected/actual, ссылки на доказательства, статус и результат восстановления. +Для доставки сопоставьте синтетический маркер и `event_id` в **Журнале**, HTTP-запросе +и **n8n Executions**; проверьте тело и статус ответа. Отрицательный сценарий требует +исправного положительного контроля до и после. Существенные ошибки авторизации, +утечки и потерю данных воспроизводите дважды с новыми маркерами. + +`accepted` означает подтверждение веб-хука, а HTTP 2xx без ACK — только HTTP-успех. +Они не подтверждают Telegram или другой последующий узел: его проверяют отдельно. +Повторная отправка после потери ответа может создать несколько executions с одним +`event_id`; Message487 не обещает exactly-once. Стенд и downstream должны дедуплицировать +по ID, если это требуется сценарию. + +Сырые логи, дампы БД/UI, сетевые захваты и n8n executions держите локально в каталоге +0700, чувствительные файлы — 0600. Даже URL веб-хука может содержать секрет. +В Git включайте только проверенные обезличенные выдержки и синтетические фикстуры. +Не отправляйте диагностическое письмо, не загружайте APK на VirusTotal, не публикуйте +issues/релизы и не меняйте внешний F-Droid MR в рамках обычного тестового прогона. + +## Подготовка + +| ID | Действия и доказательства | +| --- | --- | +| A01 | Зафиксируйте commit кандидата, diff после прошлого релиза, versionName/code, min/target SDK, зависимости/toolchain и точный источник APK. Версия берётся из `app/build.gradle.kts`, подпись — из `scripts/build-release-apk.sh`. Сохраните чужие изменения; не увеличивайте production versionCode ради теста. | +| A02 | Выполните `bundle exec fastlane android checks`, `PYTHON=.venv/bin/python bundle exec fastlane android python_checks`; после запуска локального n8n — `bundle exec fastlane android server_tests`. Сохраните статусы и ссылки CI именно кандидата. Нет signing-переменных в PR-проверках. Инструкции окружения — в [Тесты и CI](testing.md). | +| A03 | Выполните `bundle exec fastlane android release_artifacts` либо получите подписанный артефакт режима сборки без публикации. Сохраните SHA256SUMS, вывод `apksigner verify --verbose --print-certs`, `aapt dump badging`, permissions/merged manifest. APK должен быть release, нужного пакета/версии, с прежним ключом. Debug APK не заменяет этот шаг. | +| A04 | Сверьте исходный и merged manifest, FileProvider, exported-компоненты, backup/data extraction, ограничения HTTP, разрешения зависимостей и изменения лицензий. Объясните RECEIVE_SMS, notification listener, POST_NOTIFICATIONS, REQUEST_INSTALL_PACKAGES и компоненты планировщиков. Не требуются SMS history, default SMS role, Accessibility, QUERY_ALL_PACKAGES. Сверьте описание/PRIVACY с поведением. | +| A05 | Опишите два телефона и два выделенных эмулятора: модель, ОС/API/OEM build/patch, ABI/размер страницы, экран/шрифт/язык, пакет/версия/подпись/installer, разрешения, батарея, сеть, VPN/Private DNS. Эмуляторы — минимальный поддерживаемый API и современный. Если Samsung недоступен, OEM-проверка остаётся NOT TESTED. | +| A06 | На телефонах сохраните исходные настройки, используйте только синтетические SMS и выбранные тестовые приложения. Не включайте захват личных приложений/OTP. Не удаляйте существующую установку и не очищайте её данные. Перезагрузка, смена сети/PIN и разрушительные проверки требуют применимого разрешения; выполняйте их сначала на выделенном эмуляторе. | +| A07 | Поднимите закрытый HTTPS-стенд с доверенным сертификатом, отдельными токенами и контролируемыми ответами. Проверьте стенд прямым запросом. Локальный [DevServer](../../DevServer/README.md) — HTTP/debug-фикстура, не проверка release HTTPS; для кандидата нужен HTTPS-вход. Не публикуйте стенд с общедоступными тестовыми реквизитами. Запишите ресурсы для последующей очистки. | + +## Порядок выполнения + +1. Выберите commit кандидата и предыдущий подписанный релиз для миграции. Сохраните + `git status`, `git rev-parse HEAD` и diff; работайте в отдельном чистом checkout, + если в рабочем каталоге есть чужие изменения. Для теста до выпуска используйте + подписанный кандидат, а не последний опубликованный APK с постоянной ссылки. +2. Подготовьте JDK 21, Ruby/Bundler, Android SDK из Gradle-конфигурации, Platform Tools, + Python и Docker. SDK задайте через `ANDROID_HOME` или локальный `local.properties`. + Для Python: `python3 -m venv .venv`, затем + `.venv/bin/python -m pip install -r requirements-dev.txt`; для Ruby — `bundle install`. +3. Запустите локальный стенд: + `docker compose -f DevServer/compose.yaml up -d --wait --wait-timeout 300`. + Выполните команды A02. Это проверка фикстур; для signed release настройте закрытый + HTTPS-вход с сертификатом, которому доверяет телефон, и отдельной авторизацией. +4. Соберите кандидат командой A03, используя прежний ключ и signing-конфигурацию + `MESSAGE487_KEYSTORE_PATH`, `MESSAGE487_KEY_PASSWORD_FILE`, `MESSAGE487_KEY_ALIAS`. + Не печатайте пароли. Проверьте `dist/release/SHA256SUMS`; каждый последующий результат + должен ссылаться на hash установленного кандидата. При F-Droid-канале выполните + отдельный официальный build ниже и идентифицируйте его артефакт. +5. Для каждого устройства запишите serial/параметры и исходные настройки. Выберите + нужный serial в `adb -s SERIAL`; установите кандидат через + `adb -s SERIAL install -r /path/to/candidate.apk`. Чистая установка допустима только + на пустом тестовом устройстве/профиле. Сохраните `adb -s SERIAL shell pm path life.andre.message487`, скачайте выведенный путь через `adb -s SERIAL pull` и сравните + SHA-256. Для migration сначала установите старый signed APK и создайте тестовую очередь. +6. На экране **Подключение** задайте полный опубликованный webhook URL, токен без + префикса `Bearer ` и синтетический код устройства; включите n8n confirmation только + для стенда с описанным ниже ACK. Нажмите Save/send test, сопоставьте ID в Журнале + и серверном execution. Затем отдельно разрешите SMS/notification access и выберите + только тестовые приложения; выполните I/C/Q/L/D/U, фиксируя матрицу по устройствам. +7. После каждого отрицательного сценария верните рабочий стенд и подтвердите доставку + новым маркером. В конце восстановите устройства, заполните отчёт и решение. + R01/R02 не выпускают версию; R03 выполняется только после отдельно разрешённой публикации. + +### Контракт тестового сервера + +Сервер принимает POST с `Content-Type: application/json` и +`Authorization: Bearer <тестовый токен>`. JSON содержит `schema_version`, `event_id`, +`device_id`, `device_code`, `message_type`, `occurred_at`, `source`, `source_name`, `text`; +уведомление добавляет `title`, SMS — `sender`. Сохраните эти поля и время приёма +в закрытом журнале стенда. Для каждой пробы используйте новый синтетический маркер. + +При включённом n8n confirmation успешный ответ — HTTP 2xx и +`{"status":"accepted","event_id":"ID_ИЗ_ЗАПРОСА"}`. Такой ACK настраивается workflow, +а не возникает автоматически от самого n8n. При выключенном confirmation достаточно 2xx. +Подготовьте управляемые режимы: корректный ACK, 500, 401/403, чужой event_id, malformed +JSON, задержка дольше клиентского timeout и приём запроса с потерей ответа. +Запись успешного execution без проверки HTTP-ответа не доказывает принятие клиентом. + +Для раздельной проверки адресатов используйте endpoints A/B с разными тестовыми токенами. +Положительный контроль отправляйте через приложение, а не только curl. На эмуляторе +`adb -s SERIAL emu sms send +15551234567 'Message487 synthetic RUN-ID'` даёт отдельную +пробу SMS broadcast. Для уведомлений основная проверка — обычное приложение, создающее +уведомление с известными полями и собственным UID; shell/root используется только +дополнительно. Оба пути должны подтверждаться реальным серверным запросом. + +## F-Droid и происхождение APK + +В [fdroiddata](https://gitlab.com/fdroid/fdroiddata) выберите build block именно +кандидата для `life.andre.message487`, зафиксируйте recipe SHA, upstream SHA, +fdroiddata/fdroidserver revisions, `Binaries` и `AllowedAPKSigningKeys`, если заданы. +Для внешнего MR проверяйте его текущее состояние; при независимом review требуется +соответствующее приглашение к review. Существующий опубликованный рецепт тоже допустим +как цель проверки; не заменяйте его предполагаемым новым build block. + +Используйте официальный `registry.gitlab.com/fdroid/fdroidserver:buildserver`, запишите +фактический digest/platform, штатного пользователя сборки и конфигурацию fdroiddata. +В отдельном checkout выполните применимые команды поддерживаемой версии fdroidserver: + +```sh +fdroid readmeta +fdroid lint life.andre.message487 +fdroid fetchsrclibs life.andre.message487:VERSION_CODE --verbose +fdroid build --verbose --test --scan-binary --on-server --no-tarball life.andre.message487:VERSION_CODE +``` + +`VERSION_CODE` заменяется кодом из выбранного recipe. Объясните отличие команды, +если его требует официальное окружение. Сохраните exit codes, source/binary scanner +results и путь APK. Не изменяйте recipe для получения PASS. Предупреждения исследуйте, +а не объявляйте автоматически блокерами; отдельно проверьте updater/APK downloads, +зависимости, бинарные assets и применимость [Inclusion Policy](https://f-droid.org/docs/Inclusion_Policy/). + +При воспроизводимой сборке выполните официальный механизм binary comparison/signature-copy +с точным upstream APK и разрешённым сертификатом. Обычный Gradle build и сравнение +SHA-256 APK с разными подписями не заменяют эту проверку. +[Руководство F-Droid](https://f-droid.org/docs/Reproducible_Builds/). +Если matching upstream APK ещё не опубликован, проверка BLOCKED/NOT TESTED; +не публикуйте релиз только ради теста и не объявляйте воспроизводимость заранее. + +Для runtime установите именно проверенный подписанный APK; локальный unsigned результат +не обновляет прежнюю signed установку. Если проверяется подпись F-Droid, идентифицируйте +её отдельно. Прочитайте установленный APK через `pm path`/`adb pull` и сверяйте hash +с ожидаемым артефактом на каждом устройстве. Реальная установка клиентом F-Droid нужна +для проверки источника обновлений; установка через ADB не доказывает этот путь. + +## Матрица устройств + +Сценарии ниже выполняйте на всех четырёх устройствах, где применимы. Для сценария, +недоступного на телефоне, не подставляйте PASS эмулятора. Деструктивные сбои БД/Keystore, +подмену APK/времени, process kill, Doze и искусственные ответы сначала проверяйте +на выделенном стенде. На телефоне без возможности SMS используйте N/A с причиной; +эмуляторная SMS не доказывает доставку от оператора. + +### Установка, разрешения и UI + +| ID | Действие → требуемый результат | +| --- | --- | +| I01 | Чистая установка в пустой эмулятор/тестовый профиль; два холодных запуска. Захват SMS и уведомлений выключен, приложения не выбраны; без настройки нет отправки личных данных. Автопроверка обновлений — отдельная функция, её запросы учитывайте отдельно. | +| I02 | Установите предыдущий signed релиз, сохраните синтетические URL/токен/код устройства, выбор источников и недоставленные события, затем обновите до кандидата без удаления. Сохраняются настройки, installation ID, пауза, очередь и старые адресаты; выполните новую доставку и доставку старой очереди. Переустановка той же версии не является миграцией. | +| I03 | Отказать → выдать → отозвать RECEIVE_SMS и notification access. Нет захвата отключённого источника, нет падения/ложного статуса; повторное разрешение восстанавливает захват только новых событий. Разрешение обычных уведомлений относится к напоминаниям обновлений, а не notification listener. | +| I04 | Restricted settings после APK-install: официальный путь разрешения, повторное открытие notification access. На Samsung — Auto Blocker при первой установке и обновлении, возврат защиты после теста. См. [установку APK](apk-installation.md). Не считать разрешение unknown sources решением любой блокировки. | +| I05 | Обзор/Подключение/Источники/Журнал/Диагностика/Обновления; Back/Home, rotation, узкий экран, большой шрифт, EN/RU, светлая/тёмная тема, клавиатура, внешний/внутренний экран складного телефона. Действия и длинные диалоги доступны. Цветная и themed launcher icon проверяются реальным переключателем лаунчера, где поддерживается. | + +### Захват и управление источниками + +| ID | Действие → требуемый результат | +| --- | --- | +| C01 | Обычное тестовое приложение с собственным UID публикует выбранное уведомление; независимая сверка title/text/time/package/source_name на сервере. Повторить с невыбранным приложением: нет события. Shell notification — дополнительная проба, не замена обычного UID. | +| C02 | Обычный текст, big text, строки InboxStyle, пустое содержимое, ongoing и group summary; обновление текста уведомления. Исключённые ongoing/summary/свои уведомления не пересылаются. Уже существующее уведомление при выдаче доступа не воспроизводится. Не обещать доступ к скрытому Android содержимому. | +| C03 | Выбор/снятие приложения, ручной пакет без launcher, поиск и «Выбрать все». Массовый выбор действует на весь список, сохраняет ручные пакеты; установленное позже приложение не выбирается само. UI-перезапуск сохраняет выбор. Не выбирайте приложение, получающее downstream сообщения: возможен цикл. | +| C04 | На телефоне получите синтетическую SMS с другого разрешённого тестового номера. Проверьте sender/text/occurred_at и source `android`; история SMS не импортируется, приложение не становится default SMS и не отправляет ответ. Отдельно — длинная multipart SMS, кириллица/Unicode и две разные SMS. Зафиксируйте сегментацию/время, а не только длину строки. | +| C05 | Дедупликация включена/выключена/включена, перезапуск и обновление. Ключ — source package + исходный timestamp + точный text; другой timestamp означает новое событие даже при одинаковом тексте. Изменение title/sender само по себе не меняет ключ. Управляемую идентичность события проверяйте фикстурой/JVM и отдельно runtime с доступными контролями; не выводите PASS из двух команд с разным временем. | +| C06 | Отключение источника и пауза при захвате/отправке. Нет новых событий после отключения/паузы; пауза также задерживает старую очередь. Уже выполняющийся запрос может завершиться. После Resume старые события доставляются, пропущенные во время паузы не импортируются. Две ручные проверки подключения не должны подавляться дедупликацией сообщений. | + +### Веб-хук, авторизация и очередь + +| ID | Действие → требуемый результат | +| --- | --- | +| Q01 | Save/send test, затем реальные capture events через HTTPS. Правильный Bearer в Authorization, JSON schema/поля, уникальный event_id и совпадающий ACK. Device code сохраняется, installation ID стабилен. Journal не показывает тело сообщения. Успех ручного test не доказывает RECEIVE_SMS или listener. | +| Q02 | Правильный → неверный → отсутствующий/некорректный → восстановленный токен. Невалидный ввод не сохраняется; сервер отклоняет неправильный, UI не показывает принятие. Неверная TLS CA/hostname, self-signed без доверия и HTTP в release отклоняются. Редирект не пересылает тело/Authorization на новый адрес. Держите положительные контроли до/после. | +| Q03 | n8n ACK: чужой/отсутствующий event_id, неверный status, malformed/слишком большой JSON; generic webhook с ACK выключенным. HTTP 2xx с неверным ACK — BLOCKED и ручной retry, а generic 2xx — HTTP_SUCCESS. Отличайте отказ клиента от успеха выполнения n8n error-workflow. | +| Q04 | Timeout/network failure, HTTP 408/425/429/5xx → очередь повторяет; прочие HTTP failures → ручное исправление/retry. После восстановления сохраняются event_id, тело, старый URL/токен/ACK. Ответ потерян после приёма: возможен повтор на сервере, ID прежний. Нет обещания точного времени WorkManager retry. | +| Q05 | Создайте offline очередь на endpoint A, смените настройку на B. Старые события идут только на A с прежними реквизитами; новые — на B. Ротация токена в UI не исправляет старый encrypted envelope. Используйте отдельные тестовые endpoints; при необходимости старые события явно удаляют, а не тихо перенаправляют. | +| Q06 | Retry now, удаление тестовой записи, быстрые повторные действия и открытый detail при смене состояния. Нет дублирования локального события/потери очереди; активную отправку нельзя удалить как свободную запись. После acceptance payload удаляется из активной записи, metadata остаётся ограниченной; logical delete не доказывает физическое стирание. | +| Q07 | Offline enqueue → обычное завершение процесса/rotation/relaunch → восстановление сети. Проверить сохранность encrypted payload и доставку, включая очередь предыдущей версии. Недоступный Keystore/повреждённое хранилище — изолированный сценарий: нет отправки мусора или тихого удаления; ошибка видна. Успех Robolectric не доказывает настоящий Keystore. | + +### Жизненный цикл и фон + +| ID | Действие → требуемый результат | +| --- | --- | +| L01 | Home, блокировка экрана, удаление задачи и возвращение: новый capture и доставка с серверным доказательством. Два цикла сервер unavailable → available и offline → online; отдельно реальный Wi-Fi → мобильная → Wi-Fi на телефоне. ADB reverse/виртуальная cellular не доказывают handover оператора. | +| L02 | На выделенном эмуляторе отдельно process death и `am force-stop`. Force-stop — системная остановка, не креш. После неё открыть приложение и проверить восстановление сохранённой очереди; не обещать захват событий, потерянных пока Android держал пакет stopped. Настоящий LMKD/OOM — отдельная проверка. | +| L03 | Reboot при доступной/недоступной сети, разблокировка и новая SMS/notification; delivery recovery и источник/расписание обновлений сохраняются. Работу до первого unlock не считать обещанной: компоненты не заявлены directBootAware. Пробу в RUNNING_LOCKED фиксировать отдельно от результата после unlock. | +| L04 | Forced Doze и OEM battery restriction, затем восстановление нормального режима; pending сохраняется, доставка возобновляется. Записать actual idle/exemption/network и длительность. Forced job не доказывает естественное суточное расписание. Foreground/background soak — не менее 15 минут с несколькими событиями; более длительные/суточные прогоны отмечать отдельно. | +| L05 | Обновление APK при очереди и включённых источниках, затем при паузе. Сохраняется decryptability/адресат/состояние; пауза не снимается, источник не включается сам. Проверить новые события после установки и listener reconnect. | + +### Приватность и диагностика + +| ID | Действие → требуемый результат | +| --- | --- | +| D01 | Синтетические маркеры в body/title/sender/URL/token/device code/ID/response. Искать в app logs, crash file, ZIP и доступных системных логах; нет утечки исключаемых полей. Часть private preferences и delivery metadata не имеет дополнительного шифрования — сверять с PRIVACY, а не обещать полное шифрование данных. Проверка SQLite/Keystore только на разрешённом стенде. | +| D02 | Диагностика refresh/clear/ZIP/email chooser, Cancel и отсутствие mail app. Очистка логов не удаляет очередь. FileProvider даёт временное чтение выбранного вложения без произвольного доступа к данным/записи. Остановитесь на редакторе письма, ничего не отправляя. | +| D03 | На выделенном эмуляторе вызвать app crash и повторный запуск: prompt, crash file, ZIP. Debug injection — отдельное доказательство, не PASS release-candidate crash handling. Проверить release crash, если воспроизводимый механизм доступен. ANR/native crash/kill не считать обработанными Java handler. Сопоставить logcat, exit reason и действия. | +| D04 | Обычным probe APK попробовать чужие intents/broadcasts/provider access: нет доступа к секретам, управления приватными update actions или подделки SMS защищённому receiver. Проверить BIND_NOTIFICATION_LISTENER_SERVICE/BROADCAST_SMS/BIND_JOB_SERVICE и merged components. Shell UID/root не доказывают изоляцию от обычного приложения. | + +### Обновления и релизный флоу + +| ID | Действие → требуемый результат | +| --- | --- | +| U01 | Реальные установки официальным/сторонним F-Droid клиентом, браузером/файловым менеджером, неизвестным установщиком; ручной выбор. Источник следует installer и поддержке repo links, выбор сохраняется. Просто установленный F-Droid не меняет browser installation. 404/offline не переводят на другой источник. Подмена installer metadata — только моделирование. | +| U02 | Новая/та же/старая/повреждённая metadata; consent/Cancel download, ошибка/обрыв/size/digest/package/version/signer. Без согласия нет APK download, проверка обновлений от согласия не зависит. Неверные APK сначала JVM/изолированный эмулятор. Fixture-версии не публиковать и production versionCode не менять ради проверки. | +| U03 | GitHub download → отдельное Install, отказ/выдача unknown-source permission, возврат из Settings, Cancel/успех, rotation/background. Сверить установленную версию/hash/подпись и доставку после установки. F-Droid открывает страницу, установку выполняет клиент. Разные подписи не обновляют друг друга; не удалять приложение как первое «исправление». | +| U04 | Reminder permission/channel, Open/Skip/Disable, manual check после Skip, выключение при running job, reboot. Проверить повтор через неделю и отсутствие раннего повторения управляемым временем на эмуляторе. Принудительный запуск и simulation не считать естественным daily/weekly результатом. | +| R01 | Dry-run с явно заданной предполагаемой версией: генерация EN/RU и проверки чтения, без файлов/релизной ветки/PR/merge/tag/Release. Пустое поле CI означает обычный CI. Перед/после сравнить refs/PR/releases; mock-тест и live run отметить отдельно. Dry-run не доказывает права записи, signing или прохождение ruleset. | +| R02 | Перед реальным выпуском прочитать EN/RU changelog, сравнить versionName/code, историю и список файлов релизного PR. Gate должен ждать полный CI конкретного head/base; старый/skipped CI не принимается, изменённый main/head останавливает merge. Эти отказные случаи тестировать локально с mocks, не ломая production правила. | +| R03 | Только после отдельного запуска выпуска проверить фактический merged commit/tag, tree и источник опубликованных APK, checksum/подпись, постоянный и versioned URL, changelog обеих локалей. Сверить APK с проверенным кандидатом; различающийся артефакт требует расследования/retest. F-Droid build/publication подтверждается отдельно. | + +## Завершение и решение + +Сначала APK identity, доставка test/SMS/notification на каждом устройстве, отрицательная +авторизация/ACK, offline recovery и migration. Затем фон, updater, приватность и OEM/UI. +При сокращении матрицы оставляйте NOT TESTED; оно не становится PASS. Для небольшого +follow-up опишите diff, обязательные соседние регрессии и границы сокращённого прогона. +Старые phone results не переносите на новую версию даже при неизменённом UI. + +В конце остановите только созданные стенды/captures, удалите только свои ADB forwards/reverses, +probe APK и синтетические события; верните сеть, permissions, источник/автопроверку, +батарею, экран/шрифт/язык, Auto Blocker и исходные настройки приложения. Не удаляйте +чужие workflow/volumes и личные сообщения. Удаление локального события не удаляет +копию из n8n/downstream: очистите синтетические executions отдельно. Запишите остаточные +изменения и проверьте устройства после восстановления. + +Не рекомендовать выпуск при потере очереди/секретов, неверной подписи, обходе авторизации, +утечке исключаемых данных, необъяснённых падениях или неработающем захвате/доставке +на поддерживаемом устройстве. Критическая непроверенная миграция или BLOCKED gate +означают **РЕЛИЗ НЕ ПРОВЕРЕН**. Для каналов GitHub и F-Droid фиксируйте отдельную готовность. +Исправление: минимальная отдельная ветка, воспроизведение/регрессионный тест, новый APK, +повтор affected и соседних сценариев; старый FAIL остаётся до retest. + +Отчёт — `docs/reviews/release-YYYY-MM-DD.md`, только обезличенный материал: + +```text +Кандидат: commit, версия/код, SHA-256, сертификат, канал/происхождение APK +Окружение и устройства: фактические параметры и ограничения +Команды/CI/F-Droid: версии инструментов, recipe/image digest, результаты +Матрица: ID | устройство | PASS/FAIL/BLOCKED/NOT TESTED/N/A | доказательства +Находки: expected/actual, серьёзность, контроли, функция, retest commit/APK +Восстановление: ресурсы, что удалено/возвращено, остаточные изменения +Решение: готовность GitHub/F-Droid, blockers и непроверенные сценарии +``` + +До публикации устройство должно проверять подписанный кандидат из релизного PR; +для проверки changelog до merge нужен human review gate в [релизном флоу](release-automation.md). +Постпубликационный R03 — дополнительная проверка, а не разрешение выпускать непроверенный APK. +В рамках подготовки этого регламента тесты на устройствах не выполнялись. diff --git a/docs/ru/releases.md b/docs/ru/releases.md index 2fbdd06..79e9121 100644 --- a/docs/ru/releases.md +++ b/docs/ru/releases.md @@ -7,6 +7,8 @@ Подготовку версии и EN/RU changelog выполняет [автоматизация релиза](release-automation.md). Там же описаны ручная настройка секретов и запуск выпуска. +Перед публикацией пройдите [проверку релиза](release-testing.md) на подписанном кандидате. + Запустите `bundle exec fastlane android release_artifacts` с JDK 21 и Android SDK 36. Lane выполняет JVM/Compose-тесты и debug/release lint, затем собирает подписанный release APK. Проверяются сертификат, пакет, версия и отсутствие debug-флага APK. diff --git a/docs/ru/testing.md b/docs/ru/testing.md index c947237..c89bbd4 100644 --- a/docs/ru/testing.md +++ b/docs/ru/testing.md @@ -7,7 +7,7 @@ | Набор | Команда | Что проверяется | | --- | --- | --- | | Android | `bundle exec fastlane android checks` | JVM-логика, HTTP через MockWebServer, БД/настройки/provider через Robolectric, Compose UI, локализация, манифест, контраст обеих тем, debug/release lint и сборки, отсутствие release-подписи | -| Python | `PYTHON=.venv/bin/python bundle exec fastlane android python_checks` | HTTP-клиент тестового сервера на локальном HTTP-стенде, форматирование закреплёнными Black/isort | +| Python | `PYTHON=.venv/bin/python bundle exec fastlane android python_checks` | HTTP-клиент тестового сервера на локальном HTTP-стенде, релизная автоматизация с mock API и локальным Git, форматирование закреплёнными Black/isort | | n8n | `bundle exec fastlane android server_tests` | Приём test/notification/SMS, валидация, HTTP-ошибка, неверный ACK и таймаут на живом сервере | Для Python создайте `.venv` командой `python3 -m venv .venv` и установите @@ -15,7 +15,9 @@ `docker compose -f DevServer/compose.yaml up -d --wait --wait-timeout 300`. Серверные проверки используют синтетические данные и сохраняют их в истории execution. -`.github/workflows/ci.yml` запускает все три job на PR, push в main и вручную. +`.github/workflows/ci.yml` запускает три основных job на PR, push в main и вручную. +При ручном запуске с `release_dry_run_version` выполняется только dry-run релиза; +основные наборы в этом режиме пропускаются. XML/HTML-отчёты Android-тестов и lint загружаются и при ошибках. Успешный Android-job также публикует debug APK и неподписанные release APK. Подпись release в этих проверках не используется. Локальный успех не подтверждает результат GitHub для неотправленных изменений. @@ -25,8 +27,8 @@ XML/HTML-отчёты Android-тестов и lint загружаются и п Совпадают применимые категории: JVM-логика, Android-интеграция, Compose через Robolectric, контракты ресурсов/безопасности/UI, Python и форматирование, lint и сборки. Message487 дополнительно проверяет живой Docker/n8n. Go race-тесты и необязательный fuzz-lane -MegaProxy относятся к его Go/JNI-коду; здесь такого кода нет. Его Python-тесты истории -CI относятся к скриптам, которых в Message487 нет. +MegaProxy относятся к его Go/JNI-коду; здесь такого кода нет. У Message487 есть отдельные Python-тесты релизной автоматизации; +классификатора изменений и поиска прошлых успешных проверок MegaProxy здесь нет. Compose-тесты используют настоящую навигацию, экраны, ViewModel и настройки с тестовым Application без запуска Worker и установки глобального обработчика крешей. Явная @@ -41,3 +43,6 @@ Application без запуска Worker и установки глобальн Подписанная release-сборка отдельно запускает Android-тесты и lint с signing-переменными. PR-проверки отвергают эти переменные и остаются неподписанными. См. [релизы](releases.md). + +Полный регламент проверки подписанного кандидата, F-Droid и устройств — +[Проверка релиза](release-testing.md).