docs: record clean production acceptance
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
# Чек-лист приёмки перед production-выкладкой
|
# Чек-лист приёмки перед production-выкладкой
|
||||||
|
|
||||||
Исторический synthetic validation для версии 0.3.1 зафиксирован в [`VALIDATION_0.3.1.md`](VALIDATION_0.3.1.md). Он подтверждает перечисленные там проверки, но не заменяет этот production acceptance checklist.
|
Исторический synthetic validation и выполненный clean production acceptance версии 0.3.1 зафиксированы в [`VALIDATION_0.3.1.md`](VALIDATION_0.3.1.md). Этот checklist остаётся воспроизводимой процедурой приёмки для следующих установок.
|
||||||
|
|
||||||
|
> Clean production acceptance release artifact `v0.3.1` выполнен 2026-08-29 на Debian 13 + AmneziaWG 3.1. Итог: PASS; production GO подтверждён. Не наблюдались только фактический scheduler-triggered reboot и повторный multi-peer load-test; anti-torrent threshold выше 500 намеренно не создавался.
|
||||||
|
|
||||||
## A. Базовая установка
|
## A. Базовая установка
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@
|
|||||||
3. [`INSTALLATION.md`](INSTALLATION.md) — сжатый порядок установки на production.
|
3. [`INSTALLATION.md`](INSTALLATION.md) — сжатый порядок установки на production.
|
||||||
4. [`CONFIGURATION.md`](CONFIGURATION.md) — параметры `/etc/awg2-harness/config.toml`.
|
4. [`CONFIGURATION.md`](CONFIGURATION.md) — параметры `/etc/awg2-harness/config.toml`.
|
||||||
5. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — чек-лист приёмки перед статусом production-ready.
|
5. [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) — чек-лист приёмки перед статусом production-ready.
|
||||||
6. [`VALIDATION_0.3.1.md`](VALIDATION_0.3.1.md) — фактически выполненные Debian 13 build/package/runtime-проверки версии 0.3.1 и их ограничения.
|
6. [`VALIDATION_0.3.1.md`](VALIDATION_0.3.1.md) — synthetic validation и clean production acceptance release artifact `v0.3.1` на Debian 13 + AmneziaWG 3.1, включая ограничения прогона.
|
||||||
7. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — ограничение числа соединений через nftables.
|
7. [`ANTI_TORRENT.md`](ANTI_TORRENT.md) — ограничение числа соединений через nftables.
|
||||||
8. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — архитектура и reconciliation состояния.
|
8. [`IMPLEMENTATION_SPEC.md`](IMPLEMENTATION_SPEC.md) — архитектура и reconciliation состояния.
|
||||||
|
|
||||||
|
|||||||
+359
-6
@@ -1,6 +1,9 @@
|
|||||||
# AWG2 Harness 0.3.1 — отчёт о валидации
|
# AWG2 Harness 0.3.1 — отчёт о валидации
|
||||||
|
|
||||||
Дата проверки: 2026-08-28
|
Даты проверок:
|
||||||
|
|
||||||
|
- 2026-08-28 — synthetic runtime validation;
|
||||||
|
- 2026-08-29 — clean production acceptance.
|
||||||
|
|
||||||
## 1. Назначение
|
## 1. Назначение
|
||||||
|
|
||||||
@@ -12,7 +15,8 @@
|
|||||||
- в каком окружении выполнялись проверки;
|
- в каком окружении выполнялись проверки;
|
||||||
- какие свойства подтверждены реальным Linux runtime;
|
- какие свойства подтверждены реальным Linux runtime;
|
||||||
- какие проверки были negative/fail-closed;
|
- какие проверки были negative/fail-closed;
|
||||||
- какие сценарии остаются до production acceptance.
|
- какие сценарии оставались после synthetic-прогона;
|
||||||
|
- какие из них затем закрыты clean production acceptance.
|
||||||
|
|
||||||
Сырой terminal dump намеренно не включён в репозиторий: в нём присутствуют public keys, container IDs и инфраструктурные детали. Ниже сохранены воспроизводимые команды, существенные наблюдения и границы результата.
|
Сырой terminal dump намеренно не включён в репозиторий: в нём присутствуют public keys, container IDs и инфраструктурные детали. Ниже сохранены воспроизводимые команды, существенные наблюдения и границы результата.
|
||||||
|
|
||||||
@@ -340,7 +344,7 @@ Conntrack count читается из Amnezia network namespace, global max —
|
|||||||
|
|
||||||
Для отдельного daemon recovery test необходимо использовать clean/owned swap state либо временно отключить `[swap]`.
|
Для отдельного daemon recovery test необходимо использовать clean/owned swap state либо временно отключить `[swap]`.
|
||||||
|
|
||||||
## 20. Сводный результат
|
## 20. Сводный результат synthetic run
|
||||||
|
|
||||||
| Контур | Статус |
|
| Контур | Статус |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -374,7 +378,7 @@ Conntrack count читается из Amnezia network namespace, global max —
|
|||||||
| End-to-end VPN | NOT RUN |
|
| End-to-end VPN | NOT RUN |
|
||||||
| AWG 3.1 production acceptance | NOT RUN |
|
| AWG 3.1 production acceptance | NOT RUN |
|
||||||
|
|
||||||
## 21. Что этим test run не доказано
|
## 21. Что не доказал synthetic run
|
||||||
|
|
||||||
Не проверены:
|
Не проверены:
|
||||||
|
|
||||||
@@ -390,7 +394,7 @@ Conntrack count читается из Amnezia network namespace, global max —
|
|||||||
|
|
||||||
Эти проверки остаются обязательной частью clean production AWG 3.1 acceptance.
|
Эти проверки остаются обязательной частью clean production AWG 3.1 acceptance.
|
||||||
|
|
||||||
## 22. Итог
|
## 22. Итог synthetic run
|
||||||
|
|
||||||
Для полного synthetic runtime-прогона на `7390d1f` и отдельной финальной build/runtime-проверки swap delta на `3757302` подтверждены:
|
Для полного synthetic runtime-прогона на `7390d1f` и отдельной финальной build/runtime-проверки swap delta на `3757302` подтверждены:
|
||||||
|
|
||||||
@@ -412,6 +416,355 @@ Conntrack count читается из Amnezia network namespace, global max —
|
|||||||
|
|
||||||
**Synthetic runtime validation: PASS for tested components.**
|
**Synthetic runtime validation: PASS for tested components.**
|
||||||
|
|
||||||
**Production AWG 3.1 acceptance: NOT RUN.**
|
**Production AWG 3.1 acceptance в этом synthetic run: NOT RUN.**
|
||||||
|
|
||||||
Окончательный production GO требует выполнения [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) на clean Debian 13 host с рабочим AWG 3.1 и реальным client traffic.
|
Окончательный production GO требует выполнения [`ACCEPTANCE_CHECKLIST.md`](ACCEPTANCE_CHECKLIST.md) на clean Debian 13 host с рабочим AWG 3.1 и реальным client traffic.
|
||||||
|
|
||||||
|
Требуемый clean production acceptance был выполнен 2026-08-29; результаты приведены в следующем разделе.
|
||||||
|
|
||||||
|
## 23. Clean production acceptance — Debian 13 / AmneziaWG 3.1
|
||||||
|
|
||||||
|
Дата проверки: 2026-08-29
|
||||||
|
|
||||||
|
Проверенный release artifact:
|
||||||
|
|
||||||
|
- tag: `v0.3.1`;
|
||||||
|
- package: `awg2-harness_0.3.1_amd64.deb`;
|
||||||
|
- SHA256: `90dc8bb85f60740ca3358e40c31592b5165e250f878169ad6d05bdee3656f1b8`.
|
||||||
|
|
||||||
|
Проверка выполнена после публикации релиза. Этот раздел фиксирует post-release evidence и не изменяет tag или опубликованный artifact `v0.3.1`.
|
||||||
|
|
||||||
|
### 23.1. Окружение
|
||||||
|
|
||||||
|
- Debian GNU/Linux 13.6 (trixie);
|
||||||
|
- amd64;
|
||||||
|
- kernel: `6.12.105+deb13-amd64`;
|
||||||
|
- Docker: `26.1.5+dfsg1`;
|
||||||
|
- container: `amnezia-awg2`;
|
||||||
|
- AmneziaWG tools: `v3.1.20260812`;
|
||||||
|
- AWG interface: `awg0`;
|
||||||
|
- AWG peer CIDR: `10.8.1.0/24`;
|
||||||
|
- server peer `AllowedIPs`: IPv4 `/32`;
|
||||||
|
- host UDP port: `2053`;
|
||||||
|
- SSH port: `2323`.
|
||||||
|
|
||||||
|
Production limits:
|
||||||
|
|
||||||
|
- per-peer limit: `60mbit`;
|
||||||
|
- root rate: `600mbit`;
|
||||||
|
- anti-torrent connection limit: `500` per peer.
|
||||||
|
|
||||||
|
### 23.2. Clean installation
|
||||||
|
|
||||||
|
До установки AWG2 Harness:
|
||||||
|
|
||||||
|
- `/etc/awg2-harness` отсутствовал;
|
||||||
|
- harness iptables/ip6tables rules отсутствовали;
|
||||||
|
- harness nftables table отсутствовала;
|
||||||
|
- `ifb0` отсутствовал;
|
||||||
|
- swap отсутствовал;
|
||||||
|
- harness sysctl persistence files отсутствовали.
|
||||||
|
|
||||||
|
Установка release package завершилась успешно.
|
||||||
|
|
||||||
|
После установки:
|
||||||
|
|
||||||
|
- production config автоматически не создавался;
|
||||||
|
- `awg2-harness.service` был `disabled/inactive`;
|
||||||
|
- `awg2-reboot-scheduler.service` был `disabled/inactive`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.3. AmneziaWG 3.1 discovery
|
||||||
|
|
||||||
|
Runtime discovery определил:
|
||||||
|
|
||||||
|
- container `amnezia-awg2`;
|
||||||
|
- interface `awg0`;
|
||||||
|
- listen port `2053`;
|
||||||
|
- peer `10.8.1.1/32`.
|
||||||
|
|
||||||
|
`validate-config` и `validate-runtime` завершились успешно.
|
||||||
|
|
||||||
|
Docker UDP contract:
|
||||||
|
|
||||||
|
- `0.0.0.0:2053`;
|
||||||
|
- `[::]:2053`;
|
||||||
|
- inner AWG listen port `2053`;
|
||||||
|
- `port_contract: ok`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.4. Swap — clean positive path
|
||||||
|
|
||||||
|
На исходном сервере active swap отсутствовал.
|
||||||
|
|
||||||
|
`ensure-swap` создал managed `/swapfile`:
|
||||||
|
|
||||||
|
- size: 2048 MiB;
|
||||||
|
- mode: `0600`;
|
||||||
|
- priority: `1`;
|
||||||
|
- `/etc/fstab`: `/swapfile none swap sw,pri=1 0 0`;
|
||||||
|
- `vm.swappiness = 1`;
|
||||||
|
- ownership record создан;
|
||||||
|
- `status`: `drift: no`.
|
||||||
|
|
||||||
|
Повторный `ensure-swap` сохранил тот же inode, размер и содержимое `/etc/fstab`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.5. Network tuning
|
||||||
|
|
||||||
|
До reconciliation:
|
||||||
|
|
||||||
|
- `net.core.rmem_max = 212992`;
|
||||||
|
- `net.core.wmem_max = 212992`;
|
||||||
|
- `net.ipv4.ip_forward = 1`;
|
||||||
|
- congestion control: `cubic`.
|
||||||
|
|
||||||
|
После `apply-network-tuning`:
|
||||||
|
|
||||||
|
- `net.core.rmem_max = 67108864`;
|
||||||
|
- `net.core.wmem_max = 67108864`;
|
||||||
|
- `net.ipv4.ip_forward = 1`;
|
||||||
|
- persisted config совпадает с desired state;
|
||||||
|
- `tcp_bbr = "off"` не включает и не персистит BBR;
|
||||||
|
- runtime congestion control остался `cubic`;
|
||||||
|
- `drift: no`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.6. Traffic shaping — clean AWG 3.1
|
||||||
|
|
||||||
|
На исходном `awg0` присутствовал только штатный root `fq_codel`. `ifb0`, HTB classes и peer filters отсутствовали.
|
||||||
|
|
||||||
|
Первый `apply-limits` построил managed topology. Повторный `apply-limits` был идемпотентным.
|
||||||
|
|
||||||
|
Получено:
|
||||||
|
|
||||||
|
- egress HTB root: `600Mbit`;
|
||||||
|
- ingress IFB HTB root: `600Mbit`;
|
||||||
|
- peer `10.8.1.1`:
|
||||||
|
- egress: `60Mbit/60Mbit`;
|
||||||
|
- ingress: `60Mbit/60Mbit`;
|
||||||
|
- per-peer egress filter: `flower pref 10`, destination peer IPv4;
|
||||||
|
- per-peer ingress filter: `flower pref 10`, source peer IPv4;
|
||||||
|
- AWG ingress redirect: `u32 -> mirred -> ifb0`;
|
||||||
|
- IFB alias: `awg2-harness:traffic`;
|
||||||
|
- leaf qdisc: `fq_codel`;
|
||||||
|
- `status`: `drift: no`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.7. Live peer and traffic classification
|
||||||
|
|
||||||
|
После подключения реального AmneziaWG 3.1 клиента:
|
||||||
|
|
||||||
|
- peer определён как `online`;
|
||||||
|
- endpoint определён;
|
||||||
|
- latest handshake корректно читается;
|
||||||
|
- AWG RX/TX корректно читаются;
|
||||||
|
- egress class counter растёт;
|
||||||
|
- ingress class counter растёт.
|
||||||
|
|
||||||
|
`direct_packets_stat` не рос пропорционально пользовательской нагрузке; IPv4 peer traffic проходил через managed peer classes.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.8. Real bandwidth enforcement
|
||||||
|
|
||||||
|
Speedtest через реального клиента:
|
||||||
|
|
||||||
|
- configured peer ceiling: `60 Mbit/s`;
|
||||||
|
- download: `57.81 Mbit/s`;
|
||||||
|
- upload: `55.26 Mbit/s`.
|
||||||
|
|
||||||
|
Во время нагрузки:
|
||||||
|
|
||||||
|
- egress и ingress peer counters существенно выросли;
|
||||||
|
- HTB `overlimits` существенно выросли;
|
||||||
|
- topology сохранила `drift: no`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.9. Host firewall
|
||||||
|
|
||||||
|
Применены managed IPv4 и IPv6 INPUT chains.
|
||||||
|
|
||||||
|
Разрешены:
|
||||||
|
|
||||||
|
- loopback;
|
||||||
|
- ESTABLISHED/RELATED;
|
||||||
|
- TCP `2323`;
|
||||||
|
- ICMP / IPv6 ICMP.
|
||||||
|
|
||||||
|
Завершающее действие owned chain — DROP. Built-in INPUT policy не изменялась. Docker-managed FORWARD rules harness не изменял.
|
||||||
|
|
||||||
|
После применения подтверждены:
|
||||||
|
|
||||||
|
- новая SSH-сессия на TCP/2323;
|
||||||
|
- новый AWG handshake;
|
||||||
|
- работающий VPN dataplane;
|
||||||
|
- `Host firewall: drift: no`;
|
||||||
|
- `port_contract: ok`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.10. Anti-torrent guard
|
||||||
|
|
||||||
|
В AWG network namespace создана `table inet awg2_harness`.
|
||||||
|
|
||||||
|
Production rule использует:
|
||||||
|
|
||||||
|
- peer CIDR `10.8.1.0/24`;
|
||||||
|
- `ct state new`;
|
||||||
|
- dynamic IPv4 set;
|
||||||
|
- `ct count over 500`;
|
||||||
|
- named drop counter;
|
||||||
|
- terminal drop.
|
||||||
|
|
||||||
|
Inspector:
|
||||||
|
|
||||||
|
- enabled: true;
|
||||||
|
- max_connections_per_peer: 500;
|
||||||
|
- `drift: no`.
|
||||||
|
|
||||||
|
Threshold load-test выше 500 соединений на production намеренно не выполнялся.
|
||||||
|
|
||||||
|
Результат: PASS для control-plane и production configuration.
|
||||||
|
|
||||||
|
### 23.11. Daemon startup and self-healing
|
||||||
|
|
||||||
|
После включения `awg2-harness.service`:
|
||||||
|
|
||||||
|
- service: active;
|
||||||
|
- startup network tuning reconcile: ok;
|
||||||
|
- startup swap reconcile: ok;
|
||||||
|
- startup traffic reconcile: ok;
|
||||||
|
- startup firewall reconcile: ok.
|
||||||
|
|
||||||
|
Для проверки periodic self-healing вручную удалён root HTB qdisc на `awg0`.
|
||||||
|
|
||||||
|
Сразу после удаления inspector зарегистрировал:
|
||||||
|
|
||||||
|
`missing egress root htb qdisc`
|
||||||
|
|
||||||
|
Через следующий daemon reconciliation root HTB был автоматически восстановлен, peer classes и filters появились снова, `Traffic actual: drift: no`.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.12. Reboot scheduler
|
||||||
|
|
||||||
|
`awg2-reboot-scheduler.service`:
|
||||||
|
|
||||||
|
- enabled;
|
||||||
|
- active;
|
||||||
|
- планирует reboot внутри configured UTC window `01:00–02:00`.
|
||||||
|
|
||||||
|
Пример после production reboot:
|
||||||
|
|
||||||
|
`planned_reboot_utc=2026-08-30T01:00:38Z`
|
||||||
|
|
||||||
|
Фактического ожидания scheduler-triggered reboot в этом validation run не выполнялось.
|
||||||
|
|
||||||
|
Результат: PASS для startup/planning.
|
||||||
|
|
||||||
|
### 23.13. Reboot recovery
|
||||||
|
|
||||||
|
Выполнен ручной reboot production host.
|
||||||
|
|
||||||
|
После загрузки:
|
||||||
|
|
||||||
|
- Docker active;
|
||||||
|
- `amnezia-awg2` active;
|
||||||
|
- `awg2-harness.service` active;
|
||||||
|
- `awg2-reboot-scheduler.service` active;
|
||||||
|
- swap active с тем же UUID, размером 2 GiB и priority 1;
|
||||||
|
- network tuning: `drift: no`;
|
||||||
|
- traffic topology: `drift: no`;
|
||||||
|
- host firewall: `drift: no`;
|
||||||
|
- anti-torrent: `drift: no`;
|
||||||
|
- Docker/AWG UDP contract: `ok`.
|
||||||
|
|
||||||
|
AWG client автоматически выполнил новый handshake после reboot, peer определён как `online`, traffic counters росли.
|
||||||
|
|
||||||
|
Результат: PASS.
|
||||||
|
|
||||||
|
### 23.14. Наблюдение за Docker FORWARD state
|
||||||
|
|
||||||
|
До reboot `status` показывал `host_forward_policy_drop: true`, после reboot — `false`. При этом `docker_forward_rules_present: true`, VPN dataplane после reboot работал, а `port_contract` оставался `ok`.
|
||||||
|
|
||||||
|
Harness по контракту не управляет built-in FORWARD policy и Docker-managed FORWARD rules. Наблюдаемое изменение host state после reboot не классифицируется как drift или regression AWG2 Harness.
|
||||||
|
|
||||||
|
### 23.15. Сводный результат clean production acceptance
|
||||||
|
|
||||||
|
| Контур | Статус |
|
||||||
|
| --- | --- |
|
||||||
|
| Debian 13 clean host | PASS |
|
||||||
|
| Release `.deb` + SHA256 | PASS |
|
||||||
|
| Clean package installation | PASS |
|
||||||
|
| AWG 3.1 discovery | PASS |
|
||||||
|
| AWG 3.1 real dataplane | PASS |
|
||||||
|
| UDP 2053 contract | PASS |
|
||||||
|
| Owned swap creation | PASS |
|
||||||
|
| Swap persistence / idempotence | PASS |
|
||||||
|
| Network tuning | PASS |
|
||||||
|
| HTB 600 Mbit root | PASS |
|
||||||
|
| 60 Mbit per-peer egress | PASS |
|
||||||
|
| 60 Mbit per-peer ingress | PASS |
|
||||||
|
| Flower classification | PASS |
|
||||||
|
| IFB ingress | PASS |
|
||||||
|
| `fq_codel` | PASS |
|
||||||
|
| No material direct bypass | PASS |
|
||||||
|
| Real download: 57.81 Mbps | PASS |
|
||||||
|
| Real upload: 55.26 Mbps | PASS |
|
||||||
|
| IPv4 host firewall | PASS |
|
||||||
|
| IPv6 host firewall | PASS |
|
||||||
|
| New SSH through firewall | PASS |
|
||||||
|
| New AWG handshake through firewall | PASS |
|
||||||
|
| Docker forwarding preserved | PASS |
|
||||||
|
| Anti-torrent / `ct count over 500` configuration | PASS |
|
||||||
|
| Anti-torrent inspection | PASS |
|
||||||
|
| Daemon startup | PASS |
|
||||||
|
| Startup reconciliation | PASS |
|
||||||
|
| Periodic self-healing | PASS |
|
||||||
|
| Manual drift recovery | PASS |
|
||||||
|
| Service enablement | PASS |
|
||||||
|
| Manual reboot recovery | PASS |
|
||||||
|
| Post-reboot AWG handshake | PASS |
|
||||||
|
| Post-reboot traffic shaping | PASS |
|
||||||
|
| Post-reboot firewall | PASS |
|
||||||
|
| Post-reboot anti-torrent | PASS |
|
||||||
|
| Post-reboot swap | PASS |
|
||||||
|
| Post-reboot network tuning | PASS |
|
||||||
|
| Reboot scheduler startup/planning | PASS |
|
||||||
|
| Actual scheduled-time reboot | NOT OBSERVED |
|
||||||
|
| Multi-peer production load | NOT RE-RUN |
|
||||||
|
|
||||||
|
Production-critical функции, проверенные на реальном сервере:
|
||||||
|
|
||||||
|
- package installation;
|
||||||
|
- runtime discovery;
|
||||||
|
- swap lifecycle;
|
||||||
|
- network tuning;
|
||||||
|
- per-peer bidirectional shaping;
|
||||||
|
- real 60 Mbit/s enforcement;
|
||||||
|
- host firewall;
|
||||||
|
- Docker/AWG port contract;
|
||||||
|
- anti-torrent control-plane;
|
||||||
|
- daemon startup reconciliation;
|
||||||
|
- periodic drift self-healing;
|
||||||
|
- reboot persistence and recovery;
|
||||||
|
- reboot scheduler startup/planning.
|
||||||
|
|
||||||
|
Ограничения текущего validation:
|
||||||
|
|
||||||
|
- scheduler-triggered reboot не ожидался до фактического времени;
|
||||||
|
- multi-peer production load-test отдельно не повторялся;
|
||||||
|
- anti-torrent threshold выше 500 не создавался искусственно.
|
||||||
|
|
||||||
|
Эти ограничения зафиксированы как непроверенные сценарии и не признаны blockers для перевода пользователей на сервер: запуск и планирование scheduler проверены, обычный reboot и полное восстановление системы проверены отдельно.
|
||||||
|
|
||||||
|
**Clean production acceptance: PASS.**
|
||||||
|
|
||||||
|
**Production GO: подтверждён.**
|
||||||
|
|||||||
Reference in New Issue
Block a user