e9f0e29f75
Two modules wrote into /etc/sysctl.d and did it differently. sysctl_tuning refused to touch a file whose first line lacked its marker and cleaned up on disable. swap wrote /etc/sysctl.d/99-awg2-harness.conf with a different marker, no ownership check at all - an administrator's file at that path was silently clobbered - and never removed it when the module was turned off, so vm.swappiness stayed pinned forever. New module managed_file.rs holds the rules once: - a read that fails is never an absent file; - ownership is Absent / Managed / Foreign, decided by the marker on the first line; - write refuses Foreign, skips when the content already matches, and is otherwise atomic: temp sibling created with create_new, sync_all, mode 0644, rename, directory flush; - remove refuses Foreign and treats Absent as success. Both modules now go through it. sysctl_tuning loses its private write_atomic, ensure_managed_or_absent and remove_managed_sysctl_file_at. The swappiness file moves to /etc/sysctl.d/90-awg2-harness-swap.conf with the marker "# Managed by awg2-harness swap", matching the 90- prefix every other managed file uses. The old path is removed on first run of the new version, but only when it still carries the previous "# Managed by awg2-harness" marker; a foreign file there is left alone and does not fail the migration, since the current file lives elsewhere. Disable semantics are now explicit: swap.enabled = false removes the managed file and does nothing else. Runtime vm.swappiness is deliberately not reset - picking a value would be inventing a policy - and active swap is not deactivated, because merely turning a feature off should not trigger a destructive action. Previously ensure_swap returned early and left the persisted file behind. Also replaced a vacuous test: swappiness_conf_render_is_stable asserted that a string literal equals a format! of the same literal, touching no production code at all. It now exercises render_swappiness_conf, and a companion test proves the rendered file is recognised as managed by the same marker check that guards overwriting it - otherwise every reconcile would refuse to touch its own output. Twelve tests: the three ownership states, refusal to overwrite and refusal to remove a foreign file with content asserted intact, idempotent write, stale temp handling, an unreadable path reported as an error, plus legacy migration in all three cases - ours, foreign, absent. cargo test --workspace: 148 + 4 passed. clippy -D warnings clean.
Документация AWG2 Harness
Рекомендуемый порядок чтения:
../README.md— общий runtime-план: SSH, официальная Amnezia, установка пакета, preflight, проверка перезагрузкой и CLI.INSTALLATION.md— сжатый порядок установки на production.CONFIGURATION.md— параметры/etc/awg2-harness/config.toml.ACCEPTANCE_CHECKLIST.md— чек-лист приёмки перед статусом production-ready.ANTI_TORRENT.md— ограничение числа соединений через nftables.IMPLEMENTATION_SPEC.md— архитектура и reconciliation состояния.
Отдельно:
../tools/README.md— сборка и упаковка.deb.../reboot_module/README.md— внешний планировщик перезагрузки.
Практический порядок для оператора: сначала выполнить корневой README, затем свериться с чек-листом приёмки. Остальные документы нужны для понимания замысла и отладки.
Язык документации
Проза — на русском. Английский остаётся там, где он технически обязателен: команды, вывод утилит, ключи конфигурации, имена файлов, модулей, таблиц nftables и handles tc. Термины, у которых нет устоявшегося русского эквивалента в этом контексте (drift, reconcile, peer, namespace, handshake), не переводятся.
IMPLEMENTATION_SPEC.md описывает фактическое состояние кода. Расхождение между ним и traffic_core/src считается дефектом документа, а не допустимым упрощением.