П'ять паралельних задач. Найцінніше в них — не можливості, а знайдене.
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 працює справжній.
103 lines
5.5 KiB
Bash
103 lines
5.5 KiB
Bash
#!/usr/bin/env sh
|
||
#
|
||
# Закінчення рядків: чи не заліз у репозиторій CRLF.
|
||
#
|
||
# Навіщо окрема перевірка. За один день CRLF зламав дві різні речі, і
|
||
# жодну з них не видно в diff:
|
||
#
|
||
# 1. gofmt почав друкувати як «не відформатовані» файли, яких ніхто не
|
||
# чіпав: він вважає \r частиною рядка й пропонує переписати файл
|
||
# цілком. Людина бачить червоне на чужому коді, і найкоротший вихід
|
||
# із цього — `gofmt -w` — комітить зіпсовані переноси всім.
|
||
# 2. db/profiles/build.py, запущений на Windows у текстовому режимі,
|
||
# переписав згенеровану міграцію 0014 з \r\n. Байти інші → sha256
|
||
# інший, а netpulse-migrate звіряє суму вже застосованих міграцій і
|
||
# зупиняє накат словами «міграцію змінено після застосування».
|
||
# Тобто невидима зміна зупинила б оновлення на всіх стендах одразу.
|
||
# Порівняння `build.py --check` цього НЕ ловить: Python читає
|
||
# текстом і сам перекладає \r\n у \n ще до порівняння.
|
||
#
|
||
# Перевіряються дві різні речі, і ціна в них різна:
|
||
#
|
||
# ІНДЕКС (i/crlf) — те, що дістанеться всім і поїде на стенд. Це
|
||
# помилка: скрипт падає. У CI це і є сторож.
|
||
# РОБОЧА КОПІЯ (w/crlf) — біда однієї машини. У CI її не буває, бо
|
||
# checkout свіжий; локально ж це рівно та причина,
|
||
# через яку gofmt червоніє на чужому. Тому тут
|
||
# попередження з підказкою, а з --strict (як у CI)
|
||
# — теж падіння: у свіжому клоні на Linux такого
|
||
# бути не може, і якщо воно є, зламаний checkout.
|
||
#
|
||
# .gitattributes оголошує «у репозиторії — завжди LF». Файли, яким LF не
|
||
# призначено (*.ps1 з eol=crlf, двійкові), з перевірки виключені: у них
|
||
# CRLF — не порушення, а оголошена норма.
|
||
#
|
||
# Запуск:
|
||
# sh scripts/check-eol.sh # індекс — жорстко, робоча копія — попередження
|
||
# sh scripts/check-eol.sh --strict # обидва жорстко (так робить CI)
|
||
#
|
||
# Полагодити:
|
||
# індекс: git add --renormalize . && git commit
|
||
# робоча копія: git config core.autocrlf false
|
||
# git rm --cached -r . && git reset --hard
|
||
|
||
set -u
|
||
|
||
# CDPATH= — не помилка з пробілом, а гасіння CDPATH: якщо він виставлений
|
||
# в оточенні, cd мовчки піде не туди, і скрипт перевірятиме чужий каталог.
|
||
# shellcheck disable=SC1007
|
||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||
cd "$ROOT" || exit 1
|
||
|
||
STRICT=0
|
||
if [ "${1:-}" = "--strict" ]; then
|
||
STRICT=1
|
||
fi
|
||
|
||
# `git ls-files --eol` друкує «i/xx w/xx attr/… <TAB> шлях»: розділювач
|
||
# перед шляхом — саме табуляція, тому шляхи з пробілами не розсипаються.
|
||
list=$(git ls-files --eol) || {
|
||
echo "check-eol: git ls-files не спрацював — це взагалі репозиторій?" >&2
|
||
exit 2
|
||
}
|
||
|
||
idx=$(printf '%s\n' "$list" | awk -F'\t' '
|
||
{ split($1, c, " ")
|
||
if (c[1] == "i/crlf" || c[1] == "i/mixed") print $2 }')
|
||
|
||
# eol=crlf у атрибутах означає «цьому файлу CRLF призначено навмисно»
|
||
# (.gitattributes: *.ps1). Такий файл у робочій копії з CRLF — норма.
|
||
wt=$(printf '%s\n' "$list" | awk -F'\t' '
|
||
{ split($1, c, " ")
|
||
if ((c[2] == "w/crlf" || c[2] == "w/mixed") && $1 !~ /eol=crlf/) print $2 }')
|
||
|
||
rc=0
|
||
|
||
if [ -n "$idx" ]; then
|
||
echo "CRLF в ІНДЕКСІ — це поїде всім і зупинить накат міграцій:"
|
||
printf '%s\n' "$idx" | sed 's/^/ /'
|
||
echo " полагодити: git add --renormalize . && git commit"
|
||
rc=1
|
||
fi
|
||
|
||
if [ -n "$wt" ]; then
|
||
n=$(printf '%s\n' "$wt" | wc -l | tr -d ' ')
|
||
if [ "$STRICT" = "1" ]; then
|
||
echo "CRLF у РОБОЧІЙ КОПІЇ ($n): у свіжому клоні на Linux такого бути не може."
|
||
printf '%s\n' "$wt" | sed 's/^/ /'
|
||
rc=1
|
||
else
|
||
echo "увага: CRLF у робочій копії ($n файлів) — в індексі при цьому LF."
|
||
echo " саме через це gofmt може показувати неформатованими файли,"
|
||
echo " яких ніхто не чіпав, а генератори — переписувати цілі файли."
|
||
printf '%s\n' "$wt" | sed 's/^/ /'
|
||
echo " полагодити: git config core.autocrlf false"
|
||
echo " git rm --cached -r . && git reset --hard"
|
||
fi
|
||
fi
|
||
|
||
if [ "$rc" = "0" ] && [ -z "$wt" ]; then
|
||
echo "закінчення рядків у порядку"
|
||
fi
|
||
|
||
exit "$rc"
|