server-monitor-manager/agents/antigravity/inbox/from-smm-deliverables/Старые задачи/smm-antigravity-task-reproducible-builds-2026-08-07.md
Ochenstarik 23eb3f5233 chore(agents): разбор рабочих папок с диска на 2026-08-18
Задания, отчёты и патчи, лежавшие в 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>
2026-08-18 14:19:54 +07:00

125 lines
10 KiB
Markdown
Raw 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.

# Воспроизводимость сборки: централизованные версии пакетов и lock-файлы
## Часть 1 — сначала исправить PR #14
Не начинать новую ветку, пока не закрыты два дефекта в уже открытом PR #14 (`antigravity/repo-hygiene`). Оба находятся в release-workflow, которые **не запускаются на pull request** — они триггерятся только по тегу и `workflow_dispatch`, поэтому зелёный CI на PR их не покрывает.
### 1.1. `permissions` стоит на уровне шага — это недопустимый ключ
Три места: `linux-release.yml:63`, `linux-release.yml:127`, `windows-release.yml:86`.
```yaml
- name: Attach bootstrap to GitHub Release
uses: softprops/action-gh-release@3bb1273…
permissions: # ← уровень шага
contents: write
with:
```
В схеме GitHub Actions `permissions` существует только на уровне workflow и на уровне job. У шага такого ключа нет. При срабатывании по тегу workflow либо не загрузится с ошибкой `Unexpected value 'permissions'`, либо шаг выполнится с унаследованным `contents: read` и публикация релиза упадёт с 403.
Исправление: перенести `permissions: contents: write` на уровень job. В `linux-release.yml` это оба job — `bootstrap` и `publish`; в `windows-release.yml``package`. Workflow-уровень оставить `contents: read`.
Job-уровень — самая мелкая гранулярность, которую даёт GitHub; более узко не бывает.
### 1.2. SBOM генерируется и выбрасывается
Три места: `linux-release.yml:57`, `linux-release.yml:111`, `windows-release.yml:67`.
Файл SBOM не попадает ни в `path:` шага `upload-artifact`, ни в `files:` шага `action-gh-release`. То есть он создаётся и остаётся в рабочем каталоге runner'а. Требование задания «приложить к артефактам релиза» не выполнено.
Сопутствующее:
- `|| true` гасит любую ошибку генерации: сломанный шаг выглядит зелёным, а SBOM молча отсутствует. Для артефакта цепочки поставки это обесценивает саму затею — убрать;
- в job `bootstrap` файла `linux-release.yml` нет шага `setup-dotnet`, а SBOM пишется в подкаталог `sbom/`, тогда как остальные пути в этом job — корневые;
- SBOM в job `bootstrap` и в job `publish` строится из одного и того же `ServerMonitorManager.slnx`, то есть дублируется.
Исправление: генерировать SBOM один раз, до шага загрузки, в job, где уже настроен .NET; добавить файл и в `upload-artifact`, и в `files:` релиза; `|| true` убрать. Дублирующую генерацию в job `bootstrap` удалить.
### 1.3. Как проверить себя
Release-workflow нельзя прогнать через PR. Проверять так:
- `actionlint` на все пять файлов `.github/workflows/` — он ловит и недопустимые ключи, и опечатки в схеме;
- либо `gh workflow run` вручную по `workflow_dispatch` на своей ветке, если это не приведёт к публикации релиза (шаги релиза защищены `if: startsWith(github.ref, 'refs/tags/')`, поэтому на ветке они пропускаются, а разбор файла всё равно произойдёт).
В отчёте показать вывод проверки. Утверждение «исправлено» без демонстрации разбора файла не принимается — именно отсутствие такой проверки и привело к дефекту.
---
## Часть 2 — новая задача
### Репозиторий и ветка
- Репозиторий: https://github.com/ochenstarik-ui/server-monitor-manager
- База: `main` (после merge PR #13 и #14)
- Ветка: `antigravity/reproducible-builds`
- Рабочая папка: `C:\Users\Ochenstarik\projects\smm-antigravity`
### Зачем
`docs/installer-contract.md` §1 требует, чтобы production-установка использовала закреплённый релиз, а `docs/product-horizons.md`, Горизонт 0, требует подписанной поставки с хэшами всех артефактов. Обе гарантии опираются на предположение, что из одного коммита получается один и тот же бинарник.
Сейчас это неверно: версии NuGet-пакетов заданы в каждом `.csproj` по отдельности, lock-файлов нет, восстановление зависимостей идёт по диапазонам. Сборка одного и того же тега завтра может дать другой набор зависимостей, и никакая подпись артефакта этого не покажет.
Задача закрывает предпосылку, без которой подписанная поставка не имеет смысла.
### Работы
**1. `Directory.Packages.props` в корне.**
Централизованное управление версиями: `ManagePackageVersionsCentrally` включено, все `PackageVersion` собраны в одном файле, из `.csproj` версии убраны, остаются только `PackageReference` без атрибута `Version`.
Затрагиваются все проекты решения: `Core`, `Control`, `Agent`, `Desktop`, `Provisioning.Helper`, тестовый проект.
**2. Lock-файлы.**
`RestorePackagesWithLockFile` включён, `packages.lock.json` каждого проекта закоммичен. В CI восстановление выполняется с `--locked-mode`, чтобы расхождение lock-файла с проектом ломало сборку, а не молча подтягивало другую версию.
**3. `Directory.Build.props` в корне.**
- `Nullable`, `EnableNETAnalyzers`, `AnalysisLevel latest-recommended`;
- `InvariantGlobalization` там, где это уместно для серверных проектов;
- детерминированная сборка: `Deterministic`, `ContinuousIntegrationBuild` под условием `$(CI)`;
- `TreatWarningsAsErrors` **не включать** — см. границы.
**4. CI.**
В `linux-control-agent.yml` и `windows-build.yml` добавить восстановление в locked-режиме. Прогон должен падать, если lock-файл не соответствует проектам.
### Границы
Не изменять:
- `src/ServerMonitorManager.Control/LinkService.cs`, `LinkPolicyApplier.cs`, `LinkReconciliationBackgroundService.cs`, `ControlStore.cs`, `ControlMaintenance.cs`, `ControlOptions.cs`, `appsettings.json`;
- `src/ServerMonitorManager.Provisioning.Helper/**`, `deploy/**`;
- `CertificateAuthority.cs`, `CertificateLifecycleService.cs`, `src/ServerMonitorManager.Agent/AgentClient.cs`;
- содержимое файлов в `tests/**` — правки допускаются только в `.csproj` тестового проекта.
Первые две группы заняты заданием B-3R, третья — заданием по жизненному циклу сертификатов.
Не входит в задание:
- **`TreatWarningsAsErrors`.** Включение сейчас сломает незавершённую ветку `hermes/task3-b3-fact-reconciliation` при её ребейзе на main. Отдельная задача после её merge;
- разделение тестов на `Core.Tests` / `Control.Tests` / `Agent.Tests` / `Helper.Tests` — тестовые файлы заняты;
- обновление версий пакетов: задача переносит существующие версии как есть, а не апгрейдит их. Любое изменение номера версии должно быть отдельно обосновано в отчёте;
- merge собственного PR.
### Критерий приёмки
- ни один `.csproj` не содержит `Version=` в `PackageReference`;
- `packages.lock.json` закоммичены для всех проектов;
- CI восстанавливает зависимости в `--locked-mode` и падает при рассинхроне — продемонстрировать намеренной поломкой lock-файла в отдельном временном коммите, показать красный прогон, затем откатить;
- номера версий пакетов не изменились относительно `main` — показать сравнение;
- `git diff --name-only main` не содержит ни одного файла из списка границ;
- Control suite прогнан на Linux;
- Desktop собирается — в CI, локально WinUI 3 собрать нельзя, если нет Windows App SDK;
- CI зелёный, PR создан и не смержен.
### Отчётность
Раздельно: что проверено локально, что в CI со ссылками на прогоны, что не проверялось и почему.
Отдельно показать: вывод `actionlint` по части 1 и сравнение версий пакетов до и после по части 2.
Физический acceptance (`SMM_ACCEPT_RESTORE=1 SMM_ACCEPT_REBOOT=1 tests/acceptance/three-server-mesh.sh`) выполнить нельзя — не выданы SSH- и topology-параметры.