Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 53 additions & 39 deletions .github/scripts/check-release-version.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
#!/usr/bin/env python3
"""Enforce the release-version invariant for Bluefin Server.

project.conf declares:
The two release version axes are each declared in exactly one place:

variables:
release-version: "X.Y.Z" # must match the FSDK point release
project.conf installer-version: "X.Y.Z" # FSDK point release
include/flatcar.yml flatcar-version: "X.Y.Z" # Flatcar LTS release

That value names every published *OS* release asset
(`bluefin-server-ddi-<v>.raw.zst`, `bluefin-server-<v>.efi`,
`bluefin-server-installer-<v>.raw.zst`) and is the version
systemd-sysupdate extracts from those filenames via `@v`.
The installer-version axis names the offline installer disk image and PXE boot
inputs (bluefin-server-installer-<v>.raw.zst, bluefin-server-pxe-*), which
compose their userspace from freedesktop-sdk.

The k0s sysext is deliberately *not* on this axis: it is an
independently-pinned third-party payload versioned from `include/k0s.yml`
and enforced separately by `.github/scripts/check-k0s-version.py`.
The flatcar-version axis names the OS payload release assets
(bluefin-server-ddi-<v>.raw.zst, bluefin-server-<v>.efi) and is the version
systemd-sysupdate extracts from those filenames via `@v`. project.conf pulls
include/flatcar.yml in via its `(@)` list, so %{flatcar-version} resolves
project-wide without being restated.

The release *tag* is derived independently by the Justfile
(`fsdk_version`), which greps the point release out of the pinned
`elements/freedesktop-sdk.bst` junction ref. Renovate bumps that ref
automatically; nothing bumps `release-version`. When the two drift, CI
publishes a new tag containing assets that still carry the old version
string, so `systemd-sysupdate` sees no version change and the fleet
silently stops updating.
The k0s sysext is on its own axis: an independently-pinned third-party
payload versioned from `include/k0s.yml` and enforced separately by
`.github/scripts/check-k0s-version.py`.

This script fails closed on that drift.
This script validates both axes against their pins:
* project.conf installer-version against elements/freedesktop-sdk.bst
* include/flatcar.yml flatcar-version is well-formed

This script fails closed on any drift.
"""

import re
Expand All @@ -33,11 +34,15 @@
ROOT = Path(__file__).resolve().parents[2]
PROJECT_CONF = ROOT / "project.conf"
FSDK_JUNCTION = ROOT / "elements" / "freedesktop-sdk.bst"
FLATCAR_PIN = ROOT / "include" / "flatcar.yml"

