Test Details Overview

Rework the release pipeline and attest what it publishes (#5249)

* Remove the CI scripts nothing runs anymore

The release pipeline has accumulated scripts with no caller: the RPM
build and signing tools from before RPM builds were switched off, the
GitLab configuration, the nano-env image builders that the test
workflows stopped using when they moved to ci/prepare, the Windows
test wrappers superseded by ci/build.sh, the previous generation of the
tag generator and the macOS dependency installer. None of them is
referenced by a workflow, a Dockerfile or another script.

* Name package files after the build tag

CPack named packages after the CMake version, nano-node-29.0.0-Linux,
and the deploy scripts renamed each one to the published name on
upload. Setting CPACK_PACKAGE_FILE_NAME from the tag gives every
package its published name as soon as it is built, which is also the
name an attestation will record for it. The Windows build gets ZIP
added to its CPack generators so one cpack run produces both the
installer and the archive.

* Build release packages through ci/build.sh

Each platform had its own way of configuring and building the release
packages: a bash script with a hard-coded Qt path for Linux and macOS,
and a PowerShell wrapper around two batch files for Windows, none of
them sharing anything with the ci/build.sh the test workflows use.
ci/build-packages.sh now drives ci/build.sh for all three, runs cpack
and collects the packages in packages/ under their published names.

ci/build.sh passes the build type to cmake --build so the Visual Studio
generator builds the requested configuration instead of always Debug,
and CMakeLists.txt keeps every configuration's binaries in the build
root, where the test scripts look for them.

The Windows build step never received NETWORK or CI_TAG, so its beta
packages were live-network builds reporting a development version;
both are passed now. The commented-out Authenticode signing script and
its secrets go, as does the SIMD flag, which has no effect on MSVC.

* Upload packages with one script

deploy.sh and deploy.ps1 did the same job in two languages: hash each
package, write the hash beside it and copy both to the download bucket.
ci/deploy/upload.sh does it for every platform from the packages/
directory, which already holds the published names, so the per-platform
globs and the renaming on upload are gone, together with the RPM branch
that has had no caller since RPM builds were switched off.

The .sha256 files now contain the bare file name. The Linux ones used
to embed the runner's absolute build path, which made them useless to
sha256sum -c.

* Rewrite the Docker image build and push

The image went through a 170-line library sourced by five one-line
wrappers, with the registry names, the nightly suffix, the tag list and
the login spread across it, plus a scan of every local image to decide
what to push. Two scripts replace it: docker-build.sh builds the image
once and names it for the registries, docker-push.sh tags and pushes
one repository and reports the digest it got, which the next step needs
for attestation. The workflow logs in with docker/login-action and
spells out each registry's tags, including that only beta gets a latest
tag on Docker Hub. Whether a live build is a nightly is now read off
the tag instead of a separate input.

The build no longer pulls the previous image as a layer cache; with a
multi-stage Dockerfile that cache held only the final stage and saved
nothing of the compile.

* Rewrite the tag generator

generate_next_git_tag.sh grew its options, globals and output modes
over several rounds and was hard to reason about: it matched tags with
an unescaped dot, force-moved tags and force-pushed the release branch,
and wrote its results to GITHUB_ENV for the workflow to copy into
outputs. ci/deploy/next-tag.sh keeps the scheme (DB tags on develop,
RC tags on the release branch, plain release tags on request, versions
committed into CMakeLists.txt and the release commit pushed to its
branch) in a third of the lines, with a --dry-run that prints the tag
it would create. Pushes are no longer forced, so a collision fails
instead of moving a published tag, and the outputs go straight to
GITHUB_OUTPUT.

The workflow checks out the full history for it: deciding whether the
latest tag already covers HEAD needs the commits between them.

* Run Build & Deploy on the tag it builds

Build & Deploy used to create the tag in its first job and have the
build jobs check that tag out, so a run's own commit was the branch
head it started from while the packages came from the version commit
one step ahead. Anything that records the run's commit, including the
attestations the next change adds, would have named the wrong one.

Tagging moves to its own workflow, Tag Build, which keeps the schedule
and the manual trigger, creates the tag and then starts Build & Deploy
on it with gh workflow run, the one way a GITHUB_TOKEN may start a
workflow. Build & Deploy now runs on a tag ref, checks out that ref as
any workflow does and takes the tag name from it, so it can also be
started by hand on an existing tag to rebuild it. A first job refuses
to run on anything but a build tag.

The upload steps run only when the bucket credentials are present,
which lets a fork build and verify packages without them.

* Attest release packages and images

Every job that publishes something now asks GitHub Actions to attest
it: actions/attest signs the digests of the packages in packages/ and
of each pushed image under the workflow's OIDC identity, stores the
attestation with the repository and, for images, in the registry next
to the image. A consumer can then check that a download was built by
this workflow from the commit it names, which the .sha256 files beside
the packages cannot show since they come from the same job.

The jobs get the id-token and attestations permissions this needs, and
the package jobs publish the attestation bundle next to the packages
so it can be verified without the GitHub API.

* Describe the release pipeline

A short page under ci/deploy for whoever next has to touch a release:
how a tag comes about, what Build & Deploy publishes where, and the
commands a user runs to verify a download against its attestation.

* Keep packages as workflow artifacts

The packages only ever left the runner through the bucket upload, so a
run without the bucket secrets, which is every run on a fork, lost what
it built. The package jobs now attach them to the run as well, which
keeps every build inspectable and lets a fork verify the attestation of
what it built.

* Rewrite Prepare Release and describe the whole release process

Prepare Release cuts the release branch and moves develop on to the
next major. The job did it in six inline steps: it fetched the default
branch name over the REST API, bumped the major on a timestamped branch,
opened the pull request, hard-reset its checkout and only then created
the release branch, from the default branch whatever ref it had been
started on, with no permissions block and a typo in a step name.

ci/deploy/prepare-release.sh does the same work in the order a reader
expects, refuses to run on anything but the default branch or when that
branch is not at <major>.0, and takes --dry-run like the tag generator.
It shares the version helpers with next-tag.sh through common.sh and
names the pull request's repository explicitly, so a fork never opens
one against the upstream repository.

The README now opens with the release process itself: how development
builds come about, the steps and the order for a release, point
releases, rebuilding a tag, and where the workflows stop.

* Let a failed network build finish the other one

The package and Docker jobs build beta and live as one matrix with
GitHub's default fail-fast, so a failure in one network cancelled the
other network's build of the same platform and the run published less
of the tag than it could have. With fail-fast off every build runs to
its own result, and the run shows exactly which outputs were published.

* Rewrite the release pipeline README as a reference

The page told the release as a story: the tag grammar was spread over
three paragraphs, the bucket and the registries were used before they
were named, workflow names changed form from one mention to the next,
and the notes a maintainer needs sat as asides inside procedure steps.
It was also hard-wrapped at a column.

It now defines its terms first, gives the tag kinds and the rules the
tag script applies in one place, lists what Build & Deploy publishes
where with the exact file and image names, describes each workflow and
script with its inputs and outputs, and keeps the release procedure,
repository configuration, local dry runs and verification as sections
of their own.

* Build packages without debug information

Beta packages were RelWithDebInfo builds. On Linux the debug
information goes into the binaries themselves, so each beta package
weighed half a gigabyte against 25 MB for live. macOS and Windows keep
their debug information outside the packaged files, so nothing shipped
there changes.

Packages of both networks now build as Release. The symbol table
stays, so stack traces in the log keep their function names. The
Docker images are unchanged and keep their debug information.

* Push a release's tag and branch update together

A release pushed its tag first and the version commit to its branch
second. When the branch push was rejected, by a protection rule or a
push that got in between, the tag stayed published while
releases/v<major> was left behind, and a rerun saw HEAD covered by that
tag and created nothing, so the branch never caught up on its own.

The two refs now go out in one atomic push: either both land or neither
does, and a rerun starts from an origin that is as it was. Pre-release
runs still push only their tag.

__________

Type: commit

Hash: 429f7dc608f2b3bdeb37ccb71fdd406b5b963104

Created: yesterday

__________

gr0v1ty/nano-node:429f7dc608f2b3bdeb37ccb71fdd406b5b963104

Test Results

Test Case Status Duration Median Deviation Log Graph
No test results available yet. Check the GitHub test run for job status and logs.