П'ять паралельних задач. Найцінніше в них — не можливості, а знайдене.
0069 БІЛІНГ. Аудит 0009 показав, що перевірка ліміту не спрацювала б
жодного разу: isPlanLimit шукала слово «ліміт», а тригер писав
"device limit reached" англійською. Перше ж досягнення стелі дало б
клієнту 500 замість пояснення. Плюс три діри: тригер лише на INSERT
(стеля в 15 обходилась за чотири дії через архів), max_maps/max_agents/
max_users не перевіряло ніщо — тобто рівно те, чим відрізняються плани,
і license_keys була закрита політикою tenant_isolation з 0011, хоча
tenant_id там NULLABLE навмисно: головний сценарій self-hosted був
недосяжний.
Після закінчення ліцензії не вимикається нічого — замерзає лише ріст.
Моніторинг, що перестав моніторити через несплачений рахунок, це
аварія в мережі клієнта, спричинена нами.
0070 SLA. Джерелом обрано ts.icmp_1h, а не device_status_history:
остання не вміє сказати «ми не знали» — перехід пишеться лише при
зміні стану, тож доба мовчання зонда виглядає як доба роботи. Час
розкладено на чотири частини, і «немає даних» не додається ні до чого;
замість вибору між двома брехнями звіт каже, яку частку періоду він
бачив. Закритий період тримає тригер, а не домовленість у Go.
0071 ВІДПОВІДНІСТЬ. 20 правил, кожне прив'язане до родини: об'єднаний
вираз, що покриває Cisco й не покриває MikroTik, дав би «0 порушень» і
сховав сліпу пляму. Вендор не входить у перелік, доки для нього немає
зразка конфігу в тесті. TestBuiltinRulesAreNotAlwaysGreen вимагає, щоб
у кожного правила був конфіг, де воно спрацювало, І де ні.
ПІСОЧНИЦЯ УСТАНОВНИКА — та сама установка в ізольованому проєкті
compose. Знайшла дві справжні вади з трьох спроб:
* healthcheck бази ходив unix-сокетом, а споживачі по TCP. При
первинній ініціалізації Postgres слухає лише сокет — compose
вважав базу здоровою, migrate отримував connection refused. На
створеній базі цієї фази немає, тож вада чекала на першого клієнта;
* у білому переліку модулів API не було traps і filecfg — зонд із
приймачем трапів неможливо було зареєструвати взагалі.
ТЕСТИ СТОРІНОК: 137 → 252. Мережевий шар, права доступу, незворотні
дії, фільтри з адресного рядка. Підмінюється лише fetch і WebSocket —
api/client.ts працює справжній.
118 lines
7.1 KiB
YAML
118 lines
7.1 KiB
YAML
# Пісочниця NetPulse — накладка на docker-compose.yml.
|
||
#
|
||
# Це НЕ окремий стек і не спрощена копія. Це той самий docker-compose.yml,
|
||
# накритий рівно тими правками, без яких повна установка на робочій
|
||
# машині або конфліктує з наявною, або з'їдає машину. Усе інше —
|
||
# порядок служб, міграції, ролі під RLS, зонд — лишається тим самим, бо
|
||
# інакше пісочниця перевіряла б не установку, а власну вигадку.
|
||
#
|
||
# Запускати руками не треба: `./netpulse sandbox` підставляє і цей файл,
|
||
# і ім'я проєкту, і окремий .env.sandbox.
|
||
#
|
||
# docker compose -p netpulse-sandbox \
|
||
# -f docker-compose.yml -f deploy/docker-compose.sandbox.yml \
|
||
# --env-file .env.sandbox <команда>
|
||
#
|
||
# ---------------------------------------------------------------------
|
||
# ЩО САМЕ ТУТ МІНЯЄТЬСЯ І ЧОМУ
|
||
#
|
||
# 1. Порти. Базовий файл публікує 80, 443, 9443 і 162/udp числами. Друга
|
||
# інсталяція на тій самій машині впирається в них першою ж командою
|
||
# `up`, і виглядає це як «пісочниця поклала бойову систему» — рівно та
|
||
# шкода, від якої вона мала захистити. Тому проксі публікується на
|
||
# зсунуті порти І ЛИШЕ на 127.0.0.1: пісочниця не має бути видною з
|
||
# мережі навіть випадково, у ній стоїть відомий пароль і самопідписаний
|
||
# сертифікат.
|
||
#
|
||
# 2. Трапи. Зонд у пісочниці піднімається (без нього не перевірити
|
||
# реєстрацію в колекторі — а це єдиний шлях, якого HTTP-перевірки не
|
||
# бачать зовсім), але 162/udp назовні не виставляє взагалі. Порт без
|
||
# автентифікації, відкритий заради перевірки, — це не перевірка.
|
||
#
|
||
# 3. Стелі пам'яті. Без них пісочниця конкурує з рештою машини на рівних
|
||
# і виграє: Postgres резервує буфери одразу, а ядро вбиває не того,
|
||
# хто попросив забагато, а того, хто підвернувся. Стеля перетворює
|
||
# «машина стала» на «контейнер пісочниці впав», і друге видно одразу.
|
||
# Цифри взяті з запасом: стеля тут — запобіжник, а не режим економії,
|
||
# і впертись у неї на порожній базі не має ніщо. Якщо все ж уперлось,
|
||
# `./netpulse sandbox status` це називає прямо, щоб причину не шукали
|
||
# в коді.
|
||
#
|
||
# 4. restart: "no". У бойовому стеку `unless-stopped` правильний: служба
|
||
# має пережити перезавантаження хоста. Для пісочниці це протилежність
|
||
# потрібного — забута пісочниця не має воскресати після ребуту й
|
||
# мовчки тримати порт і том. Побічний наслідок корисний: контейнер,
|
||
# який падає в циклі, тут одразу видно як мертвий, а не як «щось
|
||
# довго стартує».
|
||
#
|
||
# ---------------------------------------------------------------------
|
||
# ЧОМУ ПОТРІБЕН COMPOSE 2.24.4
|
||
#
|
||
# Списки `ports` при накладанні файлів compose ДОДАЄ, а не замінює: без
|
||
# явного тега `!override` базові «80:80» лишилися б на місці поруч зі
|
||
# зсунутими, і пісочниця все одно вчепилась би в порт бойового проксі.
|
||
# Тег `!override` з'явився у docker compose 2.24.4.
|
||
#
|
||
# Ця вимога зникає одним рядком у docker-compose.yml — якщо базові порти
|
||
# зробити змінними зі значенням за замовчуванням:
|
||
#
|
||
# ports:
|
||
# - "${NETPULSE_BIND:-0.0.0.0}:${NETPULSE_PORT_HTTP:-80}:80"
|
||
# - "${NETPULSE_BIND:-0.0.0.0}:${NETPULSE_PORT_HTTPS:-443}:443"
|
||
# - "${NETPULSE_BIND:-0.0.0.0}:${NETPULSE_PORT_GRPC:-9443}:9443"
|
||
#
|
||
# Тоді пісочниці вистачить .env.sandbox, накладка портів стає не
|
||
# потрібна, а мінімальна версія compose лишається 2.0 — як у решті
|
||
# установника. Поки цього немає, `./netpulse sandbox` перевіряє версію і
|
||
# відмовляється працювати на старішій, а не мовчки бере не ті порти.
|
||
|
||
# Ім'я проєкту продубльовано тут навмисно. `./netpulse sandbox` і так
|
||
# передає -p, але якщо цей файл колись запустять руками без -p, ізоляція
|
||
# має лишитись: інше ім'я проєкту — це інші контейнери, інша мережа й,
|
||
# найголовніше, ІНШІ ТОМИ. Без нього `down -v` у пісочниці знищив би
|
||
# базу бойової інсталяції.
|
||
name: netpulse-sandbox
|
||
|
||
services:
|
||
db:
|
||
mem_limit: 768m
|
||
restart: "no"
|
||
|
||
cache:
|
||
mem_limit: 320m
|
||
restart: "no"
|
||
|
||
migrate:
|
||
mem_limit: 256m
|
||
|
||
cli:
|
||
mem_limit: 256m
|
||
|
||
api:
|
||
mem_limit: 384m
|
||
restart: "no"
|
||
|
||
collector:
|
||
mem_limit: 256m
|
||
restart: "no"
|
||
|
||
proxy:
|
||
mem_limit: 128m
|
||
restart: "no"
|
||
# Порти пише установник у .env.sandbox, попередньо переконавшись, що
|
||
# вони вільні. Значення за замовчуванням тут — щоб файл не був
|
||
# непрацездатним сам по собі, а не щоб на них покладатись.
|
||
ports: !override
|
||
- "127.0.0.1:${NETPULSE_SB_HTTP:-18080}:80"
|
||
- "127.0.0.1:${NETPULSE_SB_HTTPS:-18081}:443"
|
||
- "127.0.0.1:${NETPULSE_SB_GRPC:-18082}:9443"
|
||
|
||
agent:
|
||
mem_limit: 192m
|
||
restart: "no"
|
||
# Порожньо, а не інший порт: 162/udp не має автентифікації, і
|
||
# відкривати його заради перевірки означало б купити перевірку ціною
|
||
# дірки. Усе, що перевіряє зонд — обмін запрошення на токен, gRPC до
|
||
# колектора, поява рядка в core.agents, — відбувається вихідними
|
||
# з'єднаннями й публікації порту не потребує.
|
||
ports: !override []
|