RELEASE_VERSION_RE = re.compile(
r"^\s*release-version:\s*[\"']?([0-9]+\.[0-9]+\.[0-9]+)[\"']?\s*$", re.MULTILINE
INSTALLER_VERSION_RE = re.compile(
r"^\s*installer-version:\s*[\"']?([0-9]+\.[0-9]+\.[0-9]+)[\"']?\s*$", re.MULTILINE
)
FSDK_REF_RE = re.compile(r"freedesktop-sdk-([0-9]+\.[0-9]+\.[0-9]+)")
FLATCAR_PIN_RE = re.compile(
r"^\s*flatcar-version:\s*[\"']?([0-9]+\.[0-9]+\.[0-9]+)[\"']?\s*$", re.MULTILINE
)


def read(path):
Expand All @@ -49,39 +54,48 @@ def read(path):
def main():
conf = read(PROJECT_CONF)
junction = read(FSDK_JUNCTION)
flatcar = read(FLATCAR_PIN)

conf_match = RELEASE_VERSION_RE.search(conf)
if not conf_match:
installer_match = INSTALLER_VERSION_RE.search(conf)
if not installer_match:
sys.exit(
"ERROR: project.conf does not declare a "
"'release-version: X.Y.Z' variable."
"ERROR: project.conf does not declare an "
"'installer-version: X.Y.Z' variable."
)
declared = conf_match.group(1)
installer_declared = installer_match.group(1)

ref_match = FSDK_REF_RE.search(junction)
if not ref_match:
fsdk_match = FSDK_REF_RE.search(junction)
if not fsdk_match:
sys.exit(
"ERROR: elements/freedesktop-sdk.bst has no "
"'freedesktop-sdk-X.Y.Z' point release in its ref."
)
pinned = ref_match.group(1)
fsdk_pinned = fsdk_match.group(1)

flatcar_pin_match = FLATCAR_PIN_RE.search(flatcar)
if not flatcar_pin_match:
sys.exit(
"ERROR: include/flatcar.yml does not declare a "
"'flatcar-version: X.Y.Z' variable."
)
flatcar_pinned = flatcar_pin_match.group(1)

if declared != pinned:
if installer_declared != fsdk_pinned:
sys.exit(
"ERROR: release-version drift.\n"
f" project.conf release-version : {declared}\n"
f" elements/freedesktop-sdk.bst pinned ref: {pinned}\n"
"ERROR: installer-version drift.\n"
f" project.conf installer-version : {installer_declared}\n"
f" elements/freedesktop-sdk.bst pinned ref: {fsdk_pinned}\n"
"\n"
"The release tag is derived from the junction ref while asset\n"
"filenames are derived from release-version. While these differ,\n"
"a new GitHub Release publishes assets still named with the old\n"
"version, systemd-sysupdate reads the old version from '@v', and\n"
"deployed hosts never see an update.\n"
"The installer release tag and installer assets are derived from the\n"
"junction ref while project.conf declares installer-version.\n"
"\n"
f"Fix: set release-version to \"{pinned}\" in project.conf."
f"Fix: set installer-version to \"{fsdk_pinned}\" in project.conf."
)

print(f"OK: release-version {declared} matches the pinned FSDK point release.")
print(
f"OK: installer-version {installer_declared} matches pinned FSDK point release.\n"
f"OK: flatcar-version {flatcar_pinned} declared in include/flatcar.yml."
)


if __name__ == "__main__":
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ repos:
language: system
files: ^\.github/workflows/.*\.(yml|yaml)$
- id: check-release-version
name: release-version matches pinned FSDK point release
name: release versions match pinned FSDK and Flatcar releases
entry: python .github/scripts/check-release-version.py
language: system
pass_filenames: false
files: ^(project\.conf|elements/freedesktop-sdk\.bst|\.github/scripts/check-release-version\.py)$
files: ^(project\.conf|elements/freedesktop-sdk\.bst|include/flatcar\.yml|\.github/scripts/check-release-version\.py)$
- id: check-k0s-version
name: k0s version derived from include/k0s.yml, not restated
entry: python .github/scripts/check-k0s-version.py
Expand Down
5 changes: 3 additions & 2 deletions docs/skills/avoid-over-engineering.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@ existing repo convention already does the job.
## Verification

- [ ] `just validate` passes before and after the change.
- [ ] No hardcoded version duplicates remain; `release-version` in `project.conf`
is the single source of truth.
- [ ] No hardcoded version duplicates remain; `installer-version` in `project.conf`
and `flatcar-version` in `include/flatcar.yml` define the installer and OS
payload axes.
- [ ] Removed build dependencies are not used by any command in the element.
- [ ] For `manual`/`script` elements, the sandbox still has `/bin/sh` and any coreutils the commands need after a dep cut.
- [ ] For `script` elements, build the element with `just bst build <element>`; transitive tools (`dracut`, `ukify`, etc.) may fail silently if their own runtime deps are missing from the sandbox.
Expand Down
3 changes: 2 additions & 1 deletion docs/skills/ddi-installer-build.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ The release process is driven by `.github/workflows/build.yml`:
- CI builds the DDI payload, installer, target UKI, k0s sysext, and standalone
PXE boot inputs (`bluefin-server-pxe-vmlinuz-*`, `bluefin-server-pxe-initrd-*.cpio.gz`).
- CI uploads the versioned release assets to the corresponding
`installer-v<release-version>` GitHub Release.
`installer-v<installer-version>` GitHub Release. The release tag tracks the
installer axis, while the DDI and UKI inside it track the Flatcar payload axis (`flatcar-version`).
- CI also produces a combined `dist/release/SHA256SUMS` manifest and signs it
to create `SHA256SUMS.gpg` for `systemd-sysupdate` verification. The PXE
inputs are included in this manifest, per `docs/skills/ddi-installer.md`.
Expand Down
2 changes: 1 addition & 1 deletion docs/skills/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@ This is the lazy-load routing table for agent skills. Keep this file in memory w
- **Publish registry:** factory OCI registry at `<registry-host>:30500` (or configured by operator).
- **Cluster build workflow:** `bluefin-server-build-pipeline` in the downstream factory CI repository.
- **Cluster boot-test workflow:** `bluefin-server-boot-test` in the downstream factory CI repository.
- **Version scheme:** FSDK-derived only; no separate application version axis.
- **Version scheme:** two axes — `installer-version` (FSDK-derived, `project.conf`) and `flatcar-version` (OS payload, `include/flatcar.yml`); no application version axis.
8 changes: 4 additions & 4 deletions elements/bluefin-server/os-release-flatcar.bst
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ config:
install-commands:
- mkdir -p "%{install-root}/usr/lib"
- |
# %{release-version} is declared in project.conf and enforced against
# the junction ref by check-release-version.py — no re-parsing needed.
# %{flatcar-version} comes from include/flatcar.yml, the single source of
# truth for the Flatcar axis — no re-parsing needed.
FLATCAR_VERSION="%{flatcar-version}"

cat <<EOF > "%{install-root}/usr/lib/os-release"
Expand All @@ -28,13 +28,13 @@ config:
ID_LIKE=fedora
VERSION="${FLATCAR_VERSION}-fsdk"
VERSION_ID=${FLATCAR_VERSION}
PRETTY_NAME="Bluefin Server %{release-version}"
PRETTY_NAME="Bluefin Server %{flatcar-version}"
ANSI_COLOR="0;38;5;208"
HOME_URL="https://github.com/projectbluefin/server"
BUG_REPORT_URL="https://github.com/projectbluefin/server/issues"
FLATCAR_BOARD="%{flatcar-board}"
CPE_NAME="cpe:/o:flatcar-linux:flatcar_linux:${FLATCAR_VERSION}"
IMAGE_VERSION=%{release-version}
IMAGE_VERSION=%{flatcar-version}
EOF
- |
mkdir -p "%{install-root}/etc"
Expand Down
2 changes: 1 addition & 1 deletion elements/oci/bluefin-server-ddi.bst
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ build-depends:
location: /layer

variables:
ddi-version: "%{release-version}"
ddi-version: "%{flatcar-version}"

config:
commands:
Expand Down
7 changes: 2 additions & 5 deletions elements/oci/bluefin-server-installer.bst
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,6 @@ build-depends:
config:
location: /k0s

variables:
installer-version: "%{release-version}"

config:
commands:
# ── Step 1a: Prepare rootfs directories and mount points ────────────
Expand Down Expand Up @@ -443,15 +440,15 @@ config:
zstd --rm -T0 -19 -q "${FNAME}" -o "${FNAME}.zst"

# Also export the target UKI (.efi) for GitHub Releases and systemd-sysupdate
cp /layer/usr/lib/bluefin-server/bluefin-server.efi "bluefin-server-%{installer-version}.efi"
cp /layer/usr/lib/bluefin-server/bluefin-server.efi "bluefin-server-%{flatcar-version}.efi"
# Export raw PXE inputs alongside the UKI. PXE users supply their own
# kernel command line, so these remain separate from the fixed-cmdline UKI.
INSTALLER_KVER="$(basename "$(find /layer/usr/lib/modules -mindepth 1 -maxdepth 1 -type d | head -n1)")"
cp "/layer/usr/lib/modules/${INSTALLER_KVER}/vmlinuz" "bluefin-server-pxe-vmlinuz-%{installer-version}"
cp /installer.cpio.gz "bluefin-server-pxe-initrd-%{installer-version}.cpio.gz"

sha256sum --binary "${FNAME}.zst" > SHA256SUMS
sha256sum --binary "bluefin-server-%{installer-version}.efi" >> SHA256SUMS
sha256sum --binary "bluefin-server-%{flatcar-version}.efi" >> SHA256SUMS
sha256sum --binary "bluefin-server-pxe-vmlinuz-%{installer-version}" >> SHA256SUMS
sha256sum --binary "bluefin-server-pxe-initrd-%{installer-version}.cpio.gz" >> SHA256SUMS
ls -lh
10 changes: 7 additions & 3 deletions project.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ element-path: elements
(@):
- gnome-build-meta.bst:freedesktop-sdk.bst:include/runtime.yml
- include/aliases.yml
# OS payload axis (Flatcar): single source of truth for %{flatcar-version}
# and %{flatcar-kver}. Included here so both resolve project-wide without
# being restated. Enforced by .github/scripts/check-release-version.py.
- include/flatcar.yml

options:
arch:
Expand All @@ -23,10 +27,10 @@ sandbox:
build-arch: "%{arch}"

variables:
# Single source of truth for asset versioning; must match the FSDK point
# release pinned in elements/freedesktop-sdk.bst. Enforced by
# Installer axis (FSDK): must match the point release pinned in
# elements/freedesktop-sdk.bst. Enforced by
# .github/scripts/check-release-version.py.
release-version: "26.08.0"
installer-version: "26.08.0"

# Pull-only: read from the shared GNOME + Bluefin BuildStream CAS caches.
artifacts:
Expand Down
Loading
Loading