Гоняно на 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
Приведение документации к фактическому поведению после ревью PR #53 (раунд 2):
точка входа для CI без make (контракт 0/1/3/4), приоритет AWG_NS_EXEC_MODE над
make-алиасом, сборка без сети (DEV_SKIP_BUILD=1).
Refs #21
Refs #56
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
Реализация замечаний ревью 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
Флак: ns_exists мог вернуть false до удаления, и namespace оставался жить.
Теперь `ip netns delete` вызывается всегда, результат проверяется до 5 раз.
Стабильность в контейнере: 5/5 прогонов rc=0 (было 4/5).
Refs #21, Refs #56
В контейнере `ip netns delete` иногда возвращает успех, но namespace остаётся
в `ip netns list` — из-за этого run.sh отдавал код 4 на зелёных тестах (флак
1 из 3). Теперь удаление повторяется до 5 раз с проверкой ns_exists.
Refs #21, Refs #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
- 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
- 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
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.
Новый файл 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
Закрывает замечания ревью 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
- ui/scripts/generate-api.sh: openapi-typescript@7 над docs/openapi.yaml.
- ui/src/api/generated/README.md: правила перегенерации и семантика writeOnly-секретов.
- test_openapi_spec: валидность 3.1, полнота операций по ТЗ, writeOnly-секреты,
единый формат Error, соответствие pydantic-моделей схемам.
- test_contract_responses: все эндпоинты против схем, ошибки 401/404/409/422/503,
WS-кадры, отсутствие секретов в ответах.
- test_contract_negative: доказательство AC — подмена реализации на расходящуюся
роняет контрактный тест с указанием пути до поля.
- 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
- 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
- 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
- netns_common.py — обёртки над ip/nft/iptables: проверка netns и линков,
счётчики правил меток и kill-switch (nft -j и iptables -v -x), чтение
JSONL-логов мока и детектора, отправка трафика через probe.py;
- run_tests.py — прогон unittest с JSON-отчётом (pytest не нужен: работает
и на хосте, и в alpine-образе);
- README.md — схема топологии, таблица тестов, переменные окружения и pitfalls
(root/CAP_NET_ADMIN, rp_filter, отсутствие nft и ping в образе).
Refs #21
Refs #15