Bake the channel manifest's closure instead of a pinned app version
Production builds failed CI's baseline preflight because flake.nix pinned the app to tag 1.8 (channel.appVersion = "1.8") while the published manifest had moved on to 1.9. Stop pinning the app anywhere. flake.nix now fetches the channel's published manifest at eval time (builtins.fetchurl) and bakes its storePath verbatim, so every image carries exactly the closure RadiantWave published to Attic and never compiles the app from source. - flake.nix: drop the radiantwave/radiantwave-dev inputs, appInput, appVersion, channelVersion and baselineOutPaths; add channelAtticUrl, channelManifestDir and publishedApp; builders consume the published path. - configuration.nix: wrap the published store path in a symlinkJoin so it can live in environment.systemPackages; add --impure to autoUpgrade flags and set tarball-ttl = 0 so eval reads the current manifest. - radiantwave-updater.nix: baselinePackage (package) -> baselinePath (str), seeded from the exact manifest path. - CI (build.yml): replace the version-equality preflight with a fail-fast check that the announced closure is in the channel's Attic; set tarball-ttl = 0. - build-rpi.sh: pass --impure. - AGENTS.md: document the manifest-driven baseline.
This commit is contained in:
@@ -4,8 +4,6 @@
|
||||
disko.url = "github:nix-community/disko";
|
||||
disko.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nixos-facter-modules.url = "github:numtide/nixos-facter-modules";
|
||||
radiantwave.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=refs/tags/1.8";
|
||||
radiantwave-dev.url = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/radiantwave.git?ref=dev";
|
||||
nixos-raspberrypi.url = "github:nvmd/nixos-raspberrypi/main";
|
||||
};
|
||||
|
||||
@@ -15,8 +13,6 @@
|
||||
nixpkgs,
|
||||
disko,
|
||||
nixos-facter-modules,
|
||||
radiantwave,
|
||||
radiantwave-dev,
|
||||
nixos-raspberrypi,
|
||||
...
|
||||
}@inputs:
|
||||
@@ -62,51 +58,46 @@
|
||||
# this channel, so a `dev`-to-`main` merge carries your changes with it
|
||||
# automatically. There are no more `-dev` sibling configs to copy.
|
||||
#
|
||||
# main: appInput = radiantwave (tag 1.8), atticRepo = "radiantwave",
|
||||
# gitRef = "", appVersion = "1.8"
|
||||
# dev: appInput = radiantwave-dev, atticRepo = "radiantwave-dev",
|
||||
# gitRef = "?ref=dev", appVersion = <dev fingerprint>
|
||||
# main: atticRepo = "radiantwave", gitRef = ""
|
||||
# dev: atticRepo = "radiantwave-dev", gitRef = "?ref=dev"
|
||||
#
|
||||
# To flip branches, change ONLY these four values (then push/merge).
|
||||
# To flip branches, change ONLY these two values (then push/merge).
|
||||
#
|
||||
# Note there is deliberately NO app version here. The RadiantWave app is
|
||||
# not built or pinned by this repo; each channel's published manifest is
|
||||
# the single source of truth (see `publishedApp` below).
|
||||
channel = {
|
||||
appInput = radiantwave; # main
|
||||
atticRepo = "radiantwave"; # main
|
||||
gitRef = ""; # main
|
||||
appVersion = "1.8"; # main
|
||||
};
|
||||
|
||||
# Exposed so CI (see .gitea/workflows/build-prod-*.yml) and humans can
|
||||
# verify which channel this checkout resolves to. On `main` this must be
|
||||
# "radiantwave"; on `dev` it must be "radiantwave-dev". The prod
|
||||
# workflows fail fast if this isn't the production channel, so a merge
|
||||
# that brings a dev-pointing channel block into `main` breaks the build
|
||||
# instead of silently shipping dev builds as prod ISOs.
|
||||
channelName = if channel.appInput == radiantwave then "radiantwave" else "radiantwave-dev";
|
||||
# Exposed so CI (see .gitea/workflows/build.yml) and humans can verify
|
||||
# which channel this checkout resolves to. On `main` this is
|
||||
# "radiantwave"; on `dev` it is "radiantwave-dev".
|
||||
channelName = channel.atticRepo;
|
||||
|
||||
# Channel metadata exposed for CI preflight (see .gitea/workflows/build-*).
|
||||
# `channelVersion` must equal the version RadiantWave CI publishes in the
|
||||
# channel manifest; `baselineOutPaths` must equal the manifest's
|
||||
# `storePath`. When they do, the ISO bakes exactly the closure already in
|
||||
# Attic, so the app is substituted (never compiled locally) and the first
|
||||
# live update is a no-op. A mismatch means either the pinned input is
|
||||
# stale (as when the release tag moves) or channel.appVersion drifted.
|
||||
channelVersion = channel.appVersion;
|
||||
# Channel metadata shared by the configs and the CI preflight.
|
||||
channelAtticUrl = "https://attic.radiantwavetech.com/${channel.atticRepo}";
|
||||
channelManifestDir = "https://files.radiantwavetech.com/${channel.atticRepo}";
|
||||
baselineOutPaths = {
|
||||
x86_64-linux = (appPackage "x86_64-linux").outPath;
|
||||
aarch64-linux = (appPackage "aarch64-linux").outPath;
|
||||
};
|
||||
|
||||
# The App package, pinned to the channel's declared version. RadiantWave's
|
||||
# own flake only injects its version from the ambient APP_VERSION env var
|
||||
# on impure evals; pure evals (local `nix build`, build-rpi.sh) fall back
|
||||
# to its 0.1.0 default. Overriding the version here makes the baked
|
||||
# baseline correct regardless of eval purity, and matches the Attic
|
||||
# closure when RadiantWave CI built it with the same version string.
|
||||
appPackage = system: channel.appInput.packages.${system}.default.override {
|
||||
version = channel.appVersion;
|
||||
};
|
||||
# The baked RadiantWave app is whatever the channel's published manifest
|
||||
# currently announces. RadiantWave CI builds the app, pushes the closure
|
||||
# to the channel's Attic cache, and writes {version, storePath} to the
|
||||
# manifest. We fetch that manifest at eval time and use its storePath
|
||||
# verbatim, so an image always carries exactly the published closure and
|
||||
# never compiles RadiantWave from source. This is an *impure* fetch (no
|
||||
# hash), so every eval that reaches the app needs `--impure`: CI, the
|
||||
# kiosk's system.autoUpgrade, and local `build-rpi.sh` all pass it.
|
||||
manifestFor = manifestFile:
|
||||
builtins.fromJSON (builtins.readFile (builtins.fetchurl {
|
||||
url = "${channelManifestDir}/${manifestFile}";
|
||||
}));
|
||||
|
||||
# The published closure as a plain store-path string. configuration.nix
|
||||
# wraps it in a symlinkJoin so it can live in environment.systemPackages
|
||||
# (a bare string there would be coerced with builtins.storePath, which
|
||||
# requires the closure to already be local at eval time).
|
||||
publishedApp = manifestFile: (manifestFor manifestFile).storePath;
|
||||
|
||||
# Live app-update side channel. The manifest is served by the
|
||||
# fileserver; closures are fetched (never built) from the channel's
|
||||
@@ -118,7 +109,7 @@
|
||||
radiantwaveUpdaterModule = { repo, baseline, manifestFile ? "manifest.json" }: {
|
||||
services.radiantwaveUpdater = {
|
||||
enable = true;
|
||||
baselinePackage = baseline;
|
||||
baselinePath = baseline;
|
||||
manifestUrl = "https://files.radiantwavetech.com/${repo}/${manifestFile}";
|
||||
atticUrl = "https://attic.radiantwavetech.com/${repo}";
|
||||
};
|
||||
@@ -126,7 +117,6 @@
|
||||
|
||||
mkKioskSystem = {
|
||||
system,
|
||||
radiantwave,
|
||||
upgradeFlakeRef,
|
||||
hostName,
|
||||
diskModule,
|
||||
@@ -136,8 +126,8 @@
|
||||
inherit system;
|
||||
|
||||
specialArgs = {
|
||||
inherit radiantwave upgradeFlakeRef;
|
||||
radiantwaveApp = appPackage system;
|
||||
inherit upgradeFlakeRef;
|
||||
radiantwaveApp = publishedApp "manifest.json";
|
||||
radiantwavePlymouth = mkRadiantwavePlymouth;
|
||||
};
|
||||
|
||||
@@ -159,21 +149,19 @@
|
||||
# facter-<model>.json, and select per variant here, e.g.:
|
||||
# { facter.reportPath = ./facter-commercial.json; }
|
||||
{ facter.reportPath = ./facter.json; }
|
||||
radiantwave.nixosModules.default
|
||||
] ++ extraModules;
|
||||
};
|
||||
|
||||
mkRpiKioskSystem = {
|
||||
radiantwave,
|
||||
upgradeFlakeRef,
|
||||
hostName,
|
||||
extraModules ? [],
|
||||
}:
|
||||
nixos-raspberrypi.lib.nixosSystem {
|
||||
specialArgs = {
|
||||
inherit radiantwave upgradeFlakeRef;
|
||||
inherit upgradeFlakeRef;
|
||||
inherit nixos-raspberrypi;
|
||||
radiantwaveApp = appPackage "aarch64-linux";
|
||||
radiantwaveApp = publishedApp "aarch64-manifest.json";
|
||||
radiantwavePlymouth = mkRadiantwavePlymouth;
|
||||
};
|
||||
|
||||
@@ -189,7 +177,6 @@
|
||||
})
|
||||
./configuration.nix
|
||||
./radiantwave-updater.nix
|
||||
radiantwave.nixosModules.default
|
||||
{
|
||||
networking.hostName = hostName;
|
||||
system.configurationRevision = revision;
|
||||
@@ -239,7 +226,7 @@
|
||||
};
|
||||
in
|
||||
{
|
||||
inherit channelName channelVersion channelAtticUrl channelManifestDir baselineOutPaths;
|
||||
inherit channelName channelAtticUrl channelManifestDir;
|
||||
|
||||
packages.x86_64-linux.radiantwavekiosk = self.nixosConfigurations.radiantwavekiosk.config.system.build.toplevel;
|
||||
packages.x86_64-linux.radiantwavekiosk-commercial = self.nixosConfigurations.radiantwavekiosk-commercial.config.system.build.toplevel;
|
||||
@@ -249,53 +236,50 @@
|
||||
# Kiosk systems — one per hardware target, no dev/prod siblings.
|
||||
#
|
||||
# Every config consumes the channel selected at the top of this file
|
||||
# (see `channel`): the RadiantWave app input, the Attic repo/manifest
|
||||
# it fetches live updates from, and the KioskConfig git ref it
|
||||
# auto-upgrades from. On `main` the channel is prod; on `dev` it is the
|
||||
# dev channel. Because there is exactly one config per hardware type,
|
||||
# changes made on `dev` reach prod via a plain merge — no copying.
|
||||
# (see `channel`): the published manifest whose closure is baked as the
|
||||
# app, the Attic repo/manifest it fetches live updates from, and the
|
||||
# KioskConfig git ref it auto-upgrades from. On `main` the channel is
|
||||
# prod; on `dev` it is the dev channel. Because there is exactly one
|
||||
# config per hardware type, changes made on `dev` reach prod via a plain
|
||||
# merge — no copying.
|
||||
nixosConfigurations = {
|
||||
radiantwavekiosk = mkKioskSystem {
|
||||
system = "x86_64-linux";
|
||||
radiantwave = channel.appInput;
|
||||
hostName = "radiantwavekiosk";
|
||||
diskModule = ./disk-config.nix;
|
||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git${channel.gitRef}#radiantwavekiosk";
|
||||
extraModules = [
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = appPackage "x86_64-linux"; })
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = publishedApp "manifest.json"; })
|
||||
];
|
||||
};
|
||||
radiantwavekiosk-commercial = mkKioskSystem {
|
||||
system = "x86_64-linux";
|
||||
radiantwave = channel.appInput;
|
||||
hostName = "radiantwavekiosk-commercial";
|
||||
diskModule = ./commercial-disk-config.nix;
|
||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git${channel.gitRef}#radiantwavekiosk-commercial";
|
||||
extraModules = [
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = appPackage "x86_64-linux"; })
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = publishedApp "manifest.json"; })
|
||||
];
|
||||
};
|
||||
# Rotated screen for android-style displays.
|
||||
radiantwavekiosk-android = mkKioskSystem {
|
||||
system = "x86_64-linux";
|
||||
radiantwave = channel.appInput;
|
||||
hostName = "radiantwavekiosk-android";
|
||||
diskModule = ./disk-config.nix;
|
||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git${channel.gitRef}#radiantwavekiosk-android";
|
||||
extraModules = [
|
||||
./rotated_display.nix
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = appPackage "x86_64-linux"; })
|
||||
(radiantwaveUpdaterModule { repo = channel.atticRepo; baseline = publishedApp "manifest.json"; })
|
||||
];
|
||||
};
|
||||
# Raspberry Pi 5.
|
||||
radiantwavekiosk-rpi = mkRpiKioskSystem {
|
||||
radiantwave = channel.appInput;
|
||||
hostName = "radiantwavekiosk-rpi";
|
||||
upgradeFlakeRef = "git+https://gitea.radiantwavetech.com/RadiantWaveTech/KioskConfig.git${channel.gitRef}#radiantwavekiosk-rpi";
|
||||
extraModules = [
|
||||
(radiantwaveUpdaterModule {
|
||||
repo = channel.atticRepo;
|
||||
baseline = appPackage "aarch64-linux";
|
||||
baseline = publishedApp "aarch64-manifest.json";
|
||||
manifestFile = "aarch64-manifest.json";
|
||||
})
|
||||
];
|
||||
@@ -307,8 +291,8 @@
|
||||
# SATA with ./commercial-disk-config.nix — don't cross them.
|
||||
# The same names build dev-flavored images when the flake is checked
|
||||
# out on the `dev` branch (the channel block above selects the dev
|
||||
# app, attic repo, and upgrade ref), so there are no separate -dev
|
||||
# ISOs.
|
||||
# manifest, attic repo, and upgrade ref), so there are no separate
|
||||
# -dev ISOs.
|
||||
kiosk-iso = mkIso {
|
||||
targetConfig = "radiantwavekiosk";
|
||||
diskModule = ./disk-config.nix;
|
||||
|
||||
Reference in New Issue
Block a user