From dd14f91632146adf1ac476347c63ad66fdc64ca6 Mon Sep 17 00:00:00 2001 From: "kubestellar-hive[bot]" <280983584+kubestellar-hive[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 17:46:37 -0400 Subject: [PATCH] refactor(ci): enforce release-version invariant against pinned FSDK ref project.conf declares release-version as the single source of truth for asset filenames, while the Justfile independently derives fsdk_version from the pinned elements/freedesktop-sdk.bst junction ref and build.yml uses that derived value for the release tag. Nothing compared the two, and they have drifted: project.conf said 25.08.13 while the junction is pinned to freedesktop-sdk-25.08.15. While drifted, a release publishes a new tag whose assets still carry the old version string. files/os/sysupdate.d/*.transfer read that version from the filename via @v, see no change, and hosts stop updating with no error anywhere in the pipeline. Add .github/scripts/check-release-version.py, which parses both values and fails closed on mismatch. Wire it into the existing `just validate` entry point (already run by build.yml's "Validate Element Graph" step) and into pre-commit. Correct project.conf to 25.08.15 so the declared invariant holds. Refs #31 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: kubestellar-hive[bot] <280983584+kubestellar-hive[bot]@users.noreply.github.com> --- .github/scripts/check-release-version.py | 84 ++++++++++++++++++++++++ .pre-commit-config.yaml | 6 ++ Justfile | 1 + project.conf | 6 +- 4 files changed, 95 insertions(+), 2 deletions(-) create mode 100755 .github/scripts/check-release-version.py diff --git a/.github/scripts/check-release-version.py b/.github/scripts/check-release-version.py new file mode 100755 index 0000000..2926f55 --- /dev/null +++ b/.github/scripts/check-release-version.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +"""Enforce the release-version invariant for Bluefin Server. + +project.conf declares: + + variables: + release-version: "X.Y.Z" # must match the FSDK point release + +That value names every published release asset +(`bluefin-server-ddi-.raw.zst`, `bluefin-server-.efi`, +`bluefin-server-installer-.raw.zst`, `k3s-.raw.zst`) and is the +version systemd-sysupdate extracts from those filenames via `@v`. + +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. + +This script fails closed on that drift. +""" + +import re +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +PROJECT_CONF = ROOT / "project.conf" +FSDK_JUNCTION = ROOT / "elements" / "freedesktop-sdk.bst" + +RELEASE_VERSION_RE = re.compile( + r"^\s*release-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]+)") + + +def read(path): + if not path.is_file(): + sys.exit(f"ERROR: expected file not found: {path.relative_to(ROOT)}") + return path.read_text(encoding="utf-8") + + +def main(): + conf = read(PROJECT_CONF) + junction = read(FSDK_JUNCTION) + + conf_match = RELEASE_VERSION_RE.search(conf) + if not conf_match: + sys.exit( + "ERROR: project.conf does not declare a " + "'release-version: X.Y.Z' variable." + ) + declared = conf_match.group(1) + + ref_match = FSDK_REF_RE.search(junction) + if not ref_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) + + if declared != pinned: + sys.exit( + "ERROR: release-version drift.\n" + f" project.conf release-version : {declared}\n" + f" elements/freedesktop-sdk.bst pinned ref: {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" + "\n" + f"Fix: set release-version to \"{pinned}\" in project.conf." + ) + + print(f"OK: release-version {declared} matches the pinned FSDK point release.") + + +if __name__ == "__main__": + main() diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 13710d4..a0b66c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,3 +12,9 @@ repos: entry: actionlint language: system files: ^\.github/workflows/.*\.(yml|yaml)$ + - id: check-release-version + name: release-version matches pinned FSDK point release + 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)$ diff --git a/Justfile b/Justfile index 371775c..4743bfc 100644 --- a/Justfile +++ b/Justfile @@ -51,6 +51,7 @@ tags: # ── Validate ────────────────────────────────────────────────────────── [group('dev')] validate: + python3 .github/scripts/check-release-version.py just bst show --deps all oci/bluefin-server-ddi.bst just bst show --deps all oci/bluefin-server-installer.bst just bst show --deps all oci/k3s-sysext.bst diff --git a/project.conf b/project.conf index d889137..10655b0 100644 --- a/project.conf +++ b/project.conf @@ -23,8 +23,10 @@ sandbox: build-arch: "%{arch}" variables: - # Single source of truth for asset versioning; must match the FSDK point release. - release-version: "25.08.13" + # Single source of truth for asset versioning; must match the FSDK point + # release pinned in elements/freedesktop-sdk.bst. Enforced by + # .github/scripts/check-release-version.py. + release-version: "25.08.15" # Pull-only: read from the shared GNOME + Bluefin BuildStream CAS caches. artifacts: