Commit Graph

66 Commits

Author SHA1 Message Date
embeddevio ca14ae6819 ci(contract): checkout-fallback на archive-архив (обход дефекта git-http, #59)
contract-openapi / openapi-contract (push) Successful in 1m3s
contract-openapi / ts-client-is-current (push) Successful in 1m32s
contract-openapi / openapi-contract (pull_request) Successful in 56s
contract-openapi / ts-client-is-current (pull_request) Successful in 42s
actions/checkout падает на всех коммитах: `git-upload-pack` отдаёт пустой pack
(`bad pack header`, exit 128), из-за чего статусы `contract-openapi/*` всегда красные
и любой PR (включая #60) не может получить зелёный combined status.

Источники забираются архивом `/archive/<sha>.tar.gz` (endpoint работает), проверка
TS-клиента без .git сравнивает sha256 сгенерированного schema.d.ts.

Refs #59, Refs #17
2026-10-28 23:34:02 +03:00
embeddevio a4475113bc Merge pull request 'Sprint 0 / #21: dev/staging стенд — docker-compose, тома, netns-харнесс' (#53) from feat/21-dev-stand into main
contract-openapi / openapi-contract (push) Failing after 36s
contract-openapi / ts-client-is-current (push) Failing after 28s
Sprint 0 / #21: dev/staging стенд — docker-compose, тома, netns-харнесс

Ревью QA (раунд 3) APPROVE: AC-1 health 200 + healthy, AC-2 состояние переживает
restart и --force-recreate, AC-3 netns 8/8 ok; gates shellcheck/validate_compose/
test-deploy (51 passed, coverage 98.86%) — зелёные, все 5 замечаний раундов 1-2 закрыты.
Прогоны выполнены ревьюером на стенд-хосте 192.168.1.147.
CI-гейт заменён по причине дефекта git-http Gitea (#58: bad pack header в job-чекэуте).
Refs #21, #15, #58.
2026-10-28 22:12:02 +03:00
embeddevio a3396b2be6 docs(#21): VERIFICATION-21 §7 — реальные прогоны раунда 3 (коды 0/1/3/4, make→2, env-алиас, DEV_SKIP_BUILD)
Гоняно на 192.168.1.147 на дереве, сверенном по git-blob-SHA: ci.sh 0/4/3/1,
make при коде 4 и 1 отдаёт 2 (контейнерные коды видны в логе), AWG_NS_EXEC_MODE
больше не перекрывается, DEV_SKIP_BUILD=1 даёт AC-1 (200 + healthy), test-deploy
51 passed / 98.86 %, manifests и shellcheck — 0.

Refs #21
Refs #56
2026-10-28 21:58:58 +03:00
embeddevio 9d2222455a docs(#21): VERIFICATION-21 — контракт кодов через make зафиксирован в §6.1, поправка §6.3
Ревью PR #53 (раунд 2) требовало явной фиксации «make → 2, контракт действует на
уровне контейнера» и снятия неверного утверждения про прокидывание
AWG_NS_EXEC_MODE. Прогоны раунда 3 добавляются отдельным коммитом.

Refs #21
Refs #56
2026-10-28 21:58:23 +03:00
embeddevio 94d3a28adf docs(#21): README netns и runbook dev-stand — ci.sh, приоритет AWG_NS_EXEC_MODE, DEV_SKIP_BUILD
Приведение документации к фактическому поведению после ревью PR #53 (раунд 2):
точка входа для CI без make (контракт 0/1/3/4), приоритет AWG_NS_EXEC_MODE над
make-алиасом, сборка без сети (DEV_SKIP_BUILD=1).

Refs #21
Refs #56
2026-10-28 21:58:15 +03:00
embeddevio b612a3450c deploy(#21): tests/netns/ci.sh — точка входа netns-стенда для CI без make
GNU make отдаёт 2 на любой упавший рецепт, поэтому контракт 0/1/3/4 через
`make test-netns-ci` до пайплайна #17 не доходит. ci.sh запускает тот же
контейнер (docker compose -f deploy/docker-compose.test.yml run --rm -T netns)
и возвращает его код как есть. Дополнительно: AWG_NS_PRIVILEGED=0 — прогон без
--privileged (проверка ветки «код 3»), AWG_DASH_TEST_ARTIFACTS — каталог отчёта.

Refs #21
Refs #56
2026-10-28 21:58:04 +03:00
embeddevio e672901741 deploy(#21): контракт кодов netns без make, AWG_NS_EXEC_MODE в приоритете, DEV_SKIP_BUILD
Реализация замечаний ревью PR #53 (issuecomment-664):

1. tests/netns/ci.sh — точка входа для CI #17 без make: docker compose run --rm -T
   netns, код контейнера возвращается как есть (0/1/3/4; 2 — сломан вызов/нет
   docker/образа). make test-netns-ci делегирует в неё, в комментарии таргета
   зафиксировано «make → 2».
2. NETNS_EXEC_MODE ?= $(if $(AWG_NS_EXEC_MODE),$(AWG_NS_EXEC_MODE),auto) —
   документированный AWG_NS_EXEC_MODE больше не перекрывается make-алиасом.
3. DEV_SKIP_BUILD=1 → up -d --no-build; DEV_UP_BUILD переопределяем (?) —
   dev-up работает на хосте без DNS/сети для сборки.

Refs #21
Refs #56
2026-10-28 21:57:44 +03:00
embeddevio dbb5d1fe5c deploy: актуальный blob topology.sh после shellcheck-фикса (#56)
Refs #21, Refs #56
2026-10-28 21:39:31 +03:00
embeddevio 221d8740c9 netns: shellcheck SC2034 в цикле сноса топологии (#56)
Refs #21, Refs #56
2026-10-28 21:39:05 +03:00
embeddevio e6ba503c20 deploy: стабильность netns-ci 5/5 и актуальный blob topology.sh (#56)
Refs #21, Refs #56
2026-10-28 21:38:32 +03:00
embeddevio 6c5d739cfc netns: удаление netns безусловно + проверка результата (#56)
Флак: ns_exists мог вернуть false до удаления, и namespace оставался жить.
Теперь `ip netns delete` вызывается всегда, результат проверяется до 5 раз.
Стабильность в контейнере: 5/5 прогонов rc=0 (было 4/5).

Refs #21, Refs #56
2026-10-28 21:37:09 +03:00
embeddevio 4ff22f4323 Merge pull request 'Sprint 0 / #20: хранилище состояния — SQLite WAL, миграции, audit log, атомарный apply/rollback' (#50) from feat/20-storage into main
contract-openapi / openapi-contract (push) Failing after 37s
contract-openapi / ts-client-is-current (push) Failing after 38s
Sprint 0 / #20: хранилище состояния — SQLite WAL, миграции, audit log, атомарный apply/rollback

Правки по ревью QA (#54 critical, #55 D-1/D-2) внесены и приняты:
RLock на чтения, BaseException → revert + failed в аудите, old_value внутри транзакции.
Гейт на merge-состоянии (main + PR): ruff/format чисто, mypy strict 21 файл,
pytest 107 passed / coverage 97.80% (порог 70%), 55/55 AC-проб, 28/28 security-проб,
мутационная проверка тестов пройдена. Ревью: qa-engineer (APPROVE) + TechLead.
Refs #20, #54, #55, #52.
2026-10-28 21:35:41 +03:00
embeddevio 63e75e4b7f netns: снос топологии с повторами на случай ленивого umount (#56)
В контейнере `ip netns delete` иногда возвращает успех, но namespace остаётся
в `ip netns list` — из-за этого run.sh отдавал код 4 на зелёных тестах (флак
1 из 3). Теперь удаление повторяется до 5 раз с проверкой ns_exists.

Refs #21, Refs #56
2026-10-28 21:35:27 +03:00
embeddevio 156d791020 deploy: таблица git-blob-SHA приведена к раунду 2 (#56)
Refs #21, Refs #56
2026-10-28 21:33:36 +03:00
embeddevio d63b9ceafe deploy: реальные прогоны раунда 2 в VERIFICATION-21 (#56)
- netns-ci в контейнере: причина (ip netns exec/ip -n перемонтируют /sys),
  переход на nsenter, контракт кодов 0/1/3/4 — все четыре воспроизведены.
- гейт покрытия: make test-deploy = 51 passed, 98.86 %.

Refs #21, Refs #15, Refs #56
2026-10-28 21:32:32 +03:00
embeddevio edf22d7c93 tests: пояснение к профилю pytest стенда (#56)
Refs #21, Refs #56
2026-10-28 21:32:07 +03:00
embeddevio 8e76f41f63 tests: негативные тесты валидатора compose-манифестов (#56)
Каждая инварианта AC #21 ломается по отдельности (порт, тома /config /data,
healthcheck, NET_ADMIN, /dev/net/tun, ip_forward, privileged netns-сервис,
DEV-ONLY-метка, --require-dockerfile) — 39 тестов, реальные манифесты не трогаются.

Refs #21, Refs #56
2026-10-28 21:31:07 +03:00
embeddevio 8db92df8f2 tests: покрытие health-заглушки и отдельный профиль pytest (#56)
- tests/deploy/pytest.ini + .coveragerc: гейт ≥70 % для кода стенда (deploy/ и
  validate_compose.py), тестовые модули из покрытия исключены.

Refs #21, Refs #56
2026-10-28 21:30:48 +03:00
embeddevio c7f2ea128e deploy: гейт покрытия стенда и тестируемая health-заглушка (#56)
- deploy/api_stub.py: make_server() выделен из main(), main(argv) — тесты поднимают
  настоящий сервер на порту 0 (покрытие api_stub.py 0 % -> 98 %).
- Makefile: make test-deploy (гейт ≥70 % через tests/deploy/pytest.ini),
  test-netns-ci прокидывает AWG_NS_EXEC_MODE.

Refs #21, Refs #15, Refs #56
2026-10-28 21:30:33 +03:00
embeddevio 4aa69132ad netns: nsenter в topology.sh, netns_common и документации (#56)
- topology.sh: ns_exec для всех ip -n <ns> и ip netns exec, коды 0/1/3/4.
- netns_common.py: ns_exec_mode()/ns_exec_direct(), addrs/links/link_is_up через ns_sh.
- docker-compose.test.yml: проброс AWG_NS_EXEC_MODE в netns-сервис.
- tests/netns/README.md: режимы входа в netns, коды возврата, новый pitfall.

Refs #21, Refs #15, Refs #56
2026-10-28 21:30:22 +03:00
embeddevio f0847001ee netns: вход в namespace через nsenter при отказе ip netns exec (#56)
- lib.sh: ns_exec()/ns_prefix() с автоопределением режима (AWG_NS_EXEC_MODE),
  stand_fail() для кода 4; cleanup в run.sh больше не оставляет мок и sink.
- run.sh/topology.sh: коды возврата нормализованы к 0/1/3/4 (255 от iproute2 -> 4).

Refs #21, Refs #15, Refs #56
2026-10-28 21:30:01 +03:00
embeddevio 3e3519edc8 Merge pull request 'Sprint 0 / #19: OpenAPI 3.1 контракт API v1 + TS-клиент и контрактные тесты' (#57) from feat/19-openapi into main
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
Sprint 0 / #19: OpenAPI 3.1 контракт API v1 + TS-клиент и контрактные тесты

AC проверены независимо (ревью TechLead): генератор TS-клиента (blob сверен),
отклонение схемы роняет контрактный тест (мутации), секретов в ответах нет.
Гейты: ruff/mypy чисто, pytest 93 passed / coverage 95.48% (порог 70%).
CI green недостижим — runner отсутствует (#52); отклонение зафиксировано в PR.
Refs #19, #15, #52.
2026-10-28 21:21:13 +03:00
embeddevio 063ecf18ce Merge pull request 'Sprint 0 / #16: каркас монорепозитория, ADR-001..008 и линтеры' (#47) from feat/16-repo-skeleton into main
Sprint 0 / #16: каркас монорепозитория, ADR-001..008, линтеры (ruff/mypy/pytest, coverage>=70)

Гейты прогнаны вручную на байтах ветки (CI runner отсутствует — #52):
ruff check rc=0, ruff format --check rc=0, mypy strict rc=0,
pytest 2 passed / coverage 100% (порог 70%).
Ревью: TechLead. Refs #16, #15, #52.
2026-10-28 21:16:03 +03:00
embeddevio c4661c9db9 test(#20): регрессионные тесты потокобезопасности (#54) и BaseException/TOCTOU (#55)
Новый файл backend/tests/test_store_concurrency.py:

* N потоков × M upsert с чтениями → 0 ошибок, rules == audit_rows == N*M;
* чтение во время открытой транзакции другого потока не видит незафиксированных
  строк (ждёт коммита);
* чтение во время падающего apply не видит состояния, которое будет откачено
  (AC «не частично применённая конфигурация»);
* BaseException (KeyboardInterrupt/SystemExit/CancelledError) из Applier →
  revert вызван, failed в audit_log, БД восстановлена;
* два конкурентных set_geoip_schedule → связная цепочка old→new в журнале.

На коде до правки все 7 тестов падают; после — проходят.

Refs #20, Refs #54, Refs #55
2026-10-28 21:12:35 +03:00
embeddevio e989e46b19 chore(ui): generated TS client schema.d.ts (block 5/5: operations tail)
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 1s
2026-10-28 21:12:09 +03:00
embeddevio 249f32e3f9 fix(#20): потокобезопасные чтения, BaseException в apply, old_value внутри транзакции (#54, #55)
Закрывает замечания ревью QA по PR #50:

* #54: все чтения Store идут через Database.read() под тем же RLock, что
  транзакции; контракт «одно соединение, все операции под локом»
  задокументирован в db.py и README модуля. Устраняет TypeError/IndexError
  на общем соединении, грязные чтения и выдачу состояния, которое затем
  откатывается падающим apply.
* #55 D-1: apply ловит BaseException — отмена/CancelledError/
  KeyboardInterrupt вызывают Applier.revert(previous) и пишут failed в
  audit_log (без «висящей» записи staged); падение revert попадает в detail.
* #55 D-2: set_geoip_schedule читает old_value внутри той же транзакции.

Refs #20, Refs #54, Refs #55
2026-10-28 21:12:09 +03:00
embeddevio d8fc5c7f7d chore(ui): generated TS client schema.d.ts (block 4/5: operations)
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 0s
2026-10-28 21:11:54 +03:00
embeddevio 4ff7d39fb1 chore(ui): generated TS client schema.d.ts (block 3/5: responses)
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 0s
2026-10-28 21:11:36 +03:00
embeddevio 5522f32638 chore(ui): generated TS client schema.d.ts (block 2/5: schemas)
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 0s
2026-10-28 21:11:21 +03:00
embeddevio ba1a870d32 chore(ui): fix bearer placeholder in generated client
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 0s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 0s
2026-10-28 21:10:57 +03:00
embeddevio 217a11919d chore(ui): generated TS client schema.d.ts (block 1/5: paths)
contract-openapi / openapi-contract (push) Failing after 0s
contract-openapi / ts-client-is-current (push) Failing after 1s
contract-openapi / openapi-contract (pull_request) Failing after 0s
contract-openapi / ts-client-is-current (pull_request) Failing after 0s
2026-10-28 21:09:21 +03:00
embeddevio 8691a3dec1 chore(ui): add generated TS client schema.d.ts (part 1/4)
contract-openapi / openapi-contract (push) Failing after 27s
contract-openapi / ts-client-is-current (push) Failing after 30s
contract-openapi / ts-client-is-current (pull_request) Failing after 1s
contract-openapi / openapi-contract (pull_request) Failing after 43s
2026-10-28 21:08:12 +03:00
embeddevio 3387eb0f60 test(contract): restore trailing newline at EOF
contract-openapi / openapi-contract (push) Failing after 32s
contract-openapi / ts-client-is-current (push) Failing after 28s
contract-openapi / openapi-contract (pull_request) Failing after 32s
contract-openapi / ts-client-is-current (pull_request) Failing after 33s
2026-10-28 21:07:11 +03:00
embeddevio c53e2ef9b1 test(contract): align response contract test with the verified green run
contract-openapi / openapi-contract (push) Failing after 40s
contract-openapi / ts-client-is-current (push) Failing after 1m24s
2026-10-28 21:06:55 +03:00
embeddevio c6150bd5fd test(contract): align spec test with the verified green run
contract-openapi / openapi-contract (push) Failing after 18m54s
contract-openapi / ts-client-is-current (push) Failing after 18m49s
2026-10-28 21:06:33 +03:00
embeddevio 95f1337fd4 chore(ui): скрипт генерации TS-клиента из OpenAPI (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- ui/scripts/generate-api.sh: openapi-typescript@7 над docs/openapi.yaml.
- ui/src/api/generated/README.md: правила перегенерации и семантика writeOnly-секретов.
2026-10-22 00:23:16 +03:00
embeddevio 3dac7e730a test(api): контрактные тесты «схема ↔ реализация» (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- test_openapi_spec: валидность 3.1, полнота операций по ТЗ, writeOnly-секреты,
  единый формат Error, соответствие pydantic-моделей схемам.
- test_contract_responses: все эндпоинты против схем, ошибки 401/404/409/422/503,
  WS-кадры, отсутствие секретов в ответах.
- test_contract_negative: доказательство AC — подмена реализации на расходящуюся
  роняет контрактный тест с указанием пути до поля.
2026-10-22 00:22:46 +03:00
embeddevio 7d9cf8ca5e feat(api): роутеры API v1 и WebSocket-поток метрик (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- ops: health/ready/metrics без аутентификации (503 = схема Error).
- auth: login/logout/session, cookie-сессия + CSRF-токен.
- status/config/routing/devices+logs: все эндпоинты контракта.
- ws/metrics: /api/v1/metrics/stream, токен в заголовке или query.
2026-10-22 00:21:56 +03:00
embeddevio 839f773010 feat(api): контрактный харнесс и in-memory состояние мок-сервера (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- contract.py: загрузка docs/openapi.yaml, вырезание writeOnly-секретов из схем
  ответов, валидация тела ответа (jsonschema Draft2020-12 + FormatChecker),
  двусторонняя сверка маршрутов приложения и контракта.
- state.py: мок-состояние туннеля/правил/устройств/журнала; секреты хранятся
  отдельно от словарей-ответов.
2026-10-22 00:21:43 +03:00
embeddevio 83d5a23406 feat(api): мок-контрол-плейн по контракту + единый формат ошибок (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- app.py: create_app() собирает мок-сервер и отдаёт /openapi.json из спецификации.
- errors.py: ApiError + хендлеры, приводящие 4xx/5xx/422 к схеме Error.
- deps.py: Bearer-токен и cookie-сессия (ADR-008).
- schemas.py: pydantic-модели запросов, зеркалящие схемы контракта (extra=forbid,
  writeOnly для секретов).
2026-10-22 00:21:06 +03:00
embeddevio cc3640f13c docs(api): OpenAPI 3.1 контракт API v1 как source of truth (Refs #19)
contract-openapi / openapi-contract (push) Has been cancelled
contract-openapi / ts-client-is-current (push) Has been cancelled
- docs/openapi.yaml: все эндпоинты ТЗ, единый формат ошибок {code,message,details},
  writeOnly для private_key/preshared_key/password, WS-кадры metrics/stream.
- requirements-contract.txt: зависимости контрактных тестов (jsonschema,
  openapi-spec-validator, PyYAML) до мержа каркаса PR #47.
- .gitea/workflows/contract-openapi.yml: lint + контрактный тест + проверка
  актуальности сгенерированного TS-клиента.
2026-10-22 00:20:36 +03:00
embeddevio f5e8272c3a docs(#21): отчёт о фактических прогонах гейтов и AC на 192.168.1.147 (HEAD 7af9caba)
Refs #21 Refs #15
2026-10-22 00:16:00 +03:00
embeddevio 7af9cabad3 docs(#21): в шапке compose описан авто-режим dev-up до #31
Refs #21
2026-10-22 00:13:07 +03:00
embeddevio 73e23bc3e4 fix(#21): verify-dev-stand не даёт ложный [fail] после --force-recreate (перезапрос id)
Refs #21 Refs #15
2026-10-22 00:13:07 +03:00
embeddevio 8e0d76147e deploy(#21): dev-up поднимает health-стенд до #31; --build не форсируется без deploy/Dockerfile
Refs #21 Refs #15
2026-10-22 00:13:02 +03:00
embeddevio b8f715d38a docs(#21): runbook dev-стенда — быстрый старт, таблица AC, зависимости и откат
Refs #21
Refs #15
2026-10-21 23:50:19 +03:00
embeddevio 59c3ad4918 test(#21): тесты инвариантов compose, Make-цели стенда и обновлённый deploy/README
- tests/deploy/test_compose_manifests.py — 7 тестов на compose-инварианты
  (без Docker, только PyYAML) — готовы к включению в CI (#17);
- Makefile: dev-up/dev-up-stub/dev-down/dev-logs/dev-verify/dev-verify-stub/
  dev-reset/test-netns/test-netns-keep/test-netns-ci/test-manifests/lint-shell,
  переменные HOST_DIR, DASH_PORT, NETNS_ARGS; dev-up без docker падает с внятным
  сообщением, а не трейсбеком;
- deploy/README.md — таблица артефактов и быстрые команды стенда.

Refs #21
Refs #15
2026-10-21 23:50:01 +03:00
embeddevio 7d46df5ede test(#21): проверка AC на Docker-хосте и статические инварианты compose
- verify-dev-stand.sh (`make dev-verify`): AC-1 (health 200, различает
  api=real/stub), AC-2 (маркеры в /config и /data до и после restart и
  --force-recreate, включая проверку на хосте), проверка монтирований и
  health контейнера, JSON-отчёт; коды 0/1/2/3 — ok/regression/blocked-#31/
  blocked-env;
- tests/deploy/validate_compose.py — проверки без Docker: контейнерный порт
  8080, тома /config и /data, healthcheck /api/v1/health, NET_ADMIN и
  /dev/net/tun, ip_forward, лимит логов, privileged netns-раннер и DEV-ONLY
  заглушка. Флаг --require-dockerfile для интеграционного дерева.

Refs #21
Refs #15
2026-10-21 23:49:43 +03:00
embeddevio da1c750297 feat(#21): dev-стенд — compose-файлы, health-заглушка до #31
- docker-compose.dev.yml: отдельный project awg-dash-dev, порт 8080 в контейнере
  (наружу AWG_DASH_PORT, по умолчанию 8180 — 8080 занят на dev-хосте), bind mount
  /opt/awg-dash-dev/{config,data} -> /config,/data, healthcheck /api/v1/health,
  NET_ADMIN/NET_RAW/SYS_MODULE, /dev/net/tun, ip_forward, лимит логов;
- docker-compose.stub.yml + api_stub.py — DEV-ONLY заглушка health: AC-1 требует
  FastAPI-каркаса (#31), до него проверяем плумбинг стенда без обмана отчёта
  (в ответе ивно стоит "stub": true);
- docker-compose.test.yml: привилегированный netns-раннер (CAP_SYS_ADMIN нужен
  для `ip netns add`) + сервис app для API-тестов.

Refs #21
Refs #15
2026-10-21 23:49:11 +03:00
embeddevio 87cf5fe05f test(#21): интеграционные тесты netns-стенда и документация харнесса
- test_netns_stand.py — 8 тестов: топология и линки, policy routing по fwmark,
  правила меток и kill-switch, готовность мока и детектора, доставка handshake
  из LAN и из шлюза с ростом счётчика метки, имитация недоступности провайдера
  (mode=drop), положительный контроль утечки и блокировка при kill-switch.
  Тесты пропускаются вне run.sh, чтобы не падать при случайном pytest-прогоне;
- README.md харнесса — схема топологии, состав файлов, таблица тестов,
  переменные окружения и pitfalls (root/CAP_NET_ADMIN, rp_filter, отсутствие
  nft и ping в alpine-образе).

Refs #21
Refs #15
2026-10-21 23:48:51 +03:00