Задания, отчёты и патчи, лежавшие в C:\Users\Ochenstarik\projects и в домашней папке, перенесены в agents/. Разложено по агентам там, где имя файла позволяло определить автора; остальное — в _salvage-2026-08-18/ и разбирается вручную. Патчи в notes/salvage-2026-08-18/ — незакоммиченная работа из брошенных рабочих копий: она существовала только на диске. Тяжёлое (релизные архивы, инсталляторы, наборы данных) в репозиторий не попало: оно лежит рядом, в Agent_projects/_archive и Agent_projects/_data. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17 KiB
Codex: cosign в поставке и работающий автозапуск проверки релиза → v0.1.0-alpha.15
Задание самодостаточно: истории работы по этому репозиторию у вас нет, всё нужное ниже.
Репозиторий
- https://github.com/ochenstarik-ui/server-monitor-manager
- База:
main@0405b0b(merge PR #42) - Ветка:
codex/cosign-provisioning
Server Monitor Manager — Windows-клиент, ASP.NET Core Control Hub, Linux-агент и WireGuard-mesh с политиками nftables. На серверы ставится bash-скриптом deploy/ochenstarik-server-monitor-manager.sh (bootstrap); deploy/smm-setup.sh — обёртка, скачивающая релизные ассеты и дающая команды install-hub и install-node.
Правила репозитория
mainзащищён: PR обязателен, обязательны статусыbuild-and-testиbuild, force-push запрещён;- один PR — одна тема;
- описание PR заполняется после завершения CI, со ссылками на конкретные прогоны;
- отсутствие проверки не является дефектом отчёта; утверждение о проверке, противоречащее статусу CI, — является;
docs/release-policy.mdзапрещает двигать опубликованные теги и заменять ассеты: исправление выпускается следующей версией;.github/workflows/linux-release.yml— единственный публикатор релизов.
Что произошло
v0.1.0-alpha.14 выпущен и содержит полный набор из 17 ассетов, включая server-monitor-manager-manifest.pem. Это первый релиз, подпись которого проверяема.
Release Verification против него упал, и это ровно тот результат, ради которого workflow писался. Он нашёл два независимых дефекта.
Дефект 1 — cosign не поставляется, установка на чистый сервер невозможна
Прогон 31894428693, шаг Run Positive Installation:
ochenstarik-server-monitor-manager.sh: OK
[ochenstarik-server-monitor-manager] Supported platform: ubuntu 24.04, x86_64
[ochenstarik-server-monitor-manager] ERROR: Required command is missing: cosign
verify_manifest в bootstrap (deploy/ochenstarik-server-monitor-manager.sh:298) вызывает require_command cosign. При этом:
cosignне входит в стандартные репозитории Ubuntu;install_dependenciesставит толькоwireguard-tools nftables iproute2;smm-setup.shне упоминает cosign вообще;docs/linux-bootstrap.mdобъясняет, зачем нужен сертификат, но нигде не говорит, откуда взять cosign.
Следствие: install-hub на чистой Ubuntu скачивает все файлы, доходит до проверки подписи и умирает. Владелец проекта не может поставить систему на свои серверы — при том, что установка «одной командой» и была смыслом PR #42.
Дополнительно, в CI отказ произошёл по смежной причине, которую тоже надо устранить: шаг Setup cosign (sigstore/cosign-installer) кладёт бинарь в каталог, который добавляется в PATH через GITHUB_PATH, а тест вызывает bootstrap через sudo, и secure_path в /etc/sudoers эту запись отбрасывает. То есть даже установленный на runner'е cosign невидим для проверяемого кода.
Дефект 2 — Release Verification никогда не запускается сам
.github/workflows/release-verification.yml объявлен с on: release: types: [published]. Релиз создаёт linux-release.yml под GITHUB_TOKEN, а события, порождённые этим токеном, по правилам GitHub не запускают другие workflow — защита от рекурсии. Прогон по alpha.14 пришлось запускать вручную через workflow_dispatch.
Механизм выглядит настроенным и не может сработать ни разу. Пункт «Release Verification отработал автоматически» в приёмке предыдущего задания был недостижим в принципе — это дефект задания, не исполнителя.
Часть 1 — обеспечить cosign
Требование: оператор на чистой Ubuntu выполняет одну команду и получает установленную систему с проверенной подписью. Ни ручной установки cosign, ни SMM_ALLOW_UNSIGNED.
Реализовать провижининг cosign в поставке:
- закреплённая версия и закреплённая контрольная сумма на каждую архитектуру, обе константами в скрипте, а не вычисляемые на лету;
- скачивание бинаря публичным
curlсhttps://github.com/sigstore/cosign/releases/download/<version>/cosign-linux-<amd64|arm64>; - сверка sha256 с закреплённой константой до запуска бинаря; несовпадение — отказ;
- установка в
/usr/local/bin/cosignрежимом0755(каталог входит вsecure_path, поэтому cosign станет виден и подsudo); - если пригодный
cosignуже вPATH— не трогать существующий, но проверить, что он запускается; - версия и её контрольные суммы записываются в
docs/linux-bootstrap.md, чтобы обновление было осознанным действием, а не молчаливым дрейфом.
Где размещать вызов — ваше решение, но оно должно закрывать оба пути: короткий (install-hub / install-node в smm-setup.sh) и сквозной (preflight / verify-release в bootstrap). Второй используется в tests/acceptance/three-server-mesh.sh.
Отдельно предусмотреть отказ с внятным текстом, если скачать cosign невозможно (нет сети, недоступен github). Сообщение должно называть версию, ожидаемую сумму и путь установки — оператору должно хватить его, чтобы поставить cosign вручную.
Часть 2 — сделать проверку честной
Удалить шаг Setup cosign из .github/workflows/release-verification.yml.
Пока cosign даёт runner, тест проверяет окружение GitHub, а не поставку. После удаления шага Run Positive Installation проходит только если cosign обеспечивает сам установщик — то есть ровно в том случае, когда пройдёт и установка у оператора.
Убедиться, что негативные проверки подписи (run-negative-tests.sh) остаются работоспособны и продолжают отвергать подделанные manifest, подпись и сертификат.
Часть 3 — починить автозапуск
Добиться того, чтобы публикация тега давала результат проверки без действий человека. Два пригодных пути:
- перевести
release-verification.ymlнаon: workflow_runпо завершенииRelease pipelineс фильтром по успешному завершению и по тегу —workflow_runсрабатывает на завершение другого workflow и ограничениемGITHUB_TOKENне блокируется; - либо вынести проверку в отдельный job внутри
linux-release.yml, зависящий от публикации.
Первый путь сохраняет разделение и оставляет workflow_dispatch для ручного перепрогона; второй проще, но смешивает выпуск и проверку в одном workflow. Выберите один и обоснуйте выбор в отчёте.
workflow_dispatch с параметром tag сохранить в любом случае — им перепроверяют старые релизы.
Часть 4 — выпустить v0.1.0-alpha.15
- До тегирования прогнать
Release pipelineчерезworkflow_dispatchна своей ветке. Шаги публикации защищеныif: startsWith(github.ref, 'refs/tags/')и пропустятся, но сборка и подпись выполнятся. Пропуск этого шага уже сжёг два номера (alpha.10,alpha.11). - Создать и запушить тег обычным
git push— не черезgh release create: релиз создаёт сам workflow по событиюpush: tags: v*. - Убедиться, что
Release Verificationзапустился сам и зелёный. Это главный результат задания. - Тег не двигать ни при каких обстоятельствах.
Часть 5 — эргономика install-hub и install-node
Найдено живой установкой на Ubuntu 24.04, обе вещи стоили оператору прерванных попыток.
Аргументы проверяются после скачивания. Вызов install-hub ВАШ-ХОСТ 178.212.13.102 — плейсхолдер вместо адреса, IP на месте порта — прошёл проверку арности, после чего скрипт скачал 24 МБ и только потом дошёл бы до разбора значений. Валидация PUBLIC_HOST, HTTPS_PORT и WG_PORT должна выполняться до первого сетевого запроса. Отдельно отвергать очевидный плейсхолдер: значение, не являющееся ни IPv4-литералом, ни синтаксически годным DNS-именем.
Скачивание идёт молча. curl -fsSL на 24 МБ не печатает ничего, и оператор дважды принимал это за зависание и жал Ctrl+C. Показывать индикатор и имя файла: curl -fL --progress-bar -o <имя>. То же относится к любому крупному файлу, который скрипт тянет сам.
Имя install-node перекрыто. У обёртки есть своя команда install-node без аргументов, а у bootstrap — одноимённая, принимающая путь к архиву. Оператор, скачавший файлы заранее, получает install-node takes no arguments и не имеет способа догадаться, что нужен разделитель --. Либо принимать необязательный путь к архиву и, если он задан, пропускать скачивание, либо в тексте отказа прямо называть обходной путь: smm-setup.sh -- install-node ARCHIVE. Первое лучше: скачивание заново — это ещё 24 МБ поверх уже имеющихся.
Проверка подписи виснет молча и без таймаута. verify_manifest вызывает cosign verify-blob ... >/dev/null 2>&1. При медленной или частично недоступной сети cosign уходит к службам sigstore и не возвращается, а оператор видит только строку Verifying manifest signature... и не имеет ни малейшего указания, что происходит. Наблюдалось на живой машине. Требуется: не глушить вывод cosign (или сохранять его в лог и печатать при отказе), обернуть вызов в timeout с внятным сообщением по истечении, и в тексте отказа прямо называть службы, к которым нужен доступ. Отдельно задокументировать в docs/linux-bootstrap.md, что проверка подписи требует исходящего доступа к sigstore — сейчас об этом не сказано нигде, и оператор в закрытом контуре узнает это зависанием.
mesh-status печатает сырой Unix-time. Колонка HANDSHAKE показывает 1786843345. Оператор смотрит в неё ровно затем, чтобы понять, свежий ли handshake, и обязан считать это в уме. Выводить относительное время (12s ago, 3m ago) либо never, если рукопожатия не было.
Покрыть контрактным тестом: неверный порт и плейсхолдер в PUBLIC_HOST отвергаются без обращения в сеть; install-node с путём к архиву не приводит к сообщению об аргументах.
Часть 6 — записать судьбу alpha.14
В docs/release-policy.md:
v0.1.0-alpha.14— первый релиз с полным набором подписи, но установка из него на чистый хост невозможна: cosign не поставляется. Проверяем, не устанавливаем;v0.1.0-alpha.15— первый релиз, устанавливаемый на чистый хост.
Границы
Antigravity ведёт проверку подписи на стороне Desktop. Не трогать: src/ServerMonitorManager.Desktop/**, tests/ServerMonitorManager.Desktop.Security.Tests/**, .github/workflows/windows-build.yml.
Ваша область: deploy/**, .github/workflows/linux-release.yml, .github/workflows/release-verification.yml, tests/release-verification/**, tests/bootstrap/**, docs/linux-bootstrap.md, docs/release-policy.md.
Критерий приёмки
- cosign обеспечивается поставкой; закреплены версия и контрольные суммы обеих архитектур;
- подделанная контрольная сумма cosign даёт отказ — покрыто тестом;
- шаг
Setup cosignизrelease-verification.ymlудалён; Release Verificationпоv0.1.0-alpha.15запустился по событию, безworkflow_dispatch, и зелёный; ссылка на прогон в отчёте;workflow_dispatchс параметромtagпродолжает работать; ссылка на прогон по произвольному тегу;install-hubиinstall-nodeдоводят установку до конца на хосте без cosign;- неверные аргументы отвергаются до первого сетевого запроса; крупные загрузки показывают индикатор;
SMM_ALLOW_UNSIGNEDне используется ни в одном новом пути и остаётся тем, чем был — аварийным флагом;workflow_dispatch-прогонRelease pipelineвыполнен до тегирования, ссылка в отчёте;- судьба
alpha.14записана вdocs/release-policy.md; - всё через PR, CI зелёный, PR не смержен до зелёного.
Отчёт
Раздельно: что проверено локально, что в CI со ссылками на прогоны, что не проверялось и почему.
Физическая приёмка на реальных серверах в задание не входит — её выполняет владелец после выпуска релиза.