diff --git a/docs/en/release-testing.md b/docs/en/release-testing.md index ca5e264..98dbcb0 100644 --- a/docs/en/release-testing.md +++ b/docs/en/release-testing.md @@ -37,13 +37,14 @@ scans public signed APKs separately; see [release automation](release-automation | ID | Procedure and acceptance evidence | | --- | --- | | A01 | Record clean candidate source commit, dirty paths, versionName/code for every APK, min/target SDK, ABI, toolchain and dependency lockfiles. Preserve unrelated user changes. A docs-only branch must identify the separately built source commit. | -| A02 | Run `bundle exec fastlane android test`, `python_checks` and `native_integration`; retain commands, exit statuses, test counts and CI links. Integration uses real GOST/OpenSSH; it does not test Android TUN/JNI. | +| A02 | Run `bundle exec fastlane android test`, `bundle exec fastlane android python_checks` and `bundle exec fastlane android native_integration`; retain commands, statuses, test counts and exact-commit CI links. `test` runs native/JVM/lint/build checks only. Also require both API 26/API 35 device suites: `bundle exec fastlane android device_test_build`, then `bundle exec fastlane android device_tests api:26` and `bundle exec fastlane android device_tests api:35`, or their full CI results. Use accelerated cold boots; never retry failed tests to get green. PR suites skipped by change filtering do not establish candidate coverage; release-branch CI runs all suites. Debug TUN/JNI tests and GOST/OpenSSH integration support, but do not replace, signed-APK acceptance. | | A03 | Build with `bundle exec fastlane android release_artifacts` using JDK 21 and the normal release signer. Retain SHA256SUMS, `apksigner verify --verbose --print-certs`, `aapt dump badging`, merged permissions/components and ABI inventory. Do not bump production version codes just to arrange an update test. | | A04 | Compare source and merged manifest permissions; explain library additions. Review exported components, intent handlers, FileProvider paths, backup rules, SDKs, executable assets, dynamic loading, APK downloads and dependency/licenses changes. Check privacy policy and listing against behaviour. | | A05 | For an actual F-Droid candidate, pin its recipe/upstream/fdroidserver revisions and official buildserver image digest; run official metadata checks, scanner and unchanged recipe. Where configured, run official reproducibility/signature-copy verification against the matching upstream APK. A normal Gradle build is not this result. If no applicable recipe/release exists, record that explicitly. | -| A06 | Inventory two phones and two emulators anew: model, Android/API, OEM build, patch, ABI, page size, screen/font scale, language, installed package/version/signer, VPN/Private DNS/Always-on/lockdown, permissions and connectivity. One emulator must use the declared minimum API (currently 26); another uses a recent supported API. 4 KiB testing does not establish 16 KiB support. | +| A06 | Inventory two phones and two emulators anew: model, Android/API, OEM build, patch, ABI, page size, screen/font scale, language, installed package/version/signer, VPN/Private DNS/Always-on/lockdown, permissions and connectivity. One emulator must use the declared minimum API (currently 26); the other uses API 35, matching the second required CI suite. Newer APIs are additional coverage. 4 KiB testing does not establish 16 KiB support. | | A07 | Save existing app configuration and original system settings before mutation. Use synthetic profiles and dedicated ordinary test apps; on a personal phone restrict routing to those apps. Obtain applicable authorization for phone reboot/network changes. Do not clear/uninstall a pre-existing installation or change its lock credential. | -| A08 | Establish controlled HTTP/HTTPS origins, GOST and OpenSSH endpoints, separate jump credentials/keys, logs and a capture point; add authenticated MASQUE/HTTP3 with UDP enabled and UDP echo/HTTP3 origins for H01–H11. Prove direct baseline and fixture health. Loopback/ADB reverse is suitable for tunnel correctness, but is not evidence of physical Wi-Fi/cellular routing or DNS leak resistance. Never route personal apps through the fixture. | +| A08 | Establish controlled HTTP/HTTPS origins, GOST HTTPS/SOCKS5/MASQUE and OpenSSH endpoints, independent jump credentials/keys, HTTPS subscription feeds, DoH, logs and a capture point. Enable UDP and provide UDP echo/HTTP3 origins; for H12–H15 provide TCP HTTPS and UDP MASQUE on the same numeric port of each hop. Prove direct baseline and fixture health. Loopback/ADB reverse alone proves neither physical handover nor DNS leak resistance. Never route personal apps through the fixture. | +| A09 | Audit the release automation evidence separately from device results: all required suites succeeded for the exact release head/base; the actual tagged merge has those two parents and the tested head tree. Check version/ABI codes and both locales of notes. For an authorized tag release, match every signed APK hash to SHA256SUMS and completed VirusTotal analyses, Markdown/JSON reports and release-note links. API errors/timeouts or malicious/suspicious verdicts must block publication. Exercise failures with Python fixtures, not live release creation; this procedure does not authorize merge/tag/publish. | ## Priorities when the review budget is limited @@ -57,8 +58,9 @@ insufficient time to restore personal devices and remove temporary access. ## Four-device execution matrix -Run I01–I05, P01–P05, T01–T09, L01–L08, D01–D04, U01–U04 and E01–E03 -on all four devices where applicable; add H01–H11 for MASQUE candidates. Run advanced +Run I01–I06, P01–P07, T01–T10, C01–C05, L01–L11, D01–D05, U01–U04 and E01–E03 +on all four devices where applicable; add S01–S04 for SOCKS5 and H01–H15 for +MASQUE/HTTPS HTTP/3 preference. Record transport and hop variants as separate subcases. Run advanced capture, Direct Boot, forced Doze and destructive-data cases on the dedicated emulators first. Repeat applicable cases on phones only within the recorded authorization. A phone exception remains visible in the matrix; an emulator result never silently substitutes for it. @@ -72,51 +74,67 @@ visible in the matrix; an emulator result never silently substitutes for it. | I03 | Deny then grant VPN consent; cancel connection; revoke consent by switching VPN where safe. Check UI, actual VPN/service state and traffic; stale callbacks must not claim a connection. Denied notification permission must have a usable explanation and settings path. | | I04 | Start/stop/reconnect from visible controls and notification; rapid repeated taps, Back, Home, task removal, activity recreation and rotation. No duplicate tunnel, stale spinner or unintended connection after Stop. Check actual traffic after each state transition. | | I05 | English and Russian; narrow screen, large font, portrait/landscape, dark/light theme, keyboard and foldable outer/inner display. Scroll long dialogs and profile names, check all buttons/labels are reachable. Check IEC/SI display, Latin MiB input labels, limits, timestamps and empty/error states. | +| I06 | Open the GitHub link beside the version and the Settings privacy-policy link in EN/RU, including narrow/large-font layouts; verify their repository/policy targets. With no browser handler, show a localized error without crashing or changing VPN state. Check connection-visibility warnings against actual Android VPN/Always-on/lockdown settings. | ### Profiles, persistence and trust | ID | Steps → required observation | | --- | --- | -| P01 | Create, edit, clone, select, reorder and delete synthetic HTTPS/SSH and jump profiles; include MASQUE α when present in the candidate. Cancel a new draft. Restart after saving; check independent profile fields and active/Always-on references. Delete only test profiles. | -| P02 | Import supported URI/text and full JSON; export with secrets excluded and explicitly included; reimport and make a real connection. Check omitted versus empty secrets, stable IDs, duplicate merge, old schema, unknown future schema, malformed/truncated/oversized data and cancelled SAF picker. No partial destructive import or silent secret loss. | +| P01 | Create, edit, clone, select, reorder and delete synthetic HTTPS, HTTPS Jump, SSH, SSH Jump, SOCKS5 and MASQUE α profiles. Exercise HTTPS HTTP/3 preference separately (H12–H15). Cancel a new draft. Restart after saving; check independent profile fields and active/Always-on references. Delete only test profiles. | +| P02 | Import supported URI/text and full JSON; export with secrets excluded and explicitly included; reimport and make a real connection. Check omitted versus empty secrets, stable IDs, duplicate merge, old schema, unknown future schema, malformed/truncated/oversized data and cancelled SAF picker. No partial destructive import or silent secret loss. Include explicit unknown JSON transport and URI scheme (reject, never silently HTTPS), omitted legacy type (HTTPS default), ignored browser/unknown fields reported once without values, and exported-schema validation against vendored MegaProxyConfig. Unsupported fields do not round-trip. | | P03 | Rotate/background during save/import/export; repeat after activity/process death on an emulator. Failed/lost export must not truncate an existing destination. Review saved-state/logs for credentials using a synthetic secret marker. Device-protected/credential-protected storage and real Keystore failures are distinct tests. | | P04 | SSH first-use prompt: Cancel, verify fingerprint independently, Accept and reconnect. Change the server host key, confirm rejection; test jump and destination separately, including password/key modes and different credentials. No silent trust change or direct fallback. | | P05 | HTTPS and, where included, MASQUE α: valid identity, untrusted/self-signed and wrong-host certificates; explicitly allow an exception only for its selected hop and restore verification. Check malformed custom JA3/profile selection. An allowed self-signed fixture is not positive evidence of CA/hostname verification. | +| P06 | With a profile/global-settings editor open, refresh its subscription with changed credentials/routing; save only a name or one setting. Untouched fresh values and unreadable encrypted secrets must survive; an intentional edit wins only for that field. Repeat a failed write/retry and profile deletion during save. Also change SSH host/port/pin while its trust prompt is open: accepting the old prompt must not trust the changed endpoint. Inspect credential screens and recent-app snapshots for FLAG_SECURE protection. | +| P07 | On disposable emulator data, inject malformed profile/global JSON, wrong routing-field types and unavailable Keystore secrets. Preserve original stored bytes and show a usable error; never silently reset routing or credentials. Startup must refuse unsafe defaults; Stop remains available for a running manual VPN, respecting Always-on. Trigger failover with damaged settings: no crash or silent profile switch. Restore the fixture explicitly, then verify recovery. Test legacy IPv6 migration against the configuration actually used by the first connection. | ### Real forwarding, routing and diagnostics | ID | Steps → required observation | | --- | --- | -| T01 | Ordinary-app HTTP and HTTPS requests through HTTPS/GOST, SSH/OpenSSH, HTTPS Jump and SSH Jump; include MASQUE α when present in the candidate. Use unique tokens, binary upload/download comparisons and server-side evidence. Exercise multiple requests and simultaneous streams; confirm destination/jump roles and no double traffic counting. | +| T01 | Ordinary-app HTTP and HTTPS requests through HTTPS/GOST, SSH/OpenSSH, HTTPS Jump, SSH Jump, SOCKS5 and MASQUE α; exercise both selections of HTTPS HTTP/3 preference (H12–H15). Use unique tokens, binary upload/download comparisons and server-side evidence. Exercise multiple requests and simultaneous streams; confirm destination/jump roles and no double traffic counting. Use an origin that replies only after the client write half-close; the full response must survive FIN on every transport. | | T02 | Correct → wrong → missing → restored credentials at each authenticated hop. Require working controls and no successful origin delivery for the negative token. A “Connected” label with rejected requests is not success. | | T03 | Proxy refused, timeout, reset, unreachable origin and truncated response; restore each. Application must report bounded errors and recover. No direct fallback unless the selected routing policy explicitly calls for it. | | T04 | All-app routing on an emulator; selected-app routing on every device with two ordinary UIDs (included/excluded). Toggle local-network bypass and probe controlled LAN/private and public targets. Confirm included/excluded decisions from observed route, not just checkboxes. | -| T05 | IPv4 and, with a verified IPv6 uplink/origin, IPv6 allow/block. HTTPS/SSH must block arbitrary UDP/QUIC; blocked tokens must not reach the UDP origin with a working direct control. If the candidate includes MASQUE α, verify tunneled UDP with origin evidence, local UDP bypass and oversized datagram failure; test Chrome/Firefox constraints and GOST IPv6-target limitations separately. A browser falling back to HTTP/2 is not QUIC support. See [MASQUE limits](masque.md). | +| T05 | IPv4 and, with a verified IPv6 uplink/origin, IPv6 allow/block. HTTPS over TCP (HTTP/1.1 or HTTP/2) and SSH must block proxied non-DNS UDP/QUIC; test configured local bypass separately; blocked tokens must not reach the UDP origin with a working direct control. For MASQUE α, HTTPS selecting HTTP/3 and SOCKS5, verify tunneled UDP with origin evidence, local UDP bypass and oversized datagram failure; test Chrome/Firefox constraints and GOST IPv6-target limitations separately. A browser falling back to HTTP/2 is not QUIC support. See [MASQUE limits](masque.md). | | T06 | Run connection diagnostics: exit IP/country, primary failure and fallback. Compare with controlled server egress. Check cancellation and invalid/offline profile behaviour; inspect logs for synthetic credential leakage. Distinguish failed external providers from broken tunnelling. | | T07 | Transfer a known amount, inspect upload/download totals, reset/limit behaviour and persistence. The SSH session rotation threshold in MiB must rotate the session as documented; it is not a traffic quota and must not be tested as a VPN cutoff. Test selected/all failover with unavailable primary, healthy secondary and exhausted candidates; verify actual egress and Stop during failover. | | T08 | Check [TCP metrics](connection-metrics.md) with controlled traffic: RTT is to the first proxy, not website latency; no data differs from zero. Induce loss on a dedicated fixture, correlate outgoing retransmits with independent capture, and verify expiry after five minutes without new readings. Check jump/multiplexed sockets are counted once, standalone diagnostics do not change these metrics, and a new VPN session resets them. Record native-test evidence separately from device observations. | | T09 | Inspect successful HTTPS and SSH negotiation logs (plus MASQUE α HTTP/3 multiplexing and selected fingerprint where included) against the controlled server: TLS version/cipher/ALPN, actual HTTP CONNECT version after fallback, and initial SSH algorithms in both directions. Exercise both jump hops. Verify events contain no IPs, domains, credentials, certificate identities or raw banners; use synthetic markers. RTT/retransmits alone must not trigger failover; timeout/reset recovery remains a separate check. | +| T10 | Run Test with MASQUE, SOCKS5 and HTTPS selecting HTTP/3: retain separate Cloudflare and BrowserLeaks HTTP/3 verdicts. One/both unavailable must not erase a successful HTTPS/exit-IP result. In HTTPS fallback show the UDP warning, without false HTTP/3 success. These native probes use proxied UDP without TCP fallback but bypass Android TUN; additionally use an included ordinary browser/app and controlled HTTP/3 origin (H06). External-service availability is supporting evidence, not a deterministic CI gate. During a delayed temporary Test, Stop/start or switch profile: old completion must neither stop the replacement VPN nor publish stale success/diagnostics. | ### Configuration subscriptions -Use disposable HTTPS feeds and synthetic credentials on API 26 and API 35. Verify -bootstrap ownership, manual refresh while paused, background restart/overdue checks, -primary failure and valid backup, recovery to primary, and failure of all sources. -Check 401/403, redirects, invalid UTF-8, oversized decoded gzip, malformed fields, -empty snapshots and canonical ID collisions: none may overwrite working profiles. -Add a local profile and remove an owned profile from the feed; local profiles and -surviving selections must remain. Change/remove the subscription during download -and verify that the obsolete snapshot cannot commit. Inspect stored/exported data -with secret markers, test Keystore process restart, and require a reconnect notice -only after effective active connection changes. Confirm live traffic continues on -the previous tunnel until explicit reconnect, and no bootstrap starts VPN. +Use disposable HTTPS feeds and synthetic credentials. Record C01–C05 separately; +manual refresh and scheduled delivery are distinct subcases. + +| ID | Steps → required observation | +| --- | --- | +| C01 | Bootstrap a subscription; pause it and refresh manually; restart with an overdue check. Verify primary failure → valid backup → recovered primary and all sources unavailable. No bootstrap starts VPN. Ownership, local profiles and surviving active/Always-on selections remain correct when remote profiles disappear. | +| C02 | Reject 401/403, redirects, invalid UTF-8, oversized decoded gzip, malformed fields, empty snapshots and canonical ID collisions without replacing working profiles. Change/remove the subscription during download: obsolete results cannot commit or clear a newer refresh's busy state. Remote subscription definitions cannot replace local source URLs/recipients. Check encrypted storage, redacted exports and Keystore process restart. | +| C03 | Change an active endpoint/credential/routing policy in background while connected and while startup is delayed. Keep existing traffic until explicit reconnect; after startup, still flag changes that missed the original snapshot. Show a private reconnect notification and in-app indicator. Name-only/inactive-profile changes do not demand reconnect. Deny notification permission/disable channel: retain the in-app action and usable VPN. | +| C04 | Deliver two successive updates and use current versus stale reconnect actions; then Stop and invoke an old action. Only the current token on a running, desired VPN can reconnect. Applying an earlier snapshot must not clear a newer pending change. Verify actual new egress/credentials, cancellation of obsolete notification and no resurrection after Stop. | +| C05 | Refresh while leaving/recreating the subscription screen and while another editor has pending saves (P06). Completion clears busy state; writes finish or expose failure/Retry without losing unrelated edits. Inspect notification, logs and task snapshots for synthetic URL/password/profile markers; no feed payloads or credentials may appear. | + +### SOCKS5 + +Repeat shared profile, routing, DNS, lifecycle, update and diagnostics cases with +SOCKS5. Use a disposable GOST fixture with UDP enabled and a reachable relay. + +| ID | Steps → required observation | +| --- | --- | +| S01 | Anonymous and authenticated TCP CONNECT: correct/wrong/missing credentials, restored control, Stop/restart. Reject only-one-credential and values exceeding 255 UTF-8 bytes; include multibyte boundaries. Round-trip JSON and socks5:// with/without secrets. No SOCKS5 Jump or browser TLS fingerprint is promised; UI/import must not silently change transport. SOCKS5 credentials are plaintext on the proxy link, so use only disposable secrets. | +| S02 | UDP ASSOCIATE: binary 1200/1350/4096-byte echoes, several destinations, UDP-disabled server and unreachable/invalid relay. Wildcard relay uses the proxy bootstrap IP; a hostname relay must fail without system-DNS lookup. Close the TCP control connection: old UDP association terminates and a fresh connection recovers. Combine with per-app routing, bypass, IPv6 and D05. | +| S03 | Check TCP/UDP totals without counting relay framing twice; TCP RTT/retransmits concern TCP/control sockets, not UDP latency/loss. Test sustained UDP and Stop under load; use the native allocation-budget regression as separate evidence that reads no longer allocate 64 KiB per datagram. Device CPU/memory observations need their own duration/load baseline. | +| S04 | Fail over to/from SOCKS5, HTTPS/SSH and MASQUE; verify new TCP/UDP origin tokens, current badge and credentials, no direct fallback. Failed or unsupported UDP alone does not establish proxy blocking; HTTP/3 availability is a separate T10 result. | ### MASQUE α / HTTP/3 -Run H01–H11 on all four devices when the candidate includes MASQUE. Also repeat -I01–I05, P01–P03, T02–T04, T06–T08, L01–L08, D01–D04 and U02–U04 with a +Run H01–H11 for explicit MASQUE and H12–H15 for HTTPS HTTP/3 preference, +including Jump, on all four devices. Also repeat +I01–I06, P01–P03, P06–P07, T02–T04, T06–T10, C01–C05, L01–L11, D01–D05 and U02–U04 with a MASQUE profile: the transport cases do not replace shared feature checks. For a -candidate without MASQUE, record this section as N/A with its artifact identity. +candidate lacking a mode, record only its cases as N/A with the artifact identity. Use a disposable authenticated GOST fixture from the [MASQUE guide](masque.md), record its version/configuration, and provide controlled TCP, UDP echo and HTTP/3 @@ -129,24 +147,32 @@ outer HTTP/3 to the proxy from an app's inner QUIC traffic to an origin. The API 26/API 35 runner also exercises Randomized/custom JA3, rejected and corrected credentials, rejected self-signed certificates with an explicit exception control, Chrome/Firefox oversized UDP followed by small packets on the same socket, real -per-app routing, and timeout-driven MASQUE → custom HTTPS failover. It runs against +per-app routing, and timeout-driven MASQUE → custom HTTPS failover. It also checks anonymous/authenticated +SOCKS5 TCP/UDP, HTTPS preference and all four Jump availability pairs. Positive +private-origin TCP requests precede one-shot UDP/TCP DNS AAAA-suppression probes, +so VPN route readiness is proven before sending UDP; these do not prove real DoH +resolution or leak resistance. It runs against a disposable authenticated GOST fixture and private origin. This suite does not replace the trusted-certificate, DNS-capture, inner HTTP/3, IPv6-uplink or physical handover checks below. | ID | Steps → required observation | | --- | --- | -| H01 | Select MASQUE α, save host/UDP port/credentials and each fingerprint; restart, clone, export/import JSON and `masque://` ProxyList, with/without secrets (P01–P03). JSON preserves `proxy.type: "MASQUE"`, port and settings; ProxyList preserves its supported endpoint/credential fields, not global fingerprint settings. Verify real connectivity after import. Check EN/RU α label and default certificate verification. Jump modes remain HTTPS/SSH only: unsupported imported combinations must be rejected, without silently changing transport or routing. | +| H01 | Select MASQUE α, save host/UDP port/credentials and each fingerprint; restart, clone, export/import JSON and `masque://` ProxyList, with/without secrets (P01–P03). JSON preserves `proxy.type: "MASQUE"`, port and settings; ProxyList preserves its supported endpoint/credential fields, not global fingerprint settings. Verify real connectivity after import. Check EN/RU α label and default certificate verification. Profile Jump types remain HTTPS/SSH; HTTPS Jump can prefer HTTP/3 on both hops (H13). Unsupported imported combinations must be rejected without silently changing transport or routing. | | H02 | Send binary TCP upload/download and simultaneous requests to two origins, plus a UDP echo flow. Correlate origin tokens with GOST connection/stream records: one shared outer QUIC session carries independent CONNECT/CONNECT-UDP streams. Close one flow while others continue. Confirm HTTP/3 and multiplexing diagnostics; a badge or log alone does not prove traffic or session reuse. Missing server datagram/extended-CONNECT settings or CONNECT-UDP Capsule-Protocol must produce a clear failure. | | H03 | Correct → wrong username → wrong password → missing credentials → restored credentials, for both TCP CONNECT and CONNECT-UDP. Negative tokens must not reach the origins; record GOST rejection and bounded client failure. An established QUIC handshake is not successful authorization. Reconnect after editing credentials and check that the prior authenticated session is not reused. | | H04 | Trusted matching certificate succeeds with verification enabled; untrusted/self-signed, wrong-host and expired certificates fail without origin delivery. Explicitly permit only the selected fixture, reconnect, restore verification and repeat rejection. Confirm an unrelated profile without an explicit exception still verifies certificates. Record handshake evidence separately from HTTP authentication. | | H05 | Chrome Android, Firefox Android, Randomized and valid Custom JA3 (QUIC JA3 in the MASQUE profile, TLS JA3 in Settings): reconnect for each, exercise TCP and a small UDP payload, and inspect captured ClientHello/QUIC transport parameters against the selected preset/custom fields. Malformed or QUIC-incompatible JA3 must fail clearly. Compare Randomized across fresh sessions. Record the uQUIC preset versions and ALPN `h3`; selected-profile logs are not wire evidence, and preset matching does not establish an exact whole-browser HTTP/3 fingerprint. | | H06 | UDP echo with byte/address comparison at 512 bytes, Chrome at 1200 bytes, and around the negotiated datagram/path-MTU boundary; then try an ordinary app's real QUIC request to the controlled HTTP/3 origin. Confirm GOST egress and actual origin HTTP/3, with HTTP/2 fallback disabled for this probe. Oversized packets must be dropped whole with a diagnostic, without truncation, direct fallback or breaking a subsequent small packet/TCP stream. Record Firefox's inability to carry a 1200-byte inner QUIC Initial and GOST's missing reliable capsule fallback as limits; small UDP success is not full QUIC success. | | H07 | Repeat selected/all-app routing and local bypass using included/excluded ordinary UIDs, public/LAN TCP and UDP origins, and verified IPv4/IPv6 controls (T04–T05). IPv4-only must block IPv6 TCP and UDP; with IPv6 enabled verify TCP and local UDP bypass. Record GOST 3.3.0 IPv6-literal CONNECT-UDP rejection separately as a blocked tunneled-UDP subcase, not PASS for IPv6 UDP or an acceptable direct fallback. | -| H08 | Fresh names through the configured DoH, primary failure → fallback → all failed (D01–D02). Correlate DoH over the MASQUE TCP tunnel and external DNS capture: UDP/53 must retain DoH handling rather than become arbitrary CONNECT-UDP or unintended plaintext DNS. Exercise Private DNS/lockdown controls separately; absent external capture leaves leak resistance NOT TESTED. | +| H08 | Fresh names through the configured DoH, primary failure → fallback → all failed (D01–D02). Correlate DoH over the MASQUE TCP tunnel and external DNS capture: UDP and TCP port 53 (D05) must retain DoH handling rather than become arbitrary CONNECT-UDP or unintended plaintext DNS. Exercise Private DNS/lockdown controls separately; absent external capture leaves leak resistance NOT TESTED. | | H09 | Compare known TCP/UDP payload totals and rates, IEC/SI, reset/persistence, Test exit IP/country and provider fallback (T06–T08). Verify HTTP/3 badge and multiplexing events, and clear stale status after Stop/profile switch. For MASQUE, verify QUIC RTT and outgoing packet-loss declarations over five minutes, including zero versus unavailable, expiry, session reset and shared-session counting; QUIC must not fabricate kernel TCP RTT/retransmit values. Inspect diagnostics with synthetic markers: no credentials, target identities, host-key pins or certificate details; verify TLS/cipher/ALPN, numeric QUIC errors and correlated local stream/session numbers, bounded duplicate events and no false DPI failures on Stop; private packet captures are separate evidence. | -| H10 | Block the proxy UDP port while TCP/443 remains reachable, restart GOST, force offline/online, and repeat real Wi-Fi/mobile handover (L01–L08). Confirm bounded failures and fresh working TCP/UDP flows after recovery; existing streams may terminate. Stop during handshake/reconnect must prevent late connection and traffic. No implicit HTTPS or direct fallback; virtual cellular alone does not verify carrier handover, and recovery alone does not prove QUIC connection migration. | -| H11 | Selected/all-profile failover with unavailable MASQUE primary, healthy secondary, exhausted candidates and Stop during switching (T07). Exercise both MASQUE→HTTPS/SSH and HTTPS/SSH→MASQUE, including separate valid custom TLS/QUIC JA3 values; correlate TCP egress and new UDP tokens. UDP follows the active transport: MASQUE tunnels supported payloads, HTTPS/SSH block non-DNS UDP. No stale badge/session/credentials, unintended direct delivery or double counting after switching. | +| H10 | Block the proxy UDP port while TCP/443 remains reachable, restart GOST, force offline/online, and repeat real Wi-Fi/mobile handover (L01–L08). Confirm bounded failures and fresh working TCP/UDP flows after recovery; existing streams may terminate. Stop during handshake/reconnect must prevent late connection and traffic. Explicit MASQUE has no implicit HTTPS or direct fallback (HTTPS preference is H12–H15); virtual cellular alone does not verify carrier handover, and recovery alone does not prove QUIC connection migration. | +| H11 | Selected/all-profile failover with unavailable MASQUE primary, healthy secondary, exhausted candidates and Stop during switching (T07). Exercise both MASQUE→HTTPS/SSH and HTTPS/SSH→MASQUE, including separate valid custom TLS/QUIC JA3 values; correlate TCP egress and new UDP tokens. UDP follows the active transport: MASQUE tunnels supported payloads, HTTPS over TCP and SSH block proxied non-DNS UDP; SOCKS5 and HTTPS selecting HTTP/3 relay supported UDP too. No stale badge/session/credentials, unintended direct delivery or double counting after switching. | +| H12 | HTTPS: preference off uses TCP; preference on selects HTTP/3 on the same host/numeric UDP port when available. Block UDP while TCP stays reachable: the optional probe is bounded to three seconds, then HTTP/2 or HTTP/1.1 works with a visible UDP-fallback warning and DoH retained. The probe alone must not produce a blocking warning/failover. Reconnect repeats selection; established HTTP/3 streams are never silently moved to TCP. Persist the preference through JSON/clone/restart; plain proxy URLs omit it. | +| H13 | HTTPS Jump: test H3/H3, H3/TCP-only, TCP-only/H3 and TCP-only/TCP-only hops. Only the first pair uses nested HTTP/3; otherwise the whole chain falls back to HTTPS through the jump, with no direct exit connection. Verify separate credentials/certificate policies, remote exit-host resolution, real TCP and 1200/1280/1350-byte UDP, asymmetric MTU/loss and Stop during exit handshake. Capture both hops; one successful outer handshake proves neither exit authorization nor usable inner QUIC. | +| H14 | For each applicable hop, contrast unavailable protocol/settings, CONNECT-UDP 404/405/501 and missing Capsule-Protocol (eligible fallback) with bad credentials, certificate failures, access denial and unexpected server failures (terminal, no downgrade). Edge/QUIC-incompatible custom fingerprint selects HTTPS; Firefox Jump falls back for its datagram limit. Socket-protection/unknown-error cases require native fault-injection evidence. Explicit MASQUE still fails instead of falling back. | +| H15 | During active QUIC traffic induce lost ACKs/retransmission, GOAWAY and local request deadlines. New streams recover while unrelated healthy streams remain usable where the protocol allows. Record the native uQUIC retransmission regression separately; a successful handshake does not exercise it. One failed shared QUIC session must not count each failed stream as an independent blocking incident; test independent failures and subsequent successful tunnel recovery (L10). | Record verdicts separately for each fingerprint, TCP/UDP, payload size and address family. The existing `native_integration` and API 26/API 35 device scenarios are @@ -167,6 +193,9 @@ limits must remain visible in the release decision; do not mark unexecuted cases | L06 | Install an update while VPN is connected; check package-replaced recovery and real traffic. Repeat with connection explicitly stopped: package replacement must not enable it. Preserve signatures and APK variant; do not publish fixture versions. | | L07 | Dedicated emulator Direct Boot: set a temporary test PIN, reboot, independently verify `RUNNING_LOCKED` before/after ordinary-UID direct-boot probes; then unlock and retest. A black screen or a post-unlock observation is not this case. Record whether MegaProxy promises pre-unlock operation. | | L08 | Forced Doze with recorded screen-off/IDLE state, app exemption state and ordinary-app probes; outage/recovery while idle, then unforce/reset battery and retest. Include a timed foreground/background soak (at least 15 minutes) and record duration. Shell UID is not an ordinary background-app control. Long-term battery/24-hour behaviour remains separate. | +| L09 | Stop while HTTP/1 CONNECT is stalled, SSH/QUIC admission queues are full and TCP/UDP local-bypass or DNS flows are open. Old sockets and waiters terminate promptly; old server-side flows cannot carry new tokens. Repeat rapid Stop/start/profile switch and delayed callbacks: the new VPN, protocol, warning and profile remain current. Post-Stop direct traffic allowed by Android policy is distinct from a leaked old tunnel; use connection-specific server evidence and separate lockdown controls. | +| L10 | Seed a stale proxy/jump bootstrap IP, change its DNS answer and induce refused/unreachable: a bounded fresh resolution can recover without calling refusal proof of blocking; late old failures must not discard a newer address. Induce actual proxy failures within/outside the 60-second evidence window, then a successful tunnel: stale blocking warnings clear without erasing unrelated warnings. A target reset, local deadline, local bypass failure or duplicate shared-session error must not trigger global failover. Include a timed healthy soak; report a long-duration test separately from the 15-minute minimum. | +| L11 | Failover candidates include blank drafts, incompatible transport/fingerprint settings and unreadable credentials plus a valid alternative: skip invalid effective configurations, including global settings, and connect only to an allowed valid candidate. Repeat selected/all/exhausted modes. For SSH and SSH Jump, silence keepalive replies: the ten-second reply deadline retires the dead session and new requests can recover; Stop interrupts waiting. Also verify bidirectional/half-close replies and configured channel limits/session rotation under load. | ### DNS, lockdown and external control @@ -176,13 +205,14 @@ limits must remain visible in the release decision; do not mark unexecuted cases | D02 | Direct control → active VPN → unavailable proxy → force-stop with lockdown → restart → direct control. Repeat fresh names twice using ordinary apps and browsers where safe. Capture IPv4/IPv6 UDP/TCP 53 and strict Private DNS/853 where available. No second capture VPN: it would replace the subject. If external capture is unavailable, leak resistance is NOT TESTED. | | D03 | Compare known Android/OEM limitations against current primary sources. Separate observed leakage from attribution to MegaProxy, shell-only effects, browser Secure DNS and fixture failures. Record exact OS build; do not extrapolate to every Android release. | | D04 | Use an ordinary test app to attempt exported intents/broadcasts/provider access; private receivers and trust/export screens must not expose secrets or change VPN/trust state. Inspect manifest protection and runtime refusal. ADB shell permissions alone are not this evidence. | +| D05 | For every transport and HTTPS preference outcome, send explicit UDP/53 and framed TCP/53 queries from an ordinary UID, including LAN destinations with bypass enabled. Both must use configured DoH with fallback/IPv6 policy; no plaintext TCP retry escapes. Exercise fragmented TCP prefix/payload, pipelined IDs, write half-close with pending replies, timeout, malformed length and Stop. Check primary/fallback/all failed and AAAA suppression; CUSTOM and filtering providers must not silently switch to unfiltered resolvers. Separate these intercepted queries from Android Private DNS/browser Secure DNS, which follow normal routing. Native framing/DoH fixtures support but do not replace packet-capture evidence. | ### Updating and distribution | ID | Steps → required observation | | --- | --- | | U01 | Official and alternative F-Droid installers (fdroidrepo/fdroidrepos handlers), browser/file installer, unknown installer and manual override. An unrelated installed F-Droid client must not change a browser installation's source. Check chosen API and persistence. An unpublished F-Droid package gives an explicit unavailable result without switching to GitHub. Simulated installer identity is not installation from the repository. | -| U02 | New/same/older/malformed release metadata and unavailable network. Explicit download consent/cancel, APK size/digest/package/version/signer/ABI checks, corruption and download interruption. Use unit tests for deliberately invalid APKs and isolate destructive fixtures to emulators. | +| U02 | New/same/older/malformed release metadata and unavailable network. Explicit download consent/cancel, APK size/digest/package/version/signer/ABI checks, corruption and download interruption. Use unit tests for deliberately invalid APKs and isolate destructive fixtures to emulators. After repeated downloads, retain only the current APK and one predecessor for an active installer; stale .part files older than two days are pruned without deleting a fresh download. Use controlled timestamps for cache tests and verify the installer can still read its granted URI. | | U03 | Universal stays universal, ABI-specific stays that ABI; system install permission denied/granted, cancellation, return from settings and successful update. Read back installed APK/version/signature and verify real connectivity afterward. | | U04 | Notifications allowed/denied/channel disabled; Update, Skip version, Disable checks; manual check after skip; disable while job is in flight; job restoration after reboot. Test no early reminder and reminder after seven days by controlled timestamp injection on an emulator. Report forced jobs/time simulation separately from real daily/weekly delivery. | @@ -194,6 +224,18 @@ limits must remain visible in the release decision; do not mark unexecuted cases | E02 | Stop fixtures/captures, remove only created forwards/reverses, probe apps/files and test profiles; restore original routing, active/Always-on profile, permissions, network, Private DNS, screen/font/language and battery settings. Preserve original app/data and pre-existing VPN state. Verify restoration on each device; list any residual state. | | E03 | Recheck candidate commit and artifact hashes, complete all matrix cells and link evidence. Summarize failures and limitations by feature, not setup chronology. Keep raw private artifacts out of the PR and verify the staged file allowlist. | +## Keeping the procedure current + +Before selecting cases, record the last commit touching each language version and +review every subsequent candidate commit (`git log BASE..CANDIDATE` and the diff), +not only release notes. Map each product change/fix to case IDs and existing +JVM/Go/device tests; keep gaps explicit. Also compare the complete current feature +inventory: a feature can predate BASE yet still be missing from the procedure. +Record automated evidence and signed-device verdicts separately, including skipped +suites and fixture limits. Preserve existing case IDs and dated historical reports; +update both language versions together. The automatic release workflow checks CI +and publishes after tagging; it does not collect or enforce this manual matrix. + ## Findings, fixes and release decision Reproduce a finding on the unchanged candidate and keep that evidence. Record diff --git a/docs/ru/release-testing.md b/docs/ru/release-testing.md index b258f54..7f548c4 100644 --- a/docs/ru/release-testing.md +++ b/docs/ru/release-testing.md @@ -39,13 +39,14 @@ | ID | Процедура и необходимые доказательства | | --- | --- | | A01 | Зафиксировать commit исходников кандидата, изменённые файлы, versionName/code каждого APK, min/target SDK, ABI, toolchain и lock-файлы. Сохранить чужие изменения. Для ветки документации отдельно указать commit собранного приложения. | -| A02 | Выполнить `bundle exec fastlane android test`, `python_checks`, `native_integration`; сохранить команды, статусы, число тестов и ссылки CI. GOST/OpenSSH в интеграционном тесте не означают проверку Android TUN/JNI. | +| A02 | Выполнить `bundle exec fastlane android test`, `bundle exec fastlane android python_checks` и `bundle exec fastlane android native_integration`; сохранить команды, статусы, число тестов и ссылки CI для точного коммита. `test` запускает только native/JVM/lint/build. Дополнительно обязательны обе проверки API 26/API 35: `bundle exec fastlane android device_test_build`, затем `bundle exec fastlane android device_tests api:26` и `bundle exec fastlane android device_tests api:35`, либо их полные результаты CI. Использовать ускоренную эмуляцию с холодным запуском; не перезапускать упавшие тесты ради зелёного результата. Пропуск PR-проверки по diff не доказывает покрытие кандидата; CI релизной ветки выполняет все наборы. Debug TUN/JNI и интеграция GOST/OpenSSH дополняют, но не заменяют приёмку подписанного APK. | | A03 | Собрать `bundle exec fastlane android release_artifacts` с JDK 21 и штатной release-подписью. Сохранить SHA256SUMS, `apksigner verify --verbose --print-certs`, `aapt dump badging`, итоговые permissions/components и ABI. Не менять production versionCode ради теста обновления. | | A04 | Сопоставить исходный и merged manifest, объяснить разрешения зависимостей. Проверить exported-компоненты, intents, FileProvider, backup, SDK, исполняемые assets, динамическую загрузку, скачивание APK, изменения зависимостей/лицензий. Сверить политику приватности и описание с поведением. | | A05 | Для реального кандидата F-Droid закрепить recipe/upstream/fdroidserver и digest официального buildserver; выполнить metadata checks, scanner и неизменённый recipe. Где предусмотрено — официальную проверку reproducibility/signature-copy с соответствующим upstream APK. Gradle-сборка этого не заменяет. Отсутствие применимого recipe/релиза отметить явно. | -| A06 | Заново описать два телефона и два эмулятора: модель, Android/API, OEM build, patch, ABI, размер страницы памяти, экран/шрифт/язык, установленный пакет/версию/подпись, VPN/Private DNS/Always-on/lockdown, разрешения и сеть. Один эмулятор — минимальный заявленный API (сейчас 26), другой — современный поддерживаемый. 4 KiB не доказывают поддержку 16 KiB. | +| A06 | Заново описать два телефона и два эмулятора: модель, Android/API, OEM build, patch, ABI, размер страницы памяти, экран/шрифт/язык, установленный пакет/версию/подпись, VPN/Private DNS/Always-on/lockdown, разрешения и сеть. Один эмулятор — минимальный заявленный API (сейчас 26), другой — API 35, как второй обязательный набор CI. Более новые API проверяются дополнительно. 4 KiB не доказывают поддержку 16 KiB. | | A07 | До изменений сохранить конфигурацию приложения и системные настройки. Использовать синтетические профили и отдельные тестовые приложения; на личном телефоне направлять в VPN только их. Иметь разрешение на перезагрузку/переключение сети. Не очищать и не удалять существующую установку, не менять личный PIN. | -| A08 | Поднять контролируемые HTTP/HTTPS, GOST, OpenSSH, отдельные реквизиты/ключи для jump, логи и точку захвата; для H01–H11 добавить MASQUE/HTTP3 с авторизацией и включённым UDP, UDP echo/HTTP3 origins. Проверить прямой доступ и исправность стенда. Loopback/ADB reverse подходят для туннеля, но не доказывают реальный handover или отсутствие DNS-утечек. Личные приложения через стенд не направлять. | +| A08 | Поднять контролируемые HTTP/HTTPS origins, GOST HTTPS/SOCKS5/MASQUE, OpenSSH, отдельные реквизиты/ключи jump, HTTPS-источники подписки, DoH, логи и точку захвата. Включить UDP, подготовить UDP echo/HTTP3 origins; для H12–H15 нужны TCP HTTPS и UDP MASQUE на одном числовом порту каждого узла. Подтвердить прямой контроль и исправность стенда. Loopback/ADB reverse сами по себе не доказывают физический handover или отсутствие DNS-утечек. Личные приложения через стенд не направлять. | +| A09 | Отдельно от устройств проверить доказательства релизной автоматики: все обязательные наборы успешны для точных head/base релизного PR; тег указывает на фактический merge-коммит с этими двумя родителями и деревом проверенного head. Сверить version/ABI codes и обе локали changelog. Для разрешённого выпуска по тегу сопоставить хеш каждого подписанного APK с SHA256SUMS, завершённым анализом VirusTotal, Markdown/JSON-отчётами и ссылками в релизе. Ошибки API, таймауты, malicious/suspicious блокируют публикацию. Отрицательные сценарии проверять Python-стендами, без создания живого релиза; регламент не разрешает merge/tag/publish. | ## Приоритеты при ограниченном бюджете проверки @@ -60,8 +61,9 @@ NOT TESTED. Сокращённый прогон не превращает нев ## Матрица четырёх устройств -I01–I05, P01–P05, T01–T09, L01–L08, D01–D04, U01–U04 и E01–E03 выполняются -на всех четырёх устройствах, где применимы; для кандидата с MASQUE добавить H01–H11. +I01–I06, P01–P07, T01–T10, C01–C05, L01–L11, D01–D05, U01–U04 и E01–E03 выполняются +на всех четырёх устройствах, где применимы; добавить S01–S04 для SOCKS5 и H01–H15 +для MASQUE/предпочтения HTTP/3 в HTTPS. Варианты транспорта и узлов записывать отдельными подслучаями. Сложные захваты, Direct Boot, forced Doze и разрушительные проверки данных сначала выполняются на выделенных эмуляторах. На телефонах — в пределах полученного разрешения. Исключение для телефона остаётся в матрице; результат эмулятора не подставляется вместо него. @@ -75,52 +77,67 @@ I01–I05, P01–P05, T01–T09, L01–L08, D01–D04, U01–U04 и E01–E03 в | I03 | Отказать, затем выдать VPN consent; отменить подключение; безопасно отозвать consent переключением VPN. Сопоставить UI, VPN/service и трафик; старые callbacks не должны сообщать успех. При отказе уведомлений нужны понятное объяснение и путь в настройки. | | I04 | Подключить/отключить/переподключить через UI и уведомление; быстрые повторные нажатия, Back, Home, удаление задачи, recreation и rotation. Нет второго туннеля, вечного spinner или подключения после Stop. После переходов проверять данные. | | I05 | EN/RU, узкий экран, крупный шрифт, portrait/landscape, светлая/тёмная тема, клавиатура, внешний/внутренний экран складного телефона. Все действия доступны, длинные диалоги прокручиваются. Проверить IEC/SI, латинское MiB, лимиты, время и пустые/ошибочные состояния. | +| I06 | Открыть GitHub справа от версии и политику приватности в настройках, EN/RU, узкое окно/крупный шрифт; сверить адреса репозитория и политики. Без обработчика браузера — локализованная ошибка без падения и изменения VPN. Сопоставить предупреждения видимости подключения с фактическими VPN/Always-on/lockdown в Android. | ### Профили, сохранение и доверие | ID | Действия → требуемый результат | | --- | --- | -| P01 | Создать/изменить/клонировать/выбрать/переставить/удалить синтетические HTTPS/SSH и jump-профили, а также MASQUE α, если он есть в кандидате; отменить черновик. Перезапустить после сохранения, проверить независимость полей и active/Always-on references. Удалять только тестовые профили. | -| P02 | Импорт URI/text/full JSON; экспорт без секретов и с явно включёнными секретами; импорт обратно и реальное подключение. Проверить отсутствующие/пустые секреты, stable ID, duplicate merge, старую/будущую schema, повреждённый/обрезанный/слишком большой файл и отмену SAF. Нет частичного разрушения данных или тихой потери секретов. | +| P01 | Создать/изменить/клонировать/выбрать/переставить/удалить синтетические HTTPS, HTTPS Jump, SSH, SSH Jump, SOCKS5 и MASQUE α профили; отдельно проверить предпочтение HTTP/3 в HTTPS (H12–H15); отменить черновик. Перезапустить после сохранения, проверить независимость полей и active/Always-on references. Удалять только тестовые профили. | +| P02 | Импорт URI/text/full JSON; экспорт без секретов и с явно включёнными секретами; импорт обратно и реальное подключение. Проверить отсутствующие/пустые секреты, stable ID, duplicate merge, старую/будущую schema, повреждённый/обрезанный/слишком большой файл и отмену SAF. Нет частичного разрушения данных или тихой потери секретов. Явные неизвестные JSON transport/URI scheme отклоняются без тихой замены на HTTPS; пропущенный legacy type использует HTTPS. Игнорируемые browser/неизвестные поля сообщаются однократно без значений; экспорт сверяется с vendored MegaProxyConfig. Неподдерживаемые поля не проходят round-trip. | | P03 | Rotation/background при save/import/export; activity/process death на эмуляторе. Потерянный экспорт не должен обнулить существующий файл. Искать синтетический секрет в saved state/логах. Доступность хранилища до разблокировки и реальные отказы Keystore — отдельные проверки. | | P04 | SSH TOFU: Cancel, независимая сверка fingerprint, Accept, повторное соединение; смена ключа сервера должна отклоняться. Отдельно jump/destination, пароль/ключ и разные реквизиты. Нет молчаливого изменения доверия или direct fallback. | | P05 | HTTPS и, при наличии в кандидате, MASQUE α: правильная идентичность, недоверенный/self-signed и wrong-host сертификат. Исключение действует только на выбранный узел; затем вернуть проверку. Невалидный JA3 и TLS-профиль. Разрешённый self-signed стенд не доказывает CA/hostname verification. | +| P06 | Оставить редактор профиля/общих настроек открытым, обновить подписку с новыми реквизитами/маршрутизацией; сохранить только имя или одну настройку. Нетронутые свежие значения и нечитаемые зашифрованные секреты сохраняются; намеренное изменение побеждает только для своего поля. Повторить отказ записи/Retry и удаление профиля во время сохранения. Изменить SSH host/port/pin при открытом запросе доверия: принятие старого запроса не доверяет изменённому узлу. Проверить FLAG_SECURE на экранах секретов и в снимках недавних приложений. | +| P07 | На одноразовых данных эмулятора внести повреждённый JSON профилей/общих настроек, неверные типы routing-полей и недоступные секреты Keystore. Исходные байты сохраняются, ошибка понятна; маршрутизация и реквизиты не сбрасываются молча. Запуск не использует небезопасные значения по умолчанию; Stop остаётся доступен для работающего ручного VPN с учётом Always-on. Вызвать failover с повреждёнными настройками: нет падения или тихой смены профиля. Явно восстановить стенд и проверить работу. Сверить миграцию старого IPv6 с конфигурацией первого фактического соединения. | ### Передача данных, маршрутизация и диагностика | ID | Действия → требуемый результат | | --- | --- | -| T01 | HTTP/HTTPS из обычного приложения через GOST, OpenSSH, HTTPS Jump, SSH Jump и MASQUE α, если он есть в кандидате: уникальные токены, сравнение upload/download, серверные доказательства, повторные запросы и одновременные потоки. Проверить роли узлов и отсутствие двойного подсчёта трафика. | +| T01 | HTTP/HTTPS из обычного приложения через GOST, OpenSSH, HTTPS Jump, SSH Jump, SOCKS5 и MASQUE α, включая оба результата выбора HTTP/3 в HTTPS (H12–H15): уникальные токены, сравнение upload/download, серверные доказательства, повторные запросы и одновременные потоки. Проверить роли узлов и отсутствие двойного подсчёта трафика. Origin отвечает только после write half-close клиента: полный ответ должен сохраниться после FIN для каждого транспорта. | | T02 | Правильные → неверные → отсутствующие → восстановленные реквизиты каждого узла. Работающие контроли обязательны; отрицательный токен не должен успешно доходить до origin. Надпись «Подключено» при отказах не является успехом. | | T03 | Refused/timeout/reset прокси, недоступный origin, обрезанный ответ; затем восстановление. Ограниченное ожидание, понятная ошибка, восстановление; нет direct fallback вне явно выбранной routing policy. | | T04 | All-app routing на эмуляторе; selected-app на всех устройствах с двумя обычными UID — включённым/исключённым. Переключить local bypass, проверить контролируемые LAN/private и public адреса. Доказывать маршрутом, а не checkbox. | -| T05 | IPv4; IPv6 allow/block при независимо проверенном IPv6 uplink/origin. HTTPS/SSH должны блокировать произвольный UDP/QUIC: при работающем прямом контроле токен не должен попасть на UDP-origin. Если кандидат включает MASQUE α, подтвердить передачу UDP на origin, локальный UDP-bypass и отказ для слишком больших датаграмм; отдельно проверить ограничения Chrome/Firefox и IPv6-target в GOST. HTTP/2 fallback браузера не является QUIC. См. [ограничения MASQUE](masque.md). | +| T05 | IPv4; IPv6 allow/block при независимо проверенном IPv6 uplink/origin. HTTPS через TCP (HTTP/1.1 или HTTP/2) и SSH блокируют проксируемый UDP/QUIC, кроме DNS; настроенный local bypass проверить отдельно: при работающем прямом контроле токен не должен попасть на UDP-origin. Для MASQUE α, HTTPS с выбранным HTTP/3 и SOCKS5 подтвердить передачу UDP на origin, локальный UDP-bypass и отказ для слишком больших датаграмм; отдельно проверить ограничения Chrome/Firefox и IPv6-target в GOST. HTTP/2 fallback браузера не является QUIC. См. [ограничения MASQUE](masque.md). | | T06 | Диагностика IP/страны выхода, отказ основного провайдера и fallback; сверка с egress сервера. Отмена, offline/invalid профиль, отсутствие синтетических секретов в логе. Отказ внешнего провайдера отделять от ошибки туннеля. | | T07 | Передать известный объём, проверить totals upload/download, reset/limit/persistence. Порог ротации SSH-сессии в MiB обновляет сессию согласно настройке; это не квота трафика и не условие отключения VPN. Selected/all failover: недоступный primary, исправный secondary, исчерпанные варианты, Stop во время failover; проверить фактический egress. | | T08 | Проверить [TCP-метрики](connection-metrics.md) на контролируемом трафике: RTT до первого прокси, не до сайта; отсутствие данных отличается от нуля. На отдельном стенде вызвать потери, сопоставить исходящие ретрансляции с независимым захватом и проверить истечение данных через пять минут без новых замеров. Сокеты jump/multiplexing учитываются однократно; отдельная диагностика не меняет метрики, новая сессия VPN сбрасывает их. Результаты native-тестов записывать отдельно от наблюдений на устройствах. | | T09 | Сверить логи успешного согласования HTTPS и SSH (при наличии MASQUE α — также HTTP/3, мультиплексирование и выбранный отпечаток) с контролируемым сервером: версия TLS/шифр/ALPN, фактическая версия HTTP CONNECT после fallback, начальные алгоритмы SSH в обоих направлениях. Проверить оба звена jump. В событиях не должно быть IP, доменов, реквизитов, данных владельца сертификата и полных баннеров; использовать синтетические маркеры. RTT/ретрансляции сами по себе не запускают failover; восстановление после таймаутов/сбросов проверяется отдельно. | +| T10 | Запустить «Тест» для MASQUE, SOCKS5 и HTTPS с выбранным HTTP/3: отдельно записать результаты HTTP/3 Cloudflare и BrowserLeaks. Недоступность одного/обоих не стирает успешные HTTPS/exit-IP результаты. При HTTPS fallback показать предупреждение об UDP без ложного успеха HTTP/3. Native-пробы используют проксируемый UDP без TCP fallback, но обходят Android TUN; дополнительно нужен включённый в VPN обычный браузер/приложение и контролируемый HTTP/3 origin (H06). Доступность внешних сервисов — дополнительное доказательство, не детерминированный CI gate. Во время задержанного временного «Теста» выполнить Stop/start или сменить профиль: старое завершение не останавливает новый VPN и не публикует устаревшие успех/диагностику. | ### Подписка на конфигурацию -На API 26 и API 35 используйте временные HTTPS-источники и синтетические секреты. -Проверьте владение профилями после импорта, ручное обновление на паузе, фоновую -проверку после перезапуска, отказ основного URL и рабочий резервный, возврат к -основному и отказ всех источников. Ответы 401/403, перенаправления, неверный UTF-8, -слишком большой распакованный gzip, ошибочные поля, пустой снимок и конфликт ID -не должны заменять рабочие профили. Добавьте локальный профиль и удалите профиль -подписки из снимка: локальные профили и существующий выбор должны сохраниться. -Измените или удалите подписку во время загрузки: устаревший снимок не применяется. -Проверьте хранение, экспорт и Keystore после перезапуска процесса с маркерами -секретов. Требование переподключения появляется только при изменении активного -соединения; до явного переподключения прежний туннель продолжает передавать трафик. -Первичный импорт не должен включать VPN. +Использовать временные HTTPS-источники и синтетические секреты. Записывать C01–C05 +отдельно; ручное обновление и доставка по расписанию — разные подслучаи. + +| ID | Действия → требуемый результат | +| --- | --- | +| C01 | Импортировать подписку; поставить на паузу и обновить вручную; перезапустить с просроченной проверкой. Отказ primary → рабочий backup → восстановленный primary, затем отказ всех источников. Импорт не включает VPN. При удалении удалённых профилей сохраняются корректное владение, локальные профили и существующий active/Always-on выбор. | +| C02 | Отклонить 401/403, перенаправления, неверный UTF-8, слишком большой распакованный gzip, ошибочные поля, пустой снимок и конфликт ID без замены рабочих профилей. Изменить/удалить подписку во время загрузки: старый результат не применяется и не снимает busy новой проверки. Удалённое описание подписки не заменяет локальные URL/получателей. Проверить шифрование хранения, экспорт без секретов и перезапуск Keystore. | +| C03 | В фоне изменить активный адрес/реквизиты/маршрутизацию при подключённом VPN и при задержанном старте. Сохранить текущий трафик до явного reconnect; после старта также отметить изменения, не попавшие в исходный снимок. Показать приватное уведомление и индикатор в приложении. Смена только имени/неактивного профиля не требует reconnect. Запретить уведомления/канал: действие остаётся в приложении, VPN работает. | +| C04 | Доставить два обновления подряд, использовать актуальное и устаревшее действия reconnect; затем Stop и старое действие. Переподключается только работающий желаемый VPN с текущим токеном. Применение раннего снимка не очищает более новое ожидающее изменение. Проверить новые egress/реквизиты, отмену устаревшего уведомления и отсутствие запуска после Stop. | +| C05 | Обновлять при уходе/пересоздании экрана подписки и при ожидающих сохранениях другого редактора (P06). Завершение снимает busy; записи завершаются либо показывают ошибку/Retry без потери посторонних изменений. Проверить уведомление, логи и снимки задач с синтетическими маркерами URL/пароля/профиля; payload источника и секреты не раскрываются. | + +### SOCKS5 + +Повторить общие сценарии профилей, маршрутизации, DNS, lifecycle, обновления и +диагностики с SOCKS5. Нужен временный GOST с включённым UDP и доступным relay. + +| ID | Действия → требуемый результат | +| --- | --- | +| S01 | Анонимный и авторизованный TCP CONNECT: правильные/неверные/отсутствующие реквизиты, восстановленный контроль, Stop/restart. Отклонить одно заполненное поле реквизитов и значения длиннее 255 UTF-8 байт; проверить многобайтовую границу. Round-trip JSON и socks5:// с секретами и без. SOCKS5 Jump и TLS-отпечаток браузера не поддерживаются; UI/импорт не меняет транспорт молча. Реквизиты SOCKS5 передаются открыто на участке до прокси; использовать только одноразовые секреты. | +| S02 | UDP ASSOCIATE: двоичный echo 1200/1350/4096 байт, несколько адресатов, сервер без UDP, недоступный/невалидный relay. Wildcard relay использует bootstrap IP прокси; hostname relay отклоняется без системного DNS. Закрыть TCP control: старая UDP-ассоциация завершается, новая восстанавливает работу. Совместить с per-app, bypass, IPv6 и D05. | +| S03 | Сверить TCP/UDP totals без двойного подсчёта relay framing; TCP RTT/ретрансляции относятся к TCP/control-сокетам, а не задержке/потерям UDP. Длительный UDP и Stop под нагрузкой; native-регрессию бюджета аллокаций записать отдельно как доказательство отсутствия выделения 64 KiB на каждую датаграмму. Для CPU/памяти устройства нужны собственные длительность и базовая нагрузка. | +| S04 | Failover из/в SOCKS5, HTTPS/SSH и MASQUE: новые TCP/UDP токены origin, актуальные бейдж/реквизиты, отсутствие direct fallback. Отказ или неподдерживаемый UDP сам по себе не доказывает блокировку прокси; HTTP/3 — отдельный результат T10. | ### MASQUE α / HTTP/3 -H01–H11 выполняются на всех четырёх устройствах, если кандидат включает MASQUE. -Также повторить I01–I05, P01–P03, T02–T04, T06–T08, L01–L08, D01–D04 и +H01–H11 проверяют явный MASQUE, H12–H15 — предпочтение HTTP/3 в HTTPS, +включая Jump, на всех четырёх устройствах. +Также повторить I01–I06, P01–P03, P06–P07, T02–T04, T06–T10, C01–C05, L01–L11, D01–D05 и U02–U04 с MASQUE-профилем: проверки транспорта не заменяют общие фичи. Для -кандидата без MASQUE указать N/A и идентичность проверенного артефакта. +кандидата без конкретного режима указать N/A только для его сценариев и идентичность артефакта. Использовать одноразовый GOST-стенд с авторизацией из [инструкции MASQUE](masque.md), зафиксировать версию/конфигурацию, подготовить контролируемые TCP, UDP echo и HTTP/3 @@ -134,23 +151,31 @@ Runner для API 26/API 35 также проверяет Randomized/custom JA3, авторизации, отказ self-signed сертификата с положительным контролем явного исключения, большие UDP-пакеты Chrome/Firefox с последующими малыми пакетами на том же сокете, маршрутизацию по приложениям и failover по таймауту MASQUE → HTTPS -с ручным TLS JA3. Используются одноразовый GOST с авторизацией и приватный origin. +с ручным TLS JA3. Также проверяются анонимный/авторизованный SOCKS5 TCP/UDP, +предпочтение HTTPS и четыре сочетания доступности Jump. Перед одноразовыми +UDP/TCP DNS-пробами подавления AAAA проходит TCP-запрос к приватному origin: +это подтверждает готовность VPN-маршрута до UDP, но не реальное DoH-разрешение +или отсутствие утечек. Используются одноразовый GOST с авторизацией и приватный origin. Это не заменяет проверки доверенного сертификата, DNS-захват, внутренний HTTP/3, IPv6 uplink и физический handover ниже. | ID | Действия → требуемый результат | | --- | --- | -| H01 | Выбрать MASQUE α, сохранить хост/UDP-порт/реквизиты и каждый отпечаток; перезапустить, клонировать, экспортировать/импортировать JSON и ProxyList `masque://`, с секретами и без (P01–P03). JSON сохраняет `proxy.type: "MASQUE"`, порт и настройки; ProxyList — поддерживаемые поля адреса/реквизитов, без глобальных настроек отпечатка. После импорта подтвердить реальное подключение. Проверить EN/RU метку α и включённую по умолчанию проверку сертификата. Jump остаётся только HTTPS/SSH: неподдерживаемые сочетания при импорте отклоняются без тихой смены транспорта или маршрута. | +| H01 | Выбрать MASQUE α, сохранить хост/UDP-порт/реквизиты и каждый отпечаток; перезапустить, клонировать, экспортировать/импортировать JSON и ProxyList `masque://`, с секретами и без (P01–P03). JSON сохраняет `proxy.type: "MASQUE"`, порт и настройки; ProxyList — поддерживаемые поля адреса/реквизитов, без глобальных настроек отпечатка. После импорта подтвердить реальное подключение. Проверить EN/RU метку α и включённую по умолчанию проверку сертификата. Типы Jump-профиля остаются HTTPS/SSH; HTTPS Jump может предпочитать HTTP/3 на обоих узлах (H13). Неподдерживаемые сочетания при импорте отклоняются без тихой смены транспорта или маршрута. | | H02 | Двоичные TCP upload/download и одновременные запросы к двум origins вместе с UDP echo. Сопоставить токены origin с соединениями/потоками GOST: одна общая внешняя QUIC-сессия несёт независимые CONNECT/CONNECT-UDP потоки. Закрыть один поток, остальные продолжают работу. Проверить HTTP/3 и диагностику мультиплексирования; бейдж или лог сами по себе не доказывают трафик и повторное использование сессии. Отсутствие datagram/extended-CONNECT settings сервера или CONNECT-UDP Capsule-Protocol даёт понятный отказ. | | H03 | Правильные → неверный username → неверный пароль → отсутствующие → восстановленные реквизиты для TCP CONNECT и CONNECT-UDP. Отрицательные токены не доходят до origins; зафиксировать отказ GOST и ограниченное ожидание клиента. Успешный QUIC handshake не означает успешную авторизацию. После изменения реквизитов переподключиться и проверить, что старая авторизованная сессия не используется. | | H04 | Доверенный сертификат на правильное имя работает с включённой проверкой; недоверенный/self-signed, wrong-host и просроченный отклоняются без доставки на origin. Явно разрешить исключение только для выбранного стенда, переподключиться, вернуть проверку и повторить отказ. Независимый профиль без явного исключения продолжает проверять сертификаты. Доказательства handshake отделять от HTTP-авторизации. | | H05 | Chrome Android, Firefox Android, Randomized и валидный Custom JA3 (QUIC JA3 в MASQUE-профиле, TLS JA3 в настройках): для каждого новая сессия, TCP и небольшой UDP-пакет; сверить захваченные ClientHello/QUIC transport parameters с выбранным preset/custom полями. Некорректный или несовместимый с QUIC JA3 даёт понятный отказ. Сравнить Randomized в новых сессиях. Зафиксировать версии presets uQUIC и ALPN `h3`; лог выбора профиля не заменяет захват, совпадение preset не доказывает точный полный отпечаток HTTP/3 браузера. | | H06 | UDP echo со сверкой байтов/адреса: 512 байт, Chrome — 1200 байт, размеры вокруг согласованного лимита датаграммы/path MTU; затем реальный QUIC-запрос обычного приложения к контролируемому HTTP/3 origin. Подтвердить выход GOST и фактический HTTP/3 на origin, отключив HTTP/2 fallback для этого запроса. Слишком большой пакет отбрасывается целиком с событием в логе, без обрезания, direct fallback и поломки последующего малого пакета/TCP-потока. Невозможность Firefox передать внутренний QUIC Initial на 1200 байт и отсутствие надёжного capsule fallback в GOST записать как ограничения; малый UDP-пакет не доказывает полноценный QUIC. | | H07 | Повторить selected/all-app routing и local bypass с включённым/исключённым обычными UID, public/LAN TCP и UDP origins и проверенными IPv4/IPv6 контролями (T04–T05). IPv4-only блокирует IPv6 TCP и UDP; при включённом IPv6 проверить TCP и локальный UDP-bypass. Отказ GOST 3.3.0 для IPv6 literal CONNECT-UDP выделить как BLOCKED для туннельного UDP, а не PASS для IPv6 UDP или допустимый direct fallback. | -| H08 | Новые имена через выбранный DoH, отказ primary → fallback → отказ всех (D01–D02). Сопоставить DoH через TCP-туннель MASQUE и внешний DNS-захват: UDP/53 сохраняет обработку DoH, а не становится произвольным CONNECT-UDP или неожиданным plaintext DNS. Отдельно проверить Private DNS/lockdown; без внешнего захвата защита от утечек остаётся NOT TESTED. | +| H08 | Новые имена через выбранный DoH, отказ primary → fallback → отказ всех (D01–D02). Сопоставить DoH через TCP-туннель MASQUE и внешний DNS-захват: UDP/TCP порт 53 (D05) сохраняет обработку DoH, а не становится произвольным CONNECT-UDP или неожиданным plaintext DNS. Отдельно проверить Private DNS/lockdown; без внешнего захвата защита от утечек остаётся NOT TESTED. | | H09 | Сверить известный объём TCP/UDP с totals/rates, IEC/SI, reset/persistence, IP/страной выхода в Test и fallback провайдера (T06–T08). Проверить HTTP/3 бейдж и события мультиплексирования, убрать устаревший статус после Stop/смены профиля. Для MASQUE проверить QUIC RTT и объявления потерь исходящих пакетов за пять минут: ноль/нет данных, истечение окна, сброс сессии и однократный учёт общей сессии; QUIC не должен показывать выдуманные kernel TCP RTT/ретрансляции. Проверить диагностику синтетическими маркерами: нет реквизитов, идентичности targets, host-key pins и деталей сертификата; есть TLS/шифр/ALPN, числовые ошибки QUIC и сопоставимые локальные номера потоков/сессий, повторения ограничены, Stop не создаёт ложных DPI-ошибок; приватный захват — отдельное доказательство. | -| H10 | Заблокировать UDP-порт прокси при доступном TCP/443, перезапустить GOST, отключить/вернуть сеть, повторить реальный Wi-Fi/mobile handover (L01–L08). Ограниченное ожидание при отказах, новые рабочие TCP/UDP-потоки после восстановления; старые могут завершиться. Stop во время handshake/reconnect исключает позднее подключение и трафик. Нет неявного HTTPS или direct fallback; виртуальная cellular-сеть не доказывает handover оператора, восстановление не доказывает QUIC connection migration. | -| H11 | Selected/all-profile failover: недоступный MASQUE primary, исправный secondary, исчерпанные варианты и Stop при переключении (T07). Проверить MASQUE→HTTPS/SSH и HTTPS/SSH→MASQUE, включая отдельные валидные custom TLS/QUIC JA3; сверить TCP egress и новые UDP-токены. UDP соответствует активному транспорту: MASQUE передаёт поддерживаемые пакеты, HTTPS/SSH блокируют UDP кроме DNS. После переключения нет старого бейджа/сессии/реквизитов, неожиданного прямого доступа и двойного подсчёта. | +| H10 | Заблокировать UDP-порт прокси при доступном TCP/443, перезапустить GOST, отключить/вернуть сеть, повторить реальный Wi-Fi/mobile handover (L01–L08). Ограниченное ожидание при отказах, новые рабочие TCP/UDP-потоки после восстановления; старые могут завершиться. Stop во время handshake/reconnect исключает позднее подключение и трафик. У явного MASQUE нет неявного HTTPS или direct fallback (предпочтение HTTPS — H12–H15); виртуальная cellular-сеть не доказывает handover оператора, восстановление не доказывает QUIC connection migration. | +| H11 | Selected/all-profile failover: недоступный MASQUE primary, исправный secondary, исчерпанные варианты и Stop при переключении (T07). Проверить MASQUE→HTTPS/SSH и HTTPS/SSH→MASQUE, включая отдельные валидные custom TLS/QUIC JA3; сверить TCP egress и новые UDP-токены. UDP соответствует активному транспорту: MASQUE передаёт поддерживаемые пакеты, HTTPS через TCP и SSH блокируют проксируемый UDP кроме DNS; SOCKS5 и HTTPS с выбранным HTTP/3 также передают поддерживаемый UDP. После переключения нет старого бейджа/сессии/реквизитов, неожиданного прямого доступа и двойного подсчёта. | +| H12 | HTTPS: галочка выключена — TCP; включена — HTTP/3 на том же хосте/числовом UDP-порту, если доступен. Заблокировать UDP при доступном TCP: необязательная проба ограничена тремя секундами, затем работает HTTP/2 или HTTP/1.1 с видимым предупреждением об UDP-fallback и сохранением DoH. Сама проба не вызывает предупреждение о блокировке/failover. Reconnect повторяет выбор; установленные HTTP/3 потоки не мигрируют молча в TCP. JSON/клонирование/restart сохраняют галочку; простые proxy URL её не переносят. | +| H13 | HTTPS Jump: H3/H3, H3/только TCP, только TCP/H3 и только TCP/только TCP. Только первая пара использует вложенный HTTP/3; иначе вся цепочка откатывается в HTTPS через jump, без прямого подключения к exit. Проверить отдельные реквизиты/сертификаты, удалённое разрешение exit-host, реальный TCP и UDP 1200/1280/1350 байт, асимметричный MTU/потери и Stop во время exit handshake. Захватить оба узла; внешний handshake не доказывает авторизацию exit или работоспособность внутреннего QUIC. | +| H14 | Для каждого применимого узла разделить недоступный протокол/settings, CONNECT-UDP 404/405/501 и отсутствие Capsule-Protocol (fallback допустим) от неверных реквизитов, сертификатов, access denied и неожиданных ошибок сервера (терминальный отказ без downgrade). Edge/несовместимый с QUIC custom-отпечаток выбирает HTTPS; Firefox Jump откатывается из-за лимита датаграммы. Ошибка socket protection/неизвестная ошибка требует native fault-injection. Явный MASQUE по-прежнему завершается отказом без fallback. | +| H15 | При работающем QUIC вызвать потери ACK/ретрансляции, GOAWAY и локальные дедлайны запросов. Новые потоки восстанавливаются, независимые исправные остаются рабочими там, где это допускает протокол. Отдельно записать native-регрессию ретрансляции uQUIC; успешный handshake её не проверяет. Ошибки потоков одной упавшей QUIC-сессии не считаются независимыми свидетельствами блокировки; проверить независимые отказы и последующее успешное восстановление туннеля (L10). | Вердикты разделять по отпечатку, TCP/UDP, размеру пакета и семейству адресов. Существующие `native_integration` и сценарии API 26/API 35 — дополнительные @@ -171,6 +196,9 @@ TCP/UDP 512 байт не доказывают проверку доверенн | L06 | Обновить APK при подключённом VPN, проверить package-replaced recovery реальным трафиком. Повторить после явного Stop: обновление не должно включить соединение. Сохранить подпись/вариант; fixture-версии не публиковать. | | L07 | Direct Boot на выделенном эмуляторе с временным PIN: подтвердить `RUNNING_LOCKED` до/после проб обычного direct-boot UID; затем unlock/retest. Чёрный экран и проверка после unlock не заменяют сценарий. Отметить, обещает ли продукт работу до unlock. | | L08 | Forced Doze: screen-off/IDLE, exemption state, обычный UID, отказ/восстановление сервера; unforce/reset battery/retest. Отдельно foreground/background soak минимум 15 минут с фактической длительностью. Shell UID не является контролем обычного фонового приложения. Суточное поведение/энергопотребление проверяются отдельно. | +| L09 | Stop при зависшем HTTP/1 CONNECT, заполненных очередях SSH/QUIC и открытых TCP/UDP local-bypass или DNS потоках. Старые сокеты и ожидания быстро завершаются; старые серверные потоки не передают новые токены. Повторить быстрые Stop/start/смену профиля и задержанные callbacks: новый VPN, протокол, предупреждение и профиль остаются актуальными. Разрешённый политикой Android прямой трафик после Stop отличается от утечки старого туннеля; нужны доказательства по конкретным соединениям и отдельный lockdown-контроль. | +| L10 | Задать устаревший bootstrap IP прокси/jump, сменить DNS-ответ, вызвать refused/unreachable: ограниченное свежее разрешение восстанавливает работу, отказ сам по себе не доказывает блокировку; поздняя ошибка не удаляет более новый адрес. Вызвать реальные ошибки прокси внутри/вне окна 60 секунд, затем успешный туннель: старое предупреждение о блокировке исчезает, посторонние предупреждения сохраняются. Target reset, локальный deadline, ошибка local bypass и дубликаты общей сессии не вызывают глобальный failover. Провести здоровый soak с указанной длительностью; длительный тест записать отдельно от минимума 15 минут. | +| L11 | Включить в failover пустые черновики, несовместимые транспорт/отпечаток и нечитаемые реквизиты вместе с рабочей альтернативой: пропустить невалидные эффективные конфигурации с учётом общих настроек, выбрать только разрешённого валидного кандидата. Повторить selected/all/исчерпание. Для SSH и SSH Jump прекратить ответы keepalive: дедлайн ответа десять секунд закрывает мёртвую сессию, новые запросы восстанавливаются; Stop прерывает ожидание. Проверить двунаправленные/half-close ответы, лимит каналов и ротацию сессии под нагрузкой. | ### DNS, lockdown и внешнее управление @@ -180,13 +208,14 @@ TCP/UDP 512 байт не доказывают проверку доверенн | D02 | Direct → active VPN → proxy outage → force-stop+lockdown → restart → direct. Дважды свежие имена из обычных приложений и безопасно выбранных браузеров. Захват IPv4/IPv6 UDP/TCP 53 и strict Private DNS/853, где доступны. Второй capture VPN заменит проверяемый VPN и недопустим. Без внешнего capture отсутствие утечек — NOT TESTED. | | D03 | Сверить известные Android/OEM ограничения с актуальными первоисточниками. Отделять наблюдаемую утечку от её причины, shell-only эффектов, Secure DNS браузера и отказа стенда. Указать точную сборку ОС; не переносить вывод на все Android. | | D04 | Обычным тестовым приложением попробовать внешние intents/broadcasts/provider access. Закрытые receivers и trust/export screens не должны отдавать секреты или менять VPN/доверие. Проверить manifest и runtime отказ. Привилегии ADB shell не заменяют обычный UID. | +| D05 | Для каждого транспорта и результата предпочтения HTTPS отправить явные UDP/53 и фреймированные TCP/53 запросы от обычного UID, включая LAN при включённом bypass. Оба используют настроенный DoH с политикой fallback/IPv6; открытый TCP retry не утекает. Проверить фрагментацию TCP-префикса/payload, pipelined ID, write half-close с ожидающими ответами, таймаут, ошибочную длину и Stop. Primary/fallback/отказ всех и подавление AAAA; CUSTOM и фильтрующие провайдеры не меняются молча на нефильтрующие. Отделять перехват от Android Private DNS/browser Secure DNS, которые следуют обычной маршрутизации. Native-стенды framing/DoH дополняют, но не заменяют захват пакетов. | ### Обновление и распространение | ID | Действия → требуемый результат | | --- | --- | | U01 | Официальный и сторонний F-Droid (обработчики fdroidrepo/fdroidrepos), браузер/файловый установщик, неизвестный; ручной выбор. Посторонний установленный клиент F-Droid не меняет источник установки из браузера. Проверить API и persistence. Неопубликованный F-Droid пакет даёт понятную ошибку без перехода на GitHub. Подмена installer metadata не является установкой из репозитория. | -| U02 | Новая/та же/старая/повреждённая metadata, offline. Download consent/cancel; size/digest/package/version/signer/ABI, повреждение/обрыв APK. Заведомо неверные APK проверять unit-тестами и изолированными эмуляторами. | +| U02 | Новая/та же/старая/повреждённая metadata, offline. Download consent/cancel; size/digest/package/version/signer/ABI, повреждение/обрыв APK. Заведомо неверные APK проверять unit-тестами и изолированными эмуляторами. После повторных загрузок остаются текущий APK и один предыдущий для активного установщика; .part старше двух суток удаляются без удаления свежей загрузки. Для кеша использовать контролируемое время и проверить чтение выданного URI установщиком. | | U03 | Universal остаётся universal, ABI-specific — тем же ABI; отказ/выдача install permission, Cancel, возврат из Settings, установка. Прочитать обратно APK/version/signature и проверить передачу данных. | | U04 | Notification permission/channel; Update/Skip/Disable; manual после Skip; выключение при работающем job; восстановление job после reboot. Раннего напоминания нет, после семи дней есть — контролируемой правкой времени на эмуляторе. Forced jobs/time simulation не называть реальной суточной/недельной доставкой. | @@ -198,6 +227,19 @@ TCP/UDP 512 байт не доказывают проверку доверенн | E02 | Остановить стенды/captures; удалить только созданные forwards/reverses, probe APK/файлы и тестовые профили. Вернуть routing, active/Always-on, permissions, сеть/Private DNS, экран/шрифт/язык/battery и исходное состояние VPN. Сохранить оригинальные данные. Проверить каждое устройство, указать остаточные изменения. | | E03 | Повторно сверить commit/hash, заполнить все ячейки и ссылки. Выводы по функциям, без истории отладки стенда. Приватные исходные материалы не включать в PR; проверить allowlist добавляемых файлов. | +## Актуализация регламента + +До выбора сценариев зафиксировать последний коммит каждой языковой версии и +проверить все последующие коммиты кандидата (`git log BASE..CANDIDATE` и diff), +а не только changelog. Каждую фичу/исправление сопоставить с ID сценариев и +существующими JVM/Go/device-тестами; пробелы оставить явными. Дополнительно сверить +полный текущий набор фичей: возможность могла появиться до BASE, но не попасть +в регламент. Разделять автоматические доказательства и вердикты подписанного APK +на устройствах, включая skipped-наборы и ограничения стенда. Сохранять ID сценариев +и датированные исторические отчёты; обновлять обе локали вместе. Автоматический +release workflow проверяет CI и публикует после тега; эту ручную матрицу он не +собирает и не делает обязательным автоматическим условием. + ## Ошибки, исправления и решение о релизе Воспроизвести ошибку на неизменённом кандидате и сохранить доказательства: серьёзность,