Netpulse_SasS/scripts/dbtest.sh
byrsapty c83324ae3e
Some checks failed
CI / hygiene (push) Successful in 9s
CI / web (push) Successful in 1m13s
CI / server (push) Successful in 1m34s
CI / dbtest (push) Successful in 1m52s
CI / agent (push) Has been cancelled
Відкат на живому залізі: пароль адміністратора лежав відкритим
Механізм відкату існував з 0035 і жодного разу не виконувався на
справжньому обладнанні. Прогін до межі заліза (план -> заявка ->
погодження, без заливки) дав три правильні відмови й одну знахідку.

D-Link питає пароль інтерактивно, і `show config` віддає відповіді
окремими рядками без ключових слів. Порядкове маскування за зразками
такий рядок не бачить, тож пароль адміністратора живого комутатора
лежав у плані відкату, у ncm.rollbacks і в git-дзеркалі — маскування
перед записом у git немає взагалі.

redactLines отримав стан: після рядка заведення облікового запису до
двох односкладових рядків маскуються. Ім'я запису лишається видимим.

Дорогою: перший рядок збереженого конфігу — відлуння команди
(`Command: show config`), і планувальникклав його в команди до заливки.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-28 23:42:43 +03:00

119 lines
6.9 KiB
Bash
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# Прогін тестів проти СПРАВЖНЬОЇ бази.
#
# ЧОМУ ЦЕ ОКРЕМИЙ СКРИПТ
#
# Тести проти бази мовчки пропускаються без NETPULSE_TEST_DSN — і саме
# тому вони півтора року нічого не перевіряли: `go test ./...` показував
# «ok», а всередині кожного з них стояв t.Skip. «Пропущено» в підсумку
# виглядає рівно як «пройдено», і це найдорожча тиха відмова в проєкті:
# перевірка ізоляції кабінетів, стелі тарифу, гасіння алертів і драбин
# ескалації існували, компілювались і не виконувались.
#
# scripts/check.sh лишається швидким (без Docker і без бази) — його
# ганяють на кожну правку. Цей скрипт повільніший і потребує Postgres,
# тож викликається окремо: перед розгортанням і в CI.
#
# БАЗА МУСИТЬ БУТИ ОДНОРАЗОВОЮ. Тести пишуть, видаляють і перемикають
# ролі, а перед ними ще й котяться міграції — зокрема ті, яких у робочій
# базі ще не має бути. І це не побажання в коментарі: рівно так гине
# бойова база, коли в профілі шелла лишився експортований
# NETPULSE_TEST_DSN зі вчорашнього налагодження. Тому нижче стоїть
# перевірка імені, а не заклик до обережності.
#
# ВИКОРИСТАННЯ
# scripts/dbtest.sh # підніме свій Postgres
# NETPULSE_TEST_DSN=... scripts/dbtest.sh # проти готової бази,
# # ім'я якої містить probe/test
#
# У CI ЙДЕ ДРУГИЙ ШЛЯХ. Робота dbtest у .forgejo/workflows/ci.yml задає
# NETPULSE_TEST_DSN на базу netpulse_probe, яку раннер піднімає сервісом.
# Саме тому там і потрібна гілка «готова база»: підняти контейнер собі
# скрипт зміг би лише з докер-сокетом хоста всередині роботи, а це
# root-доступ до всієї машини для будь-якого workflow із будь-якої гілки.
# Другий наслідок цієї гілки — ім'я бази в CI мусить містити probe/test,
# інакше запобіжник нижче спрацює на власному конвеєрі.
#
set -u
SRC="$(cd "$(dirname "$0")/.." && pwd)"
OWN_DB=0
NAME=""
# Ім'я бази має саме казати, що вона одноразова. Перевірка навмисно
# дурна й невідмикна: розумніша (маркерна таблиця, прапорець згоди)
# перекладає рішення на людину рівно в той момент, коли людина поспішає.
guard_disposable() {
db=$(printf '%s' "$1" | sed -e 's/?.*$//' -e 's#.*/##')
case "$db" in
*probe*|*test*) return 0 ;;
esac
echo "!!! NETPULSE_TEST_DSN вказує на базу «$db»." >&2
echo " Тести пишуть, видаляють і котять міграції — база мусить бути" >&2
echo " одноразовою, і її імʼя має містити «probe» або «test»." >&2
echo " Якщо це чернетка — перейменуйте базу. Якщо ні — ви щойно мало" >&2
echo " не накотили міграції на робочу базу." >&2
exit 1
}
if [ -z "${NETPULSE_TEST_DSN:-}" ]; then
# Своя база на час прогону. Порт випадковий-таки ні: фіксований, але
# нетиповий, щоб не зіткнутись із локальним Postgres розробника.
PORT=${NETPULSE_TEST_PORT:-55433}
# Імʼя з номером процесу: два прогони поруч (другий термінал, дві
# задачі на одному раннері) інакше вбивали б бази один одному, і
# падіння виглядало б як помилка зʼєднання нізвідки.
NAME="netpulse-dbtest-$$"
echo "== піднімаю одноразовий Postgres :$PORT"
docker run -d --name "$NAME" -p "$PORT:5432" \
-e POSTGRES_USER=netpulse -e POSTGRES_PASSWORD=probe \
-e POSTGRES_DB=netpulse_probe \
timescale/timescaledb:2.17.2-pg16 >/dev/null || exit 1
OWN_DB=1
NETPULSE_TEST_DSN="postgres://netpulse:probe@127.0.0.1:$PORT/netpulse_probe?sslmode=disable"
export NETPULSE_TEST_DSN
n=0
until docker exec "$NAME" pg_isready -h 127.0.0.1 -U netpulse >/dev/null 2>&1; do
n=$((n+1)); [ "$n" -gt 60 ] && { echo "база не піднялась"; exit 1; }
sleep 1
done
else
guard_disposable "$NETPULSE_TEST_DSN"
fi
# Своя база зноситься лише після ЗЕЛЕНОГО прогону. Після червоного вона
# лишається: подивитись, що саме опинилось у таблицях, — єдиний спосіб
# зрозуміти половину падінь, а знесена база забирає цю можливість рівно
# тоді, коли вона потрібна.
cleanup() {
[ "$OWN_DB" = 1 ] || return 0
if [ "${rc:-1}" = 0 ]; then
docker rm -f "$NAME" >/dev/null 2>&1
else
echo
echo "база лишилась для розбору: docker exec -it $NAME psql -U netpulse netpulse_probe"
echo "прибрати: docker rm -f $NAME"
fi
return 0
}
trap cleanup EXIT INT TERM
# Міграції котяться З ЦЬОГО Ж ДЕРЕВА (go run), а не готовим образом — і
# це не дрібниця. Образ зібрано з розгорнутого коду, тож він знає лише
# старі міграції, і тести нового коду йшли б проти старої схеми: падіння
# виглядало б як «немає такого стовпця», хоч стовпець у гілці є. Один
# такий прогін уже збрехав саме так.
echo "== накат міграцій"
( cd "$SRC/server" && NETPULSE_DSN="$NETPULSE_TEST_DSN" go run ./cmd/netpulse-migrate ) || exit 1
echo "== тести"
( cd "$SRC/server" && go test ./internal/... -count=1 )
rc=$?
echo
if [ "$rc" = 0 ]; then
echo "усе зелене проти бази"
else
echo "!!! тести проти бази не пройшли"
fi
exit $rc