ZapretKVN-android/docs/GATE8_RESULTS.md
2026-07-24 20:54:45 +03:00

164 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Gate 8 — протокол выпускной матрицы
Дата локального прогона: 22 июля 2026 года. Этот документ отделяет доказанное на AVD
от проверок, для которых обязательно реальное устройство, оператор или VPN-сервер.
Stable `v0.2.1` опубликован 23 июля 2026 года по явному решению владельца. Публикация
не заменяет перечисленные ниже физические проверки и не переводит незакрытые пункты
Gate 8 в пройденные.
## Автоматизированные результаты
| Среда | Полный набор | Дополнительная проверка | Результат |
|---|---:|---|---|
| Android 8, API 26 AVD | 66/66 + security delta 3/3 | legacy resolver, clipboard/log/export/notification security | пройдено |
| Android 10, API 29 AVD | 66/66 | `DnsResolver`, Private DNS, Always-on/Lockdown API | пройдено |
| Android 16, API 36 AVD | 67/67 | современный lifecycle, UI, security и signing history | пройдено |
JVM: 85/85. Exact core fixtures: 6/6. Pinned core:
`ff11f007ec798136a5de258f947a4f34011a37ea`.
`scripts/verify-gate8-stress.sh` отдельно выполнил на API 29 и API 36:
- 100 последовательных connect/stop;
- 50 реальных переключений эмуляторной Wi-Fi/cellular underlying network;
- ровно 151 создание core: 100 подключений, одно подключение перед переходами и 50 restart;
- после завершения: session/core/TUN/callback = 0;
- FD и thread count не превысили прогретый baseline более чем на два.
Команда использует только debug receiver, защищённый `android.permission.DUMP`. Receiver
отсутствует в release APK и дополнительно запрещён manifest-аудитом CI.
## Найденные проблемы
На API 29 `getPackageArchiveInfo()` вернул `signingInfo=null` для корректного APK.
Verifier исправлен: запрашивает `GET_SIGNING_CERTIFICATES | GET_SIGNATURES`; если Android
не предоставляет signing history, применяется более строгая проверка точного текущего
сертификата. Чужая подпись от этого не принимается.
Внешний strict Private DNS дважды показал единичный timeout/EOF. Production корректно
закрыл TUN. Тест повторяет успешную проверку не более одного раза и только после полного
cleanup, моделируя явный повтор подключения пользователем; health-check приложения не
получил скрытого retry или fallback.
## Статус R8-01–R8-10
- `R8-02`, `R8-03`, `R8-05`, `R8-10` — автоматизированная часть пройдена.
- `R8-04` — AVD Wi-Fi/cellular, IPv4/IPv6 dual-stack и captive-portal fail-close пройдены;
физические cellular, IPv6-only/NAT64 и настоящий captive portal остаются открыты.
- `R8-06` — автоматизированная DNS matrix пройдена; физическая часть DNS ADR открыта.
- `R8-07` — exact/AVD routing matrix пройдена; повтор на физических OEM открыт.
- `R8-09` — пустые списки, удалённый package и revoke пройдены; shared UID открыт.
- `R8-01` и `R8-08` нельзя закрыть без реального слабого телефона и доступных тестовых
серверов каждого заявленного протокола.
## Что нужно для оставшихся галочек
1. Реальный слабый телефон API 26/28 и современный телефон Android 14+.
2. SIM/mobile data, отдельная IPv6-only/NAT64 сеть и настоящий captive portal.
3. Два подписанных тестовых APK с общим UID либо подготовленный device fixture.
4. Контролируемые VLESS, VMess, Trojan, Shadowsocks, Hysteria2 и TUIC endpoints с
TCP, UDP и QUIC сценариями.
До этих прогонов проект не объявляется готовым к публичному release.
## CPU, память и батарея — автоматизированный прогон
22 июля 2026 года `scripts/verify-gate8-performance.sh` выполнил на API 36 AVD
16 сценариев по пять повторов. Каждый сравниваемый вариант запускался в новом app
process, использовал один и тот же pinned core и одинаковый workload: 5 секунд idle,
8 MiB TCP echo либо 12 уникальных DNS-имён. Один process CPU tick равен 10 мс.
| Сценарий, median 5 прогонов | CPU ticks | PSS | TUN bytes | UID RX+TX | Throughput |
|---|---:|---:|---:|---:|---:|
| VPN off, экран выключен | 0 | 93 150 KiB | 0 | 0 | — |
| VPN idle, экран выключен | 2 | 149 303 KiB | 0 | 0 | — |
| Невыбранный UID, 8 MiB | 1 | 146 405 KiB | 0 | 0 | 9,34 Mbit/s |
| Выбранный `direct`, 8 MiB | 43 | 147 097 KiB | 34 581 272 | 53 090 760 | 5,22 Mbit/s |
| Выбранный SOCKS proxy, 8 MiB | 45 | 146 339 KiB | 34 638 464 | 53 173 520 | 5,13 Mbit/s |
| Главная видима, 5 секунд | 8 | 146 580 KiB | 0 | 0 | — |
| UI закрыт, 5 секунд | 2 | 146 699 KiB | 0 | 0 | — |
| Диагностика видима, 5 секунд | 0 | 151 149 KiB | 0 | 0 | — |
В пяти idle-окнах UID Zapret KVN передал ровно 0 байт и держал 0 status/log clients.
Счётчик TUN дважды вырос на 96 байт; это интерфейсный шум, не app-owned network traffic.
В пяти передачах по 8 MiB невыбранным UID сетевой счётчик Zapret KVN оставался равен
нулю, а TUN изменился только один раз на 96 байт. Для выбранного `direct` тот же workload
дал median 53 090 760 UID bytes и 34 581 272 TUN bytes. Тем самым harness проверяет
Android per-app boundary независимо двумя счётчиками и не выдаёт отсутствие пакетов TUN
за отсутствие фонового трафика самого приложения.
`sequential` обработал 12 уникальных DNS-имён за median 137,6 мс, `parallel` —
за 155,0 мс. На этом AVD parallel не дал выигрыша и создавал второй DoH запрос;
managed default остаётся `sequential`.
Сравнения `mixed`/`system`, MTU 9000/1500 и GCPercent 100/10 дали менее 5% разницы
по throughput, времени, CPU и PSS. По принятой политике это шум, поэтому текущие
defaults не изменены и новые GUI-переключатели не добавлены. Direct/proxy различались
менее чем на 5% по CPU, throughput и PSS; это разные пользовательские пути, а не
взаимозаменяемые defaults. Реальный VPN-сервер всё равно нужен для физической матрицы.
Сырые данные сохранены локально в
`build/gate8-performance/api36-sdk_gphone64_x86_64-20260722T110520Z/`: 80 JSONL
измерений, raw-файлы `batterystats`/meminfo/procstats/power/alarm/job/netstats,
System Trace и общий `SHA256SUMS` — 134 файла суммарно. SHA-256 `summary.json`:
`6a3afd854c0f98b36325179c84d86f58d7edd841fbcd9481874875767a9ae77e`; SHA-256
итогового manifest: `53ef9ba18ca1bba79fb9d50206f028bcfca808b1e4150efdca16ae2185aa36f5`.
Ручной `workflow_dispatch` CI запускает ту же API 36 матрицу и загружает каталог как
artifact.
Совместимость harness отдельно проверена на API 26 AVD сокращённым workload
(5 × 16 сценариев, 1 секунда idle, 1 MiB, 2 DNS-имени). Прогон прошёл полностью;
для отсутствующего в Android 8 `getconf` metadata честно фиксирует стандартный Linux
`USER_HZ=100` как `clock_ticks_source=linux-user-hz`. Эти smoke-цифры не участвуют в
выборе defaults и не заменяют слабое физическое устройство.
Это исследовательские AVD-данные: `energy_valid=false`. Они не закрывают обязательный
release/profileable прогон на слабом API 26/28 и современном физическом устройстве,
PowerMetric/ODPM или batterystats при стабильной температуре, Go GC count/pause и OOM.
## Security и release candidate
`scripts/verify-release-candidate.sh` проверяет уже собранный arm64 APK, а не только
исходный manifest. На локальном RC подтверждены:
- точный permission allowlist, `Debug=false`, backup/cleartext/process restrictions;
- единственный non-exported VPN service и bounded non-exported FileProvider;
- отсутствие runtime profile/diagnostic/update/temp material и security canaries в APK;
- APK 75 505 859 bytes (`f677408c8c1e576e916235dda5ad7bdbbb6ef518f61cc199240c89d15c04fed0`),
R8 mapping 39 743 272 bytes;
- отдельный `native-debug-symbols.zip` 44 208 695 bytes с `.symtab`/`.debug_info`;
- совпадение всех 26 allocated ELF-секций symbols build с production `libbox` pinned commit
`ff11f007ec798136a5de258f947a4f34011a37ea`.
После нормализации ZIP metadata два независимых symbols build дали одинаковый SHA-256
`f8ffac5ec47f83baeb012f23d0eb86dcae876f25f44f2214621d148b6d01663a`.
Managed runtime удаляет внешний Clash listener и связанные UI/secret поля. Instrumented
security tests проверяют redaction уже в памяти, export/share/temp cleanup, отсутствие
app-private clipboard history и foreground notification из закрытого enum состояний.
`scripts/verify-release-device.sh` собрал два minified x86_64 RC одной временной подписью и
на API 36 выполнил clean install, пять force-stopped cold starts, same-key update, запуск
после update, отказ downgrade и чужой подписи. Cold start: 399/419/423/371/407 ms,
median 407 ms; release `run-as` отклонён, process crash отсутствует.
`R8-21…R8-24` закрыты. `R8-25` остаётся открытым только для последнего arm64 APK,
подписанного постоянным GitHub release key и установленного/обновлённого на реальном
устройстве непосредственно перед публикацией. Временный тестовый ключ не выдаётся за
production evidence.
Host-side audit stable `v0.2.1` пройден для всех трёх ABI. Arm64 APK имеет SHA-256
`170faf123593ca1c2e24cdabd9ab9032860bf5eae001c1d23642c2ae39ef08fa`,
signer SHA-256
`f718835f014c8c4bfdcb281483eb9aea0d33cf705f7f1399545821b164f58898`
и exact core `ff11f007ec798136a5de258f947a4f34011a37ea`. Это не заменяет открытый
real-device прогон `R8-25`.
Stable publisher запускается локально после явного `--final-gate-approved`, сверяет
production JKS с закреплённым публичным SHA-256, повторяет host-side build/test/security
gates и создаёт GitHub Release без ожидания GitHub Actions. После публикации фоновый
workflow с одноразовым тестовым ключом повторяет 67 instrumented-тестов, process
recreation, 100/50 stress и no-background-traffic matrix, затем скачивает Release и
проверяет metadata, checksum, ABI, version и production fingerprint. Production key
в GitHub Actions больше не передаётся.