From b857c58d89e13446138ffc6ee52a091efe191b14 Mon Sep 17 00:00:00 2001 From: jestivald Date: Mon, 31 Aug 2026 19:56:26 +0300 Subject: [PATCH 1/3] =?UTF-8?q?fix(optimize):=20=D1=80=D0=BE=D1=82=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=E2=80=94=20=D1=80=D0=B5-=D1=80=D0=B0?= =?UTF-8?q?=D0=BD=20=D0=B1=D0=B5=D0=B7=20=D0=BF=D0=B0=D0=B4=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F,=20=D0=BA=D0=BE=D0=BD=D1=84=D0=BB=D0=B8=D0=BA?= =?UTF-8?q?=D1=82=20=D0=BC=D0=B0=D1=81=D0=BE=D0=BA=20=D1=80=D0=B5=D1=88?= =?UTF-8?q?=D0=B0=D0=B5=D1=82=20=D1=81=D0=B0=D0=BC=20logrotate=20(#24,=20#?= =?UTF-8?q?25)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раскатка v4.0 на флот в день релиза вскрыла два бага секции ротации и один латентный. Ре-ран (#24): backup_file звался с одним аргументом; на первом прогоне [[ -f ]] коротил цепочку, на повторном голый $2 под set -u ронял модуль посреди секции — падал ровно тот прогон, которым чинят конфигурацию. Теперь аргумент передаётся, а хелпер требует каталог назначения через ${2:?…}: будущий одноаргументный вызов упадёт сразу и внятно на любом прогоне. Дубль-детект (#25): сравнение СТРОК масок против чужих станс, а logrotate дедуплицирует по РАСКРЫТЫМ файлам — конфликт с явными путями или другим глобом не ловился, logrotate целиком скипал стансу-жертву и выходил с ошибкой, na-logrotate.service уходил в failed при active-таймере. Теперь арбитр — сам logrotate: станса пишется целиком, `-d` по всему набору, конфликтные маски отдаются чужим стансам (у них может быть сигнальный reload вместо copytruncate). Чужие дубликаты вне наших масок — предупреждение, не наша починка. Латентный: голый word-split $NA_LOG_PATHS глоб-раскрывался по живым файлам, и в стансу ложились ЯВНЫЕ пути вместо масок — лог нового vhost'а никогда не начал бы ротироваться. Теперь read -a: маски идут как заданы. tests/logrotate-unit.sh извлекает секцию и ИСПОЛНЯЕТ её против стабов logrotate/systemctl (5 кейсов, 23 проверки; на v4.0 красный по всем трём пунктам) — добавлен в CI. Co-Authored-By: Claude Fable 5 --- .github/workflows/ci.yml | 5 ++ scripts/lib/common.sh | 9 ++- scripts/optimize.sh | 74 ++++++++++++------ tests/logrotate-unit.sh | 164 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 228 insertions(+), 24 deletions(-) create mode 100644 tests/logrotate-unit.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 48b5c2f..f96da20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,11 @@ jobs: # v4-mapped пиры (`[::ffff:…]` от ss) находятся в live-lookup: обе ошибки # молча ломали ctguard и рвали пользовательские сессии (issue #22). run: bash tests/ctguard-unit.sh + - name: logrotate unit (ИСПОЛНЯЕТ секцию ротации optimize.sh против стабов) + # Ре-ран не падает на backup_file без 2-го аргумента (#24), конфликт масок + # решает вердикт самого logrotate, а не сравнение строк (#25), и глобы + # NA_LOG_PATHS не раскрываются шеллом в явные пути. + run: bash tests/logrotate-unit.sh # ── Smoke-тесты на матрице дистрибутивов ──────────────────────────────────── # Ловит ровно тот класс регрессий, из-за которых появился этот PR: установка diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 9487032..9f22b5c 100755 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -108,7 +108,14 @@ backup_dir() { mkdir -p "$d" echo "$d" } -backup_file() { [[ -f "$1" ]] && cp -a "$1" "$2/"; return 0; } +# ${2:?}: одноаргументный вызов обязан падать сразу и с внятным текстом — а не +# «$2: unbound variable» из глубины, и только на ре-ране, когда файл впервые +# существует и [[ -f ]] перестаёт коротить цепочку (issue #24). +backup_file() { + local dst="${2:?backup_file: нужен каталог назначения}" + [[ -f "$1" ]] && cp -a "$1" "$dst/" + return 0 +} apt_install() { export DEBIAN_FRONTEND=noninteractive diff --git a/scripts/optimize.sh b/scripts/optimize.sh index 2b896ce..1a3557f 100755 --- a/scripts/optimize.sh +++ b/scripts/optimize.sh @@ -705,20 +705,24 @@ else apt_install logrotate || warn "logrotate не доустановился — ротация работать не будет" fi - # Маски, которые уже держит ЧУЖАЯ станса, забирать себе нельзя: logrotate на дубликат - # пути отвечает «duplicate log entry» и пропускает НАШ файл целиком. Коварно то, что - # проверка одного файла (`logrotate -d <наш>`) при этом рапортует, что всё в порядке. + # Маски, уже покрытые ЧУЖОЙ стансой, забирать себе нельзя: logrotate на дубликат пути + # отвечает «duplicate log entry», целиком пропускает ту стансу, которой файл достался + # вторым, и выходит с ошибкой — na-logrotate.service уходит в failed при внешне + # здоровом таймере. Сверять маски СТРОКАМИ бесполезно: logrotate дедуплицирует по + # РАСКРЫТЫМ файлам, и чужая станса с явными путями или другим глобом проходит мимо + # текстового сравнения. Единственный честный арбитр — сам logrotate (`-d` по ВСЕМУ + # набору): пишем стансу целиком, спрашиваем его и конфликтные маски отдаём чужим + # стансам — у них может быть сигнальный reload вместо copytruncate, им и владеть. + # read -a, а не голый word-split: иначе шелл сам раскроет глобы по живым файлам, + # и в стансу лягут ЯВНЫЕ пути — лог нового vhost'а никогда не начнёт ротироваться. _want=(); _dup=() - for _m in $NA_LOG_PATHS; do - if grep -rqsF -- "$_m" /etc/logrotate.d/ --exclude="$(basename "$LR_CONF")" 2>/dev/null; then - _dup+=("$_m") - else - _want+=("$_m") - fi - done + read -r -a _want <<<"$NA_LOG_PATHS" - if [[ "${#_want[@]}" -gt 0 ]]; then - backup_file "$LR_CONF" + _na_lr_write() { + if [[ "${#_want[@]}" -eq 0 ]]; then + rm -f "$LR_CONF" + return 0 + fi { printf '%s ' "${_want[@]}" cat < "$LR_CONF" chmod 0644 "$LR_CONF" + } + + # copytruncate, а не reopen-сигнал: nginx и ядро ноды живут в контейнерах, послать им + # USR1 из хостовой ротации некому. + backup_file "$LR_CONF" "$BACKUP" + _na_lr_write + + if command -v logrotate >/dev/null 2>&1; then + while [[ "${#_want[@]}" -gt 0 ]]; do + _dupf="$({ logrotate -d /etc/logrotate.conf 2>&1 || true; } \ + | sed -n 's/.*duplicate log entry for //p' | sort -u)" + [[ -n "$_dupf" ]] || break + _keep=() + for _m in "${_want[@]}"; do + _hit=0 + while IFS= read -r _f; do + [[ -n "$_f" ]] || continue + # shellcheck disable=SC2053 # маска без кавычек — намеренный glob-матч + if [[ "$_f" == $_m ]]; then _hit=1; break; fi + done <<<"$_dupf" + if [[ "$_hit" -eq 1 ]]; then _dup+=("$_m"); else _keep+=("$_m"); fi + done + if [[ "${#_keep[@]}" -eq "${#_want[@]}" ]]; then + # наших масок дубликаты не задевают — это конфликт между чужими + # стансами, чинить его не нам + warn "дубликаты путей вне наших масок — часть чужих станс пропускается: logrotate -d /etc/logrotate.conf" + break + fi + _want=("${_keep[@]}") + _na_lr_write + done + fi + + if [[ "${#_want[@]}" -gt 0 ]]; then ok "стансa $LR_CONF: ${_want[*]} (maxsize $NA_LOG_MAXSIZE, rotate $NA_LOG_ROTATE)" else - rm -f "$LR_CONF" info "все заданные пути уже покрыты другими стансами — свою не создаю" fi - # copytruncate, а не reopen-сигнал: nginx и ядро ноды живут в контейнерах, послать им - # USR1 из хостовой ротации некому. for _m in "${_dup[@]}"; do - warn "путь $_m уже покрыт чужой стансой в /etc/logrotate.d — проверь, что там задан maxsize" + warn "маска $_m уже покрыта чужой стансой в /etc/logrotate.d — отдана ей; проверь, что там задан maxsize" done cat > /etc/systemd/system/na-logrotate.service <<'EOF' @@ -772,13 +807,6 @@ EOF systemctl enable --now na-logrotate.timer >/dev/null 2>&1 \ && ok "na-logrotate.timer: прогон $NA_LOG_INTERVAL" \ || warn "na-logrotate.timer не включился" - - # Валидировать можно только весь набор: конфликт масок виден лишь в общем прогоне. - if command -v logrotate >/dev/null 2>&1; then - if logrotate -d /etc/logrotate.conf 2>&1 | grep -qi 'duplicate log entry'; then - warn "logrotate сообщает о дубликате путей — часть станс будет пропущена: logrotate -d /etc/logrotate.conf" - fi - fi fi # ─── 9. THP off ────────────────────────────────────────────────────────────── diff --git a/tests/logrotate-unit.sh b/tests/logrotate-unit.sh new file mode 100644 index 0000000..97fadce --- /dev/null +++ b/tests/logrotate-unit.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash +# +# logrotate-unit.sh — ИСПОЛНЯЕТ секцию «ротация логов ноды» из optimize.sh в песочнице +# против стабов logrotate/systemctl. Секция — top-level код, целиком optimize в CI не +# гоняется, поэтому оба бага раскатки v4.0 жили именно здесь (issues #24, #25). +# +# Что стережём: +# 1. ре-ран на настроенной ноде НЕ падает (backup_file без 2-го аргумента, #24); +# 2. конфликт с чужой стансой решает вердикт САМОГО logrotate, а не сравнение строк: +# конфликтная маска отдаётся чужой стансе, наша станса переписывается (#25); +# 3. глоб-маски попадают в стансу КАК ЗАДАНЫ — не раскрытыми шеллом в явные пути по +# живым файлам (иначе лог нового vhost'а никогда не начал бы ротироваться); +# 4. чужой дубликат вне наших масок не зацикливает и нашу стансу не трогает; +# 5. полная уступка всех масок = стансы нет и есть внятное инфо-сообщение. +# +# Не требует root/сети/systemd. Запуск: bash tests/logrotate-unit.sh +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +T="$(mktemp -d)" +trap 'rm -rf "$T"' EXIT +LRD="$T/etc/logrotate.d" +REC="$T/rec" +export LRD REC +mkdir -p "$T/bin" "$LRD" "$T/systemd" "$T/backup" "$REC" \ + "$T/var/log/nginx" "$T/var/log/remnanode" + +# Секции нужен bash ≥ 4.4 (пустые массивы под set -u) — на нодах и CI он есть всегда, +# а вот системный bash macOS древний: берём первый, который умеет. +pick_bash() { + local c + for c in bash /opt/homebrew/bin/bash /usr/local/bin/bash; do + command -v "$c" >/dev/null 2>&1 || continue + if "$c" -c 'set -u; a=(); : "${a[@]}"' 2>/dev/null; then command -v "$c"; return 0; fi + done + return 1 +} +WBASH="$(pick_bash)" || { echo "[x] не нашёл bash ≥ 4.4 для исполнения секции"; exit 1; } + +# живые файлы под масками — ловушка для глоб-раскрытия шеллом (свойство 3) +touch "$T/var/log/nginx/access.log" "$T/var/log/nginx/error.log" "$T/var/log/remnanode/node.log" +: > "$REC/foreign-claims.txt" +: > "$REC/foreign-dup.txt" + +# ── Достаём секцию 8b из optimize.sh (top-level код между маркерами разделов) ─── +awk '/^# ─── 8b\./{f=1} /^# ─── 9\./{f=0} f' "$REPO_ROOT/scripts/optimize.sh" > "$T/section.raw" +[ -s "$T/section.raw" ] || { echo "[x] не смог извлечь секцию 8b из optimize.sh"; exit 1; } +# системные пути → в песочницу (sed НЕ рескантит подстановку, самоссылка $LRD безопасна) +sed -e "s#/etc/logrotate\.d#$LRD#g" \ + -e "s#/etc/logrotate\.conf#$T/etc/logrotate.conf#g" \ + -e "s#/etc/systemd/system/#$T/systemd/#g" \ + "$T/section.raw" > "$T/section.sh" + +cat > "$T/wrap.sh" < "$T/bin/systemctl" <<'ST' +#!/bin/sh +exit 0 +ST +# Эмуляция «logrotate -d »: дедуп по РАСКРЫТЫМ файлам, как у настоящего. +# foreign-claims.txt — пути, которые уже держат чужие стансы: дубликат, если путь +# всё ещё покрыт маской нашей стансы (1-я строка na-node-logs); +# foreign-dup.txt — дубликат между двумя ЧУЖИМИ стансами (репортится всегда). +cat > "$T/bin/logrotate" <<'LR' +#!/bin/bash +set -f +printf '%s\n' "$*" >> "$REC/logrotate.argv" +rc=0 +if [ -f "$LRD/na-node-logs" ] && [ -s "$REC/foreign-claims.txt" ]; then + masks="$(head -1 "$LRD/na-node-logs" | sed 's/ *{.*$//')" + while IFS= read -r p; do + [ -n "$p" ] || continue + for m in $masks; do + # shellcheck disable=SC2053 # маска без кавычек — намеренный glob-матч + if [[ "$p" == $m ]]; then + echo "error: foreign:1 duplicate log entry for $p" >&2 + echo "error: found error in file foreign, skipping" >&2 + rc=1 + break + fi + done + done < "$REC/foreign-claims.txt" +fi +if [ -s "$REC/foreign-dup.txt" ]; then + while IFS= read -r p; do + [ -n "$p" ] || continue + echo "error: other:1 duplicate log entry for $p" >&2 + rc=1 + done < "$REC/foreign-dup.txt" +fi +exit "$rc" +LR +chmod +x "$T/bin/systemctl" "$T/bin/logrotate" +export PATH="$T/bin:$PATH" + +MASKS="$T/var/log/nginx/*.log $T/var/log/remnanode/*.log" +STANZA="$LRD/na-node-logs" + +fail=0 +expect() { local d="$1"; shift; if "$@" >/dev/null 2>&1; then echo " ✔ $d"; else echo " ✘ $d"; fail=1; fi; } +expect_not() { local d="$1"; shift; if "$@" >/dev/null 2>&1; then echo " ✘ $d"; fail=1; else echo " ✔ $d"; fi; } + +run_section() { + : > "$REC/logrotate.argv" + NA_LOG_PATHS="$MASKS" "$WBASH" "$T/wrap.sh" > "$T/out.log" 2>&1 +} + +# ── Кейс 1: первый прогон, конфликтов нет ─────────────────────────────────────── +echo "== первый прогон (чисто) ==" +expect "секция отработала (rc=0)" run_section +expect "станса создана" test -f "$STANZA" +expect "глоб nginx в стансе КАК ЗАДАН (не раскрыт по живым файлам)" grep -qF "$T/var/log/nginx/*.log" "$STANZA" +expect "глоб remnanode в стансе" grep -qF "$T/var/log/remnanode/*.log" "$STANZA" +expect_not "явных раскрытых путей в стансе нет" grep -qF "access.log" "$STANZA" +expect "сервис-юнит записан" test -f "$T/systemd/na-logrotate.service" +expect "таймер-юнит записан" test -f "$T/systemd/na-logrotate.timer" + +# ── Кейс 2: ре-ран на настроенной ноде (issue #24) ────────────────────────────── +echo "== ре-ран (станса уже существует — #24) ==" +expect "ре-ран НЕ упал" run_section +expect "станса на месте после ре-рана" test -f "$STANZA" +expect "бэкап прежней стансы сделан" test -f "$T/backup/na-node-logs" + +# ── Кейс 3: чужая станса держит наш путь (issue #25) ──────────────────────────── +echo "== конфликт с чужой стансой (#25) ==" +rm -f "$STANZA" +# текстуально НЕ совпадает с нашей маской — строковый греп такое не ловил +printf '%s\n' "$T/var/log/nginx/*" '{ daily }' > "$LRD/nginx-legacy" +printf '%s\n' "$T/var/log/nginx/access.log" > "$REC/foreign-claims.txt" +expect "секция отработала (rc=0)" run_section +expect "станса создана (не снесена целиком)" test -f "$STANZA" +expect_not "конфликтная маска nginx ОТДАНА чужой стансе" grep -qF "$T/var/log/nginx" "$STANZA" +expect "неконфликтная маска remnanode осталась" grep -qF "$T/var/log/remnanode/*.log" "$STANZA" +expect "warn про уступку маски напечатан" grep -q "уже покрыта чужой стансой" "$T/out.log" +expect "после переписывания стансы вердикт перепроверен" test "$(wc -l < "$REC/logrotate.argv")" -ge 2 + +# ── Кейс 4: чужой дубликат вне наших масок ────────────────────────────────────── +echo "== чужой дубликат (не наши маски) ==" +rm -f "$STANZA" "$LRD/nginx-legacy" +: > "$REC/foreign-claims.txt" +printf '%s\n' "/var/log/other/app.log" > "$REC/foreign-dup.txt" +expect "секция отработала (rc=0)" run_section +expect "наши маски не тронуты" grep -qF "$T/var/log/nginx/*.log" "$STANZA" +expect "warn про чужой конфликт напечатан" grep -q "вне наших масок" "$T/out.log" +expect "цикл не зациклился (ровно один вызов -d)" test "$(wc -l < "$REC/logrotate.argv")" -eq 1 + +# ── Кейс 5: все маски уже у чужих станс ───────────────────────────────────────── +echo "== полная уступка всех масок ==" +rm -f "$STANZA" +: > "$REC/foreign-dup.txt" +printf '%s\n' "$T/var/log/nginx/access.log" "$T/var/log/remnanode/node.log" > "$REC/foreign-claims.txt" +expect "секция отработала (rc=0)" run_section +expect "станса не создана (все пути чужие)" test ! -f "$STANZA" +expect "инфо-сообщение напечатано" grep -q "свою не создаю" "$T/out.log" + +if [ "$fail" -ne 0 ]; then echo "LOGROTATE-UNIT: FAIL"; exit 1; fi +echo "LOGROTATE-UNIT: OK (ре-ран жив, конфликты решает вердикт logrotate, глобы не раскрываются, чужие дубликаты не наши)" From 3096f3d0e2c8963d61afa22e130bb0cc1f0825f3 Mon Sep 17 00:00:00 2001 From: jestivald Date: Mon, 31 Aug 2026 19:56:35 +0300 Subject: [PATCH 2/3] =?UTF-8?q?release:=20v4.0.1=20=E2=80=94=20=D0=B2?= =?UTF-8?q?=D0=B5=D1=80=D1=81=D0=B8=D1=8F,=20changelog,=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=D0=BC=D0=B5=D1=80=D1=8B=20=D0=BF=D0=B8=D0=BD=D0=BD=D0=B8?= =?UTF-8?q?=D0=BD=D0=B3=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NA_VERSION 4.0.0 → 4.0.1, NA_REF в примерах README/install.sh → v4.0.1, секция в CHANGELOG. Патч-релиз: фиксы секции ротации логов (#24, #25) и глоб-раскрытия NA_LOG_PATHS. Co-Authored-By: Claude Fable 5 --- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++-- install.sh | 2 +- scripts/lib/common.sh | 2 +- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cc3b37a..3d301b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Changelog +## v4.0.1 — 2026-08-31 + +Два бага секции ротации логов, пойманные в день релиза при раскатке v4.0 на флот +([#24](https://github.com/jestivald/node-accelerator/issues/24), +[#25](https://github.com/jestivald/node-accelerator/issues/25)): оба жили в +конфигурациях, которых не было в CI — повторный прогон и чужие стансы logrotate. +Плюс латентный третий, который вскрыл новый тест. + +### 🔴 Ре-ран optimize падал на уже настроенной ноде (#24) + +`backup_file` звался с одним аргументом вместо двух. На первом прогоне стансы ещё нет, +`[[ -f ]]` коротит цепочку — баг невидим; на повторном файл существует, и голый `$2` под +`set -u` ронял модуль посреди секции ротации (всё после неё не выполнялось). То есть +падал ровно тот прогон, которым конфигурацию чинят: сузить `NA_LOG_PATHS` ре-раном было +нельзя. Аргумент передаётся, а сам хелпер теперь требует каталог назначения через +`${2:?…}` — будущий одноаргументный вызов упадёт сразу и с внятным текстом на любом +прогоне, а не «unbound variable» из глубины на второй день жизни ноды. + +### 🔴 Конфликт масок с чужими стансами не ловился (#25) + +Дубль-детект сравнивал СТРОКИ масок (`grep -F` по `/etc/logrotate.d/`), а logrotate +дедуплицирует по РАСКРЫТЫМ файлам. Чужая станса с явными путями, пакетная станса nginx +или пересекающийся глоб проходили мимо текстового сравнения; logrotate отвечал +`duplicate log entry`, целиком пропускал ту стансу, которой файл достался вторым, и +выходил с ошибкой — `na-logrotate.service` уходил в failed при внешне здоровом таймере. +Теперь арбитр — сам logrotate: станса пишется целиком, прогоняется `logrotate -d` по +всему набору, и конфликтные маски отдаются чужим стансам с предупреждением (у чужой +стансы может быть сигнальный reload вместо `copytruncate` — ей и владеть). Дубликаты, +не задевающие наши маски, — конфликт между чужими стансами: о нём предупреждаем, но +чинить его не нам. + +### 🟠 Глобы из `NA_LOG_PATHS` раскрывались шеллом в явные пути + +Смежный люк, вскрытый новым тестом: голый word-split `$NA_LOG_PATHS` заодно раскрывал +глобы по живым файлам, и на ноде с существующими логами станса записывалась с ЯВНЫМИ +путями вместо масок — лог нового vhost'а никогда не начал бы ротироваться. Теперь маски +идут в стансу как заданы (`read -a`). + +### 🧪 Тест + +`tests/logrotate-unit.sh` извлекает секцию ротации из `optimize.sh` и ИСПОЛНЯЕТ её в +песочнице против стабов `logrotate`/`systemctl`: первый прогон, ре-ран, конфликт с +чужой стансой, чужой дубликат вне наших масок, полная уступка всех масок. На коде v4.0 +он красный по всем трём пунктам. Добавлен в CI. + ## v4.0 — 2026-08-31 Мажорная не из-за размера, а из-за смены дефолтов: тулкит теперь сам ротирует логи ноды diff --git a/README.md b/README.md index 472c0e6..07756ad 100644 --- a/README.md +++ b/README.md @@ -118,11 +118,11 @@ curl -fsSL https://raw.githubusercontent.com/jestivald/node-accelerator/main/ins # прод-режим: пиньте тег через NA_REF — компрометация ветки main тогда не утечёт # сразу на весь флот (скрипты тянутся из того же тега): -export NA_REF=v4.0 +export NA_REF=v4.0.1 curl -fsSL "https://raw.githubusercontent.com/jestivald/node-accelerator/$NA_REF/install.sh" | sudo -E bash -s all # максимум: + проверка minisign-подписей модулей (подписи лежат в дереве с v3.6): -export NA_REF=v4.0 NA_REQUIRE_SIG=1 \ +export NA_REF=v4.0.1 NA_REQUIRE_SIG=1 \ NA_MINISIGN_PUBKEY="RWQrJghT9nkdBC3ntiEXF29zrS8o429WhObHKq6I7CKoftVDhQBrBscu" curl -fsSL "https://raw.githubusercontent.com/jestivald/node-accelerator/$NA_REF/install.sh" | sudo -E bash -s all ``` diff --git a/install.sh b/install.sh index 6bf716c..5978d05 100755 --- a/install.sh +++ b/install.sh @@ -13,7 +13,7 @@ # curl-bash: # curl -fsSL https://raw.githubusercontent.com/jestivald/node-accelerator/main/install.sh | sudo bash -s all # # прод: пиньте тег (компрометация ветки main тогда не утечёт сразу на весь флот): -# export NA_REF=v4.0; curl -fsSL "https://raw.githubusercontent.com/jestivald/node-accelerator/$NA_REF/install.sh" | sudo -E bash -s all +# export NA_REF=v4.0.1; curl -fsSL "https://raw.githubusercontent.com/jestivald/node-accelerator/$NA_REF/install.sh" | sudo -E bash -s all # # + подписи модулей: NA_REQUIRE_SIG=1 NA_MINISIGN_PUBKEY=<ключ из README> # # ENV: NA_REF=<ветка|тег> NA_REPO_URL=<база raw-URL, для форка/зеркала> diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 9f22b5c..85942b1 100755 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -6,7 +6,7 @@ # Версия тулкита — ЕДИНСТВЕННЫЙ источник. Пишется в installed-маркеры и отдаётся # в na-diagnose/na-report --json, чтобы флот-мониторинг видел version-drift по нодам. # shellcheck disable=SC2034 -NA_VERSION="4.0.0" +NA_VERSION="4.0.1" # shellcheck disable=SC2034 RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m' From cd18484e0470bdbc0be94857315793f3943aaaea Mon Sep 17 00:00:00 2001 From: jestivald Date: Mon, 31 Aug 2026 19:56:53 +0300 Subject: [PATCH 3/3] release: sign 6 modules with minisign (v4.0.1) Co-Authored-By: Claude Fable 5 --- scripts/diagnose.sh.minisig | 6 +++--- scripts/lib/common.sh.minisig | 8 ++++---- scripts/na-report.sh.minisig | 6 +++--- scripts/optimize.sh.minisig | 8 ++++---- scripts/protect.sh.minisig | 6 +++--- scripts/rollback.sh.minisig | 6 +++--- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/scripts/diagnose.sh.minisig b/scripts/diagnose.sh.minisig index 17b0c3b..c0a072d 100644 --- a/scripts/diagnose.sh.minisig +++ b/scripts/diagnose.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 +untrusted comment: node-accelerator v4.0.1 RUQrJghT9nkdBLJfnqldUYYax1SmBwgDdXRiDFhrsI/FzxS/JgJj3fpgeZhq1UgmtIIIawExiiZNCPN/sHzr5+je/5GdATHZGAU= -trusted comment: timestamp:1788161062 file:diagnose.sh hashed -Wm6jzaGDtAQE6f98W4X14ojFAwa0e16h5bvv9MHOo2p1Zpr6OedPG6B1ROdHbqxT5Hpq+aRa+USbDAIpCaOADg== +trusted comment: timestamp:1788195409 file:diagnose.sh hashed +p5ofh+JC9BbY/T1Ctzr1u4sfyJIXbK1tU+tjD1sc62MuFzHn8K6hAn3Qp+YXnTr3gpnfhXTIH+M6P472fVN9Ag== diff --git a/scripts/lib/common.sh.minisig b/scripts/lib/common.sh.minisig index c25eb39..fb82d29 100644 --- a/scripts/lib/common.sh.minisig +++ b/scripts/lib/common.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 -RUQrJghT9nkdBKP1CAbKOjEUxpArA9TpYLGsjA4KF/awmetbs0LAG7xbesa7r7D4HEBrXhVjzkUfOXmUEsGfC9PdKlB22cmRBQE= -trusted comment: timestamp:1788161062 file:common.sh hashed -sDkHwJrZcY82mNlucEyEP2J2tQU8mGmwW8gW6c44YlQbc8jV7Btu7RcNwHrLur0DySY8KEpSVX0xRudKfCYADQ== +untrusted comment: node-accelerator v4.0.1 +RUQrJghT9nkdBKwOKY4N7laoNFGudKyYKokpkqAVMO8ZL4A4qfqQhZaOGhlEmr2CoQzYBKkDBi1zCCr7T7s8AqmpXRfAmxzUVA4= +trusted comment: timestamp:1788195409 file:common.sh hashed +beUfhY5bkXI9hMQ1bSyzrwTsN0DcXEW9QoB904FiGp9eGTHqx9uGmdTCGOXuRszMuwG4ihcCtzPUPpchydRNDg== diff --git a/scripts/na-report.sh.minisig b/scripts/na-report.sh.minisig index 5452eee..89b2113 100644 --- a/scripts/na-report.sh.minisig +++ b/scripts/na-report.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 +untrusted comment: node-accelerator v4.0.1 RUQrJghT9nkdBNmjwr6wpd5z//F4lgTsIa6dWD/8N/aZY869CdDgKV+Sz4Y8fqWUgyQVQCj30hO7g1POm4jwkgYMS0cODVv5pQY= -trusted comment: timestamp:1788161062 file:na-report.sh hashed -5DcMG4/Kr7XfH68anHa4vn2ETtyqqYbRoYxbYWqjGKCf63kD1HvyPc25lb1Zg4tO7DXwNCtxddLnhUguM4aUBw== +trusted comment: timestamp:1788195409 file:na-report.sh hashed +MZDoiNSUoUk2WboLttANFBlRp8DTtrGN+nroi6Bgo39ZrsYD3cjX7h/OwWsV/w/CPg7VLJ0RNmxkrU7acItzAw== diff --git a/scripts/optimize.sh.minisig b/scripts/optimize.sh.minisig index dd6a1d6..53ed6d8 100644 --- a/scripts/optimize.sh.minisig +++ b/scripts/optimize.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 -RUQrJghT9nkdBEEPH+fmt7Ut3CWAoeVlx1XNLe6962P9kFFpWl+qMPHydIb7tEFqZ/N+hsEe1TlPy4d5dkV1GnZXvNsU2IC6Hg8= -trusted comment: timestamp:1788161062 file:optimize.sh hashed -1wdr1EAlc/58tLmaYyRXY95DWdsGt7U0HrzcZJjQz521WpISU1C/QpDOPNGRE/MXr5URKFGHZvX/c305WhoeDg== +untrusted comment: node-accelerator v4.0.1 +RUQrJghT9nkdBAWiEgKBFnAYZ9EfYbT1tC/09FL5a79BZ5+u6e7FmsylSJ/kVOIAzHWpdCHnsxO9thv+pZ+8VftRqcv7FzzCBwI= +trusted comment: timestamp:1788195409 file:optimize.sh hashed +kGEu8xrDSP4JIp61fjLkWuzvPaPk8xnHdkWHDCCuiLSZeFjiQ8qKgZKn17/jlk6Z1ICJMykSKw0IBX+T5tjZCA== diff --git a/scripts/protect.sh.minisig b/scripts/protect.sh.minisig index e7cd661..2db4061 100644 --- a/scripts/protect.sh.minisig +++ b/scripts/protect.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 +untrusted comment: node-accelerator v4.0.1 RUQrJghT9nkdBJW7QbjT9v5Dk6an8bokwh6Gr4iIZoMQBo1F5KKnSg73UhWoWBCLp/iabhet9WHP/SiR00YJ9QBWdnmXTuhkDAw= -trusted comment: timestamp:1788161062 file:protect.sh hashed -m2ADFdtUHbq+3VBiUc9BCVBiPjsWpdb7oayReUR74X5eXjVsbPpdPQY/bv4I9E97jyYhZ+mLixFMAjl1gDfNCQ== +trusted comment: timestamp:1788195409 file:protect.sh hashed +LZVWgqk1U6+p2WHdRhrxog/LmwDJfoQTcGN1bZZZRV48oK44J/i7isxqsNVbvzkmPBw2ppufPDbJH+gb0FSMBw== diff --git a/scripts/rollback.sh.minisig b/scripts/rollback.sh.minisig index 7200da6..1c471d1 100644 --- a/scripts/rollback.sh.minisig +++ b/scripts/rollback.sh.minisig @@ -1,4 +1,4 @@ -untrusted comment: node-accelerator v4.0 +untrusted comment: node-accelerator v4.0.1 RUQrJghT9nkdBHtUwNrCoDinG8eRDo4TrqXAq0Hwzrh4mZGVTElcs2zYKR/xOS808sfl3QbCPUy1zVF++n61QNMXVXUvMX3J6AU= -trusted comment: timestamp:1788161062 file:rollback.sh hashed -aS1HWHEAT7C/J/CEt7uDzOgcUbXYqmhmVDn9SToYoaSFyu29WwzG8JZjKkts162HOsMleWF7hZ7lBihQsUHlCw== +trusted comment: timestamp:1788195409 file:rollback.sh hashed +nDy52eEyypysmejwrXtouFE11L2zaZwcS2IC6E7CWV7QAhcFyWofGnhB6AZcGScjHojnESJMG2WObTAxmH7KAw==