fix(build): исключить SIGPIPE из релизных гейтов под pipefail

Поиск с флагом -q прекращает чтение на первом совпадении и закрывает свой конец
канала. Продюсер, которому осталось что писать, получает SIGPIPE и завершается
кодом 141, а `set -o pipefail` делает 141 статусом всей конструкции:

    совпадение НАЙДЕНО -> продюсер оборван -> статус 141 -> «не найдено»

Для утвердительных проверок это ложный FAIL. Для отрицательных — «такой
конструкции в коде нет» — ложный PASS: запрещённая конструкция найдена, а гейт
зелёный. Отрицательными проверками закреплена половина инвариантов приёмки,
включая запрет обхода тестов и запрет `pnpm audit --prod`.

Порог резкий: пока вывод продюсера помещается в буфер канала (64 KiB на Linux),
он не блокируется и успевает завершиться раньше, чем потребитель начнёт читать.
Замер, 60 прогонов на размер: до 60 KiB — 0 отказов, ровно на 64 KiB — 58/60,
от 96 KiB — 60/60. То есть проверка выглядит исправной ровно до первого
источника крупнее буфера, а такие файлы в репозитории уже есть.

- 56 мест переведены на here-string: `grep -q PATTERN <<<"$content"`;
- продюсеры-команды (ss|awk, dpkg-query, /proc/cpuinfo, systemctl
  list-unit-files) сначала читаются в переменную;
- введён code_has: десять отрицательных сканов держались на `|| true` внутри
  code_without_comments, гасившем 141, — то есть на побочном эффекте
  подавления ошибок, а не на заявленном свойстве;
- несуществующий путь в скане больше не означает успех: `2>/dev/null || true`
  превращал опечатку в пустой вывод, а пустой вывод для проверки «этого в коде
  нет» — это PASS. Проверка явная, а не через set -e: в контексте `! code_has`
  bash отключает errexit на весь вызов;
- возврат пайплайна запрещён отдельной приёмкой.
This commit is contained in:
2026-09-01 04:28:54 +05:00
parent 2259f7c847
commit a1c74caa0c
11 changed files with 251 additions and 82 deletions
+4 -4
View File
@@ -41,7 +41,7 @@ REQUIRED_CONTRACT_VARS=(
validate_sha256_value() {
local name="$1"
local value="$2"
printf '%s' "$value" | grep -Eq '^[a-f0-9]{64}$' \
grep -Eq '^[a-f0-9]{64}$' <<<"$value" \
|| fail "versions.env: $name must be a 64-char lowercase hex SHA256, got: $value"
}
@@ -70,11 +70,11 @@ load_versions_contract() {
validate_sha256_value BUN_LINUX_X64_BASELINE_SHA256 "$BUN_LINUX_X64_BASELINE_SHA256"
validate_sha256_value NODE_LINUX_X64_SHA256 "$NODE_LINUX_X64_SHA256"
printf '%s' "$HY2XS_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' \
grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' <<<"$HY2XS_VERSION" \
|| fail "versions.env: HY2XS_VERSION must be X.Y.Z, got: $HY2XS_VERSION"
printf '%s' "$HY2XS_RELEASE_LINE" | grep -Eq '^[0-9]+$' \
grep -Eq '^[0-9]+$' <<<"$HY2XS_RELEASE_LINE" \
|| fail "versions.env: HY2XS_RELEASE_LINE must be an integer, got: $HY2XS_RELEASE_LINE"
printf '%s' "$HY2XS_CONFIG_SCHEMA_VERSION" | grep -Eq '^[0-9]+$' \
grep -Eq '^[0-9]+$' <<<"$HY2XS_CONFIG_SCHEMA_VERSION" \
|| fail "versions.env: HY2XS_CONFIG_SCHEMA_VERSION must be an integer"
# HY2XS_TARGET_OS — это дистрибутив (debian), а GOOS/`target_os` в metadata