Add Arch packages and proper Windows installers to the packaging pipeline - #2118
nullPointerEnjoyer wants to merge 1 commit into
Conversation
…line
Arch Linux (.pkg.tar.zst), mirroring the deb/rpm builders:
- packaging/arch/build.sh runs in a pinned archlinux:base container; makepkg
as a dedicated build user repackages the prebuilt release binaries
(PKGBUILD templates, install scriptlet applies the preset policy)
- dependencies resolved from the binaries via pacman -F on the arch-matched
x86_64 leg; the aarch64 leg repackages cross-target (Arch publishes no
arm64 images) with a static fallback map, unstripped binaries and stub man
pages
- namcap gate (keyed on its ' E: ' output: namcap always exits 0) and
fresh-container install smoke tests; arm64 skips the install smoke since
pacman refuses foreign-arch packages
- release_linux.yml builds + uploads both arches; test-local.sh replicates
Windows (NSIS), replacing the GUI-only setup.exe:
- renderable templates (build-tools/win/nsi/*.nsi.in + common.nsh macros)
and create-nsis-installers.ps1 produce two installers: a new node Setup
(all CLI tools, optional PATH entry with length-gated registry rewrite and
backup, optional mainnet service + TCP firewall rule) and an improved GUI
setup (all-users shortcuts, upgrade handling, fixed the broken
\${SMPROGRAMS} constant carried over from the old script)
- smoke-install.ps1 silent-installs, verifies files/registry/PATH/--help and
uninstalls on the CI runner; release_windows.yml gains a workflow_dispatch
dry run and version fallback like the Linux workflow
Shared helpers (packaging/common/lib.sh): the 7-binary list, version
validation (the deb/rpm charset checks rejected any suffixed version - e.g.
1.4.1-rc1 - due to a glob range quirk) and man-page generation, now
single-sourced across the three builders and smoke tests; container image
pins moved to packaging/images.env (also fixes the fedora:latest drift in
test-local.sh); test-local.sh run_step/summary block moved out of the
--skip-build branch where a default (building) run could never reach it.
Checkout hardening: persist-credentials: false and read-only permissions on
the packaging jobs.
|
🔍 OpenCodeReview found 18 issue(s) in this PR.
📄
|
| - name: Smoke test Arch packages | ||
| if: matrix.arch == 'x86_64' |
There was a problem hiding this comment.
Unlike the deb and rpm legs (whose smoke tests run under qemu via --platform linux/arm64 for both matrix archs), the Arch arm64 package is built and uploaded without any install/runtime verification: this smoke step is gated to x86_64 and the smoke-arch.sh arm64 leg never runs. A broken aarch64 payload (wrong binary, missing files, bad .PKGINFO) would ship silently. Consider adding a container-free verification (e.g. extract the .pkg.tar.zst with tar and check binaries/paths/.PKGINFO arch, similar to verify-artifacts.sh) for the aarch64 leg instead of relying only on the builder's self-check.
| .\build-tools\win\smoke-install.ps1 -Installer "Mintlayer_Node_win_${{ steps.get_version.outputs.VERSION }}_Setup.exe" -AppName "Mintlayer Node" -Kind node -Version "${{ steps.get_version.outputs.VERSION }}" | ||
| .\build-tools\win\smoke-install.ps1 -Installer "Mintlayer_Node_GUI_win_${{ steps.get_version.outputs.VERSION }}_Setup.exe" -AppName "Mintlayer Node GUI" -Kind gui -Version "${{ steps.get_version.outputs.VERSION }}" |
There was a problem hiding this comment.
The extracted VERSION is interpolated directly into this pwsh run: block via ${{ steps.get_version.outputs.VERSION }}. On a non-tag trigger the fallback uses git describe output, and a crafted tag/branch name (or ref) could break out of the quoted string and execute arbitrary code before the regex validation inside the .ps1 scripts ever runs. Pass the value through an env: block and reference $env:VERSION instead.
Suggestion:
| .\build-tools\win\smoke-install.ps1 -Installer "Mintlayer_Node_win_${{ steps.get_version.outputs.VERSION }}_Setup.exe" -AppName "Mintlayer Node" -Kind node -Version "${{ steps.get_version.outputs.VERSION }}" | |
| .\build-tools\win\smoke-install.ps1 -Installer "Mintlayer_Node_GUI_win_${{ steps.get_version.outputs.VERSION }}_Setup.exe" -AppName "Mintlayer Node GUI" -Kind gui -Version "${{ steps.get_version.outputs.VERSION }}" | |
| env: | |
| VERSION: ${{ steps.get_version.outputs.VERSION }} | |
| run: | | |
| .\build-tools\win\smoke-install.ps1 -Installer "Mintlayer_Node_win_${VERSION}_Setup.exe" -AppName "Mintlayer Node" -Kind node -Version "${VERSION}" |
| if ($Version -notmatch '^[0-9][0-9A-Za-z.~+-]*$') { | ||
| throw "invalid version '$Version' (expected digits-first X.Y.Z[-suffix])" | ||
| } |
There was a problem hiding this comment.
The Windows version validation is looser than the Linux one in packaging/common/lib.sh (validate_version requires X.Y.Z with an optional -suffix). Here, strings like "1", "1.2" or "1.2.3-rc1-x-y" pass. Since both package families ship from the same tag, keeping a single consistent rule avoids producing a Windows installer filename that the Linux gates would reject (or vice versa). Consider requiring at least two dots, mirroring the X.Y.Z[-suffix] rule.
Suggestion:
| if ($Version -notmatch '^[0-9][0-9A-Za-z.~+-]*$') { | |
| throw "invalid version '$Version' (expected digits-first X.Y.Z[-suffix])" | |
| } | |
| if ($Version -notmatch '^[0-9]+\.[0-9]+\.[0-9]+([-+~][0-9A-Za-z.~+-]*)?$') { | |
| throw "invalid version '$Version' (expected X.Y.Z[-suffix])" | |
| } |
| $InstallDir = Join-Path $env:ProgramFiles (Join-Path "Mintlayer" $AppName) | ||
| $UninstKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Mintlayer $AppName" |
There was a problem hiding this comment.
The smoke test assumes a 64-bit PowerShell: it reads $env:ProgramFiles and HKLM:\SOFTWARE...\Uninstall. The templates install to $PROGRAMFILES64 and write the uninstall key in the native registry view, so under 32-bit PowerShell (e.g. Windows PowerShell x86, or a CI step launched from a 32-bit shell) $InstallDir would resolve to 'Program Files (x86)' and Get-ItemProperty would be redirected to WOW6432Node, causing spurious failures. Add an explicit 64-bit check up front (or use $env:ProgramW6432 and the Sysnative path).
Suggestion:
| $InstallDir = Join-Path $env:ProgramFiles (Join-Path "Mintlayer" $AppName) | |
| $UninstKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Mintlayer $AppName" | |
| if ([Environment]::Is64BitProcess -ne $true) { | |
| throw "run this script under 64-bit PowerShell (installers use $PROGRAMFILES64 and the native HKLM view)" | |
| } | |
| $InstallDir = Join-Path $env:ProgramFiles (Join-Path "Mintlayer" $AppName) | |
| $UninstKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Mintlayer $AppName" |
| echo "$VERSION_FORMAT_ERROR" >&2 | ||
| exit 2 | ||
| fi | ||
| PKGVER="$(printf '%s' "$VERSION" | tr -- '-~' '__')" |
There was a problem hiding this comment.
validate_version permits '' but not '_', so mapping both '-' and '' to '_' makes distinct versions collide on the same pkgver (e.g. 1.4.1-rc1 and 1.4.1rc1 both become 1.4.1_rc1, which pacman treats as the same package version). The rpm builder maps only '-' to '', which is injective — do the same here.
Suggestion:
| PKGVER="$(printf '%s' "$VERSION" | tr -- '-~' '__')" | |
| PKGVER="$(printf '%s' "$VERSION" | tr -- '-' '_')" |
| for binpath in "$BR"/usr/bin/*; do | ||
| file "$binpath" | grep -q "not stripped" && strip --strip-unneeded "$binpath" | ||
| done |
There was a problem hiding this comment.
Under set -e, file ... | grep -q "not stripped" && strip ... aborts the whole build if a binary is already stripped (grep returns 1 and the && list's failure propagates). The deb builder deliberately uses an if wrapper for exactly this reason (see deb/build.sh comment about the "already stripped" match failure tripping errexit). Use the same form here.
Suggestion:
| for binpath in "$BR"/usr/bin/*; do | |
| file "$binpath" | grep -q "not stripped" && strip --strip-unneeded "$binpath" | |
| done | |
| for binpath in "$BR"/usr/bin/*; do | |
| if file "$binpath" | grep -q "not stripped"; then | |
| strip --strip-unneeded "$binpath" | |
| fi | |
| done |
| @@ -71,6 +78,7 @@ fi | |||
| echo "pulling container images..." | |||
| docker pull -q debian:12 >/dev/null | |||
| docker pull -q fedora:latest >/dev/null | |||
There was a problem hiding this comment.
images.env is sourced above and its header claims it is the single source of truth shared with CI, but this script still pulls and runs fedora:latest throughout instead of the pinned $FEDORA_IMAGE. Local rpm builds therefore drift from CI (fedora:44) and the pin provides no reproducibility here. Use "$FEDORA_IMAGE" in the docker pull and all fedora docker run invocations (debian:12 could be similarly pinned or noted as intentionally unpinned).
Suggestion:
| docker pull -q fedora:latest >/dev/null | |
| docker pull -q "$FEDORA_IMAGE" >/dev/null |
Summary
Extends the native packaging pipeline (deb/rpm from #2115) with:
Arch Linux (
.pkg.tar.zst) —packaging/arch/archlinux:basecontainer; makepkg (as a dedicated build user) repackages the prebuilt release binaries from PKGBUILD templates; install scriptlet applies the preset policy (Arch convention: enable, don't start)pacman -Fon the arch-matched x86_64 leg; the aarch64 leg repackages cross-target (Arch publishes no arm64 images) with a static fallback map, unstripped binaries and stub man pages — no qemu neededMintlayer_Node{,_GUI}_linux_<version>_<arch>.pkg.tar.zst—release.yml'sMintlayer*/*glob picks them up unchangedpacman -Udirectly (documented in packaging/README.md)Windows (NSIS) —
build-tools/win/create-nsis-script.ps1with renderable templates (nsi/*.nsi.in+ sharedcommon.nshmacros) and a generator producing two installers:Mintlayer_Node_win_<v>_Setup.exe(new): all CLI tools, optional PATH entry, optional mainnet service (sc.exe) + TCP firewall ruleSetShellVarContext all), upgrade handling, and a fix for the broken${SMPROGRAMS}constant carried over from the old script (Start Menu shortcuts never worked)smoke-install.ps1: silent install → verify files/registry/PATH/--help→ silent uninstall → verify clean, on the CI runnerrelease_windows.yml: gainsworkflow_dispatchdry-run + git-describe version fallback (parity with the Linux workflow)Shared helpers —
packaging/common/lib.sh+packaging/images.envfedora:latestvsfedora:44drift between test-local.sh and CI)Drive-by fixes (found by the review agents + local testing)
1.4.1-rc1) in deb/rpm/arch due to a bash glob range quirk (+-aparsed as a range)E:output (namcap always exits 0, even on errors)run_step/summary block was only defined in the--skip-buildbranch — default (building) runs could never reach it;;residue on removalpersist-credentials: false+ explicit read-only permissions on the packaging jobsTesting
Local end-to-end (docker, real 1.4.x binaries from the deb-container build):
CI plan:
workflow_dispatchdry-runs of both release workflows on this branch will exercise the real matrix (arm64 binaries, Windows silent install) before the 1.4.1 tag.