Skip to content

Commit

Permalink
nixos/version: validate system.stateVersion
Browse files Browse the repository at this point in the history
  • Loading branch information
tilpner committed Oct 29, 2024
1 parent 86e1ad4 commit 0f2e1cf
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
4 changes: 4 additions & 0 deletions nixos/doc/manual/release-notes/rl-2411.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -641,6 +641,10 @@
- `python3Packages.nose` has been removed, as it has been deprecated and unmaintained for almost a decade and does not work on Python 3.12.
Please switch to `pytest` or another test runner/framework.

- `system.stateVersion` is now validated. If you never changed this yourself, you don't need to do anything. If your `stateVersion` is not a valid NixOS release version (e.g. "24.11" is valid),
your system was already at risk of experiencing silent incompatible state updates. If your previous value is a well-formed version but not a valid release (e.g. "23.12"),
round down to the nearest actual release. If it wasn't a well-formed version (e.g. "nixos-unstable"), set it to the version of NixOS that you originally installed.

## Other Notable Changes {#sec-release-24.11-notable-changes}

<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
Expand Down
50 changes: 48 additions & 2 deletions nixos/modules/misc/version.nix
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,52 @@ let
};
initrdRelease = pkgs.writeText "initrd-release" (attrsToText initrdReleaseContents);

checkRelease = version:
let
parts = lib.versions.splitVersion version;
isVersion = lib.length parts == 2 && lib.all (p: lib.stringLength p == 2) parts;
majorVersion = lib.toIntBase10 (lib.elemAt parts 0);
minorVersion = lib.elemAt parts 1;

# Refer to both https://channels.nixos.org/ and `git log --follow -p .version`.
# Some of the early version have never been released as a channel, but are included
# anyway for the benefit of nixos-unstable users who used these intermediate versions.
# Versions prior to the introduction of the `stateVersion` option have been observed
# in usage, so they can't be omitted.
versionPatterns = [
{ fromMajor = 13; minor = [ "07" "09" "10" ]; }
{ fromMajor = 14; minor = [ "02" "04" "10" "11" "12" ]; }
{ fromMajor = 15; minor = [ "04" "05" "06" "07" "08" "09" ]; }
{ fromMajor = 16; minor = [ "03" "09" ]; }
{ fromMajor = 17; minor = [ "03" "09" "10" ]; }
{ fromMajor = 18; minor = [ "03" "09" ]; }
{ fromMajor = 21; minor = [ "03" "05" "11" ]; }
{ fromMajor = 22; minor = [ "05" "11" ]; }
];

# find the versioning pattern that applies by looking for the first
# major version newer than `majorVersion`, and picking the previous pattern
patternIndex = lib.lists.findFirstIndex
({ fromMajor, ... }: fromMajor > majorVersion)
(lib.length versionPatterns)
versionPatterns;

validMinorVersions =
if patternIndex == 0
then []
else (lib.elemAt versionPatterns (patternIndex - 1)).minor;

correctMinorVersion = lib.elem minorVersion validMinorVersions;
notNewerThanNixpkgs = lib.versionAtLeast trivial.release version;
in isVersion && correctMinorVersion && notNewerThanNixpkgs;

releaseType = types.addCheck
(types.strMatching "[[:digit:]]{2}\\.[[:digit:]]{2}")
checkRelease // {
name = "nixosRelease";
description = "NixOS release version, e.g. \"${trivial.release}\"";
descriptionClass = "nonRestrictiveClause";
};
in
{
imports = [
Expand All @@ -70,7 +116,7 @@ in

release = mkOption {
readOnly = true;
type = types.str;
type = releaseType;
default = trivial.release;
description = "The NixOS release (e.g. `16.03`).";
};
Expand Down Expand Up @@ -151,7 +197,7 @@ in
};

stateVersion = mkOption {
type = types.str;
type = releaseType;
# TODO Remove this and drop the default of the option so people are forced to set it.
# Doing this also means fixing the comment in nixos/modules/testing/test-instrumentation.nix
apply = v:
Expand Down

0 comments on commit 0f2e1cf

Please sign in to comment.