[client] Fix RPM metadata for Red Hat certification (#7614)

Goreleaser's RPM build is split into one nfpm entry per architecture, each pinned to a single-arch build, with the version substituted from the release job. The deb package, archives, and container images are unaffected.

Also fixes rpmlint: incoherent-version-in-changelog, found while investigating: nfpm writes the changelog title straight from semver and never appends the release, so entries read 0.79.0 against a 0.79.0-1 package.
This commit is contained in:
Misha Bragin
2026-09-24 11:06:16 +02:00
committed by GitHub
parent 4c19226342
commit 507415f870
5 changed files with 153 additions and 7 deletions
+9 -2
View File
@@ -191,6 +191,9 @@ jobs:
# requires a changelog. Generated, not committed (see .gitignore).
# chglog is a go.mod tool directive, so go.sum pins it and its deps.
run: bash release_files/rpm-changelog.sh
- name: Fill the RPM ISA provide version
# nfpm cannot emit rpmbuild's ISA provide and GoReleaser cannot template it.
run: bash release_files/rpm-provides.sh
- name: Set up QEMU
uses: docker/setup-qemu-action@06116385d9baf250c9f4dcb4858b16962ea869c3 #v4.1.0
- name: Set up Docker Buildx
@@ -230,14 +233,18 @@ jobs:
uses: goreleaser/goreleaser-action@5daf1e915a5f0af01ddbcd89a43b8061ff4f1a89 # v7.2.2
with:
version: ${{ env.GORELEASER_VER }}
args: release --clean ${{ env.flags }}
args: release --config .goreleaser.generated.yaml --clean ${{ env.flags }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }}
GPG_RPM_KEY_FILE: ${{ env.GPG_RPM_KEY_FILE }}
NFPM_NETBIRD_RPM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
# One per nfpm id: GoReleaser looks the passphrase up as NFPM_<ID>_PASSPHRASE.
NFPM_NETBIRD_RPM_AMD64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_ARM64_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_ARM_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
NFPM_NETBIRD_RPM_386_PASSPHRASE: ${{ secrets.GPG_RPM_PASSPHRASE }}
SKIP_PUBLISH: ${{ env.SKIP_PUBLISH }}
SKIP_DOCKER_PUSH: ${{ env.SKIP_DOCKER_PUSH }}
- name: Verify RPM signatures
+3
View File
@@ -38,4 +38,7 @@ management/server/types/testdata/
# generated by chglog in the release workflow, embedded into the RPM
changelog.yml
# generated by rpm-provides.sh, the config GoReleaser actually runs
.goreleaser.generated.yaml
.chglog.yml
+60 -5
View File
@@ -40,6 +40,32 @@ builds:
tags:
- load_wgnt_from_rsrc
# Single-arch builds: nfpm provides is not templated, so the RPM splits per arch.
- &netbird_rpm_build
id: netbird-rpm-amd64
dir: client
binary: netbird
env: [CGO_ENABLED=0]
goos: [linux]
goarch: [amd64]
ldflags:
- -s -w -X github.com/netbirdio/netbird/version.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser
mod_timestamp: "{{ .CommitTimestamp }}"
tags:
- load_wgnt_from_rsrc
- <<: *netbird_rpm_build
id: netbird-rpm-arm64
goarch: [arm64]
- <<: *netbird_rpm_build
id: netbird-rpm-arm
goarch: [arm]
- <<: *netbird_rpm_build
id: netbird-rpm-386
goarch: [386]
- id: netbird-static
dir: client
binary: netbird
@@ -223,17 +249,22 @@ nfpms:
postinstall: "release_files/post_install.sh"
preremove: "release_files/pre_remove.sh"
- maintainer: Netbird <dev@netbird.io>
- &netbird_rpm
maintainer: Netbird <dev@netbird.io>
description: Netbird client.
homepage: https://netbird.io/
license: BSD-3-Clause
vendor: NetBird
id: netbird_rpm
id: netbird_rpm_amd64
bindir: /usr/bin
builds:
- netbird
ids:
- netbird-rpm-amd64
formats:
- rpm
# Red Hat certification (RPM Version Handling) requires rpmbuild's ISA
# provide, which nfpm does not emit. The version is filled in by the release job.
provides:
- "netbird(x86-64) = @RPM_EVR@"
# The client verifies TLS to management and signal against the system trust
# store. Red Hat software certification (RPM Dependency Tracking) also
# rejects packages that declare no dependencies at all.
@@ -263,6 +294,27 @@ nfpms:
packager: NetBird <dev@netbird.io>
signature:
key_file: '{{ if index .Env "GPG_RPM_KEY_FILE" }}{{ .Env.GPG_RPM_KEY_FILE }}{{ end }}'
- <<: *netbird_rpm
id: netbird_rpm_arm64
ids:
- netbird-rpm-arm64
provides:
- "netbird(aarch-64) = @RPM_EVR@"
- <<: *netbird_rpm
id: netbird_rpm_arm
ids:
- netbird-rpm-arm
provides:
- "netbird(armv6hl-32) = @RPM_EVR@"
- <<: *netbird_rpm
id: netbird_rpm_386
ids:
- netbird-rpm-386
provides:
- "netbird(x86-32) = @RPM_EVR@"
dockers_v2:
- id: netbird
disable: "{{ .Env.SKIP_DOCKER_PUSH }}"
@@ -513,7 +565,10 @@ uploads:
- name: yum
skip: "{{ .Env.SKIP_PUBLISH }}"
ids:
- netbird_rpm
- netbird_rpm_amd64
- netbird_rpm_arm64
- netbird_rpm_arm
- netbird_rpm_386
mode: archive
target: https://pkgs.wiretrustee.com/yum/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
username: dev@wiretrustee.com
+35
View File
@@ -7,6 +7,12 @@
# template headings, review checklists, HTML comments and Co-authored-by
# trailers. None of that belongs in a package on Red Hat's catalog, and it is
# most of the changelog's size. Keep the subject line and drop the rest.
#
# chglog also records the bare tag as each entry's version, while nfpm writes
# that string into the changelog header verbatim and never appends the release.
# rpmlint then reports incoherent-version-in-changelog, because the entry reads
# 0.79.0 while the package is 0.79.0-1. Rewrite each version the way nfpm
# renders the package EVR.
set -eu
@@ -20,14 +26,29 @@ path = sys.argv[1]
lines = open(path, encoding="utf-8").read().split("\n")
NOTE = re.compile(r"^ note: (.*)$")
SEMVER = re.compile(r"^- semver: (.*)$")
BLOCK = {"|", "|-", "|+", ">", ">-", ">+"}
# nfpm defaults the RPM release to 1 and the packaging sets no other value.
RELEASE = "1"
def quote(text):
"""Render text as a YAML single-quoted scalar."""
return " note: '{}'".format(text.replace("'", "''"))
def evr(version):
"""Render a semver tag the way nfpm renders the package EVR."""
version, _, metadata = version.partition("+")
core, _, prerelease = version.partition("-")
if prerelease:
core += "~" + prerelease.replace("-", "_")
if metadata:
core += "+" + metadata
return "{}-{}".format(core, RELEASE)
def first_line_of_double_quoted(value):
"""Text of a double-quoted scalar up to its first \\n escape."""
out = []
@@ -52,6 +73,13 @@ seen = 0
i = 0
while i < len(lines):
line = lines[i]
m = SEMVER.match(line)
if m:
out.append("- semver: '{}'".format(evr(m.group(1))))
i += 1
continue
m = NOTE.match(line)
if not m:
out.append(line)
@@ -107,4 +135,11 @@ if grep -nE '^ note: ".*\\n' changelog.yml; then
exit 1
fi
# Every entry must carry the release, or rpmlint reports the changelog version
# as incoherent with the package again.
if grep -nE "^- semver: " changelog.yml | grep -vE -- "-[0-9]+'$"; then
echo "changelog entries without the RPM release survived the rewrite" >&2
exit 1
fi
test -s changelog.yml
+46
View File
@@ -0,0 +1,46 @@
#!/bin/sh
#
# Write .goreleaser.generated.yaml with the @RPM_EVR@ placeholder filled in.
#
# Red Hat certification (RPM Version Handling) expects rpmbuild's ISA provide,
# netbird(x86-64) = <evr>. nfpm does not emit it and GoReleaser does not template
# the provides field, so the version is substituted before GoReleaser runs.
#
# The value has to match what nfpm derives from the same tag: a semver
# prerelease becomes a tilde suffix, and the release defaults to 1.
set -eu
OUT=.goreleaser.generated.yaml
TAG="${GITHUB_REF#refs/tags/}"
case "$TAG" in
v*) ;;
*) TAG=$(git describe --tags --abbrev=0) ;;
esac
EVR=$(python3 - "$TAG" <<'PYEOF'
import sys
version = sys.argv[1].lstrip("v")
version, _, metadata = version.partition("+")
core, _, prerelease = version.partition("-")
if prerelease:
core += "~" + prerelease.replace("-", "_")
if metadata:
core += "+" + metadata
print("{}-1".format(core))
PYEOF
)
# Written to a separate, ignored file: GoReleaser refuses to release from a
# dirty tree, so .goreleaser.yaml itself must stay untouched.
sed "s/@RPM_EVR@/${EVR}/g" .goreleaser.yaml > "$OUT"
# A surviving placeholder means the provides entries moved or were renamed.
if grep -n "@RPM_EVR@" "$OUT"; then
echo "unsubstituted @RPM_EVR@ left in $OUT" >&2
exit 1
fi
echo "rpm provides version: ${EVR} -> ${OUT}"