Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/version: validate system.stateVersion #351158

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

tilpner
Copy link
Member

@tilpner tilpner commented Oct 25, 2024

Continuation of #81135 and #317858.

With #340501 merged, hopefully this won't break eval again.

Description of changes

The location of the release type is open for discussion, it could go into lib.types instead.

Test with

nix-instantiate --eval -E '(import ./nixos { configuration.system.stateVersion = "20.05"; }).config.system.stateVersion'

Correctly invalid (with lib.trivial.release == "24.11"):

"19", "19.3"
"unstable", "nixos-unstable", "nixos.unstable"
"19.04"
"xy.03"
"25.11"
"20.05"
"21.03"

Correctly valid:

"19.03"
"16.09"
"20.09"
"21.05"
"24.11"

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.11 Release Notes (or backporting 23.11 and 24.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: documentation This PR adds or changes documentation 8.has: changelog 8.has: module (update) This PR changes an existing module in `nixos/` labels Oct 25, 2024
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 labels Oct 25, 2024
@wegank wegank added the 12.approvals: 1 This PR was reviewed and approved by one reputable person label Oct 26, 2024
Comment on lines 49 to 160
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;

versionPatterns = [
# only 13.10
{ fromMajor = 13; minor = [ "10" ]; }
# 14.04 and 14.12
{ fromMajor = 14; minor = [ "04" "12" ]; }
# only 15.09
{ fromMajor = 15; minor = [ "09" ]; }
# 16.03 to 20.09
{ fromMajor = 16; minor = [ "03" "09" ]; }
# from 21.05
{ fromMajor = 21; 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have to play this game instead of just listing all previous versions?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention was to avoid adding yet another place that needs to be changed when a new release is cut (just when the release schedule changes). It was neater before I added pre-16 releases with less regularity.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

system.stateVersion was added in d166c85 and its first valid value was actually, uh… 15.07(!). So you can omit the earlier releases but have to account for past schedule drift. Looking at git log -p .version, you also need 21.03, 17.10 (though this only existed for about 20 minutes, so you can probably omit it), 15.08, and 15.06. (There were actually also 15.05, 15.04, 14.11 (looks like 14.12 never existed on master?), 14.10, and 14.02, but as I said those predate stateVersion.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As previously mentioned, there is a stateVersion even in the NixOS infrastructure using a value from before the option was introduced, so I can't omit it.

As for the .version log, that's a good point. I've been mostly going off of https://channels.nixos.org/ for the authoritative list of "real" versions. But that might be unfair to unstable users, if their config was generated while .version didn't refer to a channel version.

There are some very early versions with most likely zero instances in the wild, going back to 0.5 in 2004, in that history, but I'll include all of the ones following the YY.MM format (starting at 13.07), if it means we don't have to discuss which of them are "real enough". It'll still benefit users going forward, even if it might be overly-permissive for some (long) past releases. Please leave a thumbs-up or reply if you think we should just include all of them (YY.MM).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for missing the previous discussion. Just going based on the .version log as you suggested seems good to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't be expected to read all the previous iterations of this PR :)

It's not just .version, as channels.nixos.org contains some versions that have never been in master/.version, so I included it if it appeared in either.

@tilpner tilpner force-pushed the state-version-validation branch from 020c6d0 to 0f2e1cf Compare October 29, 2024 11:27
Comment on lines 54 to 148
# 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" ]; }
];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turned from a very sparse representation that made sense to me, to basically listing all versions from 2013 to 2018 exhaustively, and I'm less content with the patch for it. We could omit two lines if we ignore 17.10 (the 21min mistake), but then I'd have to add a comment explaining why, and it doesn't seem worth diverging from the "include everything" stance.

If anyone has a significantly more compact idea that doesn't need to be updated twice a year, I'm open for improvements.

@wegank wegank removed the 12.approvals: 1 This PR was reviewed and approved by one reputable person label Oct 29, 2024
@jopejoe1 jopejoe1 added the 2.status: merge conflict This PR has merge conflicts with the target branch label Dec 4, 2024
@rhendric
Copy link
Member

rhendric commented Feb 6, 2025

Even a simpler patch that only uses a regex to validate instead of a set of valid versions would be a big help. I just got finished diagnosing an issue with a noob's config that was caused by system.stateVersion = "unstable";, and having the type system catch that with a regex would have saved us all some time.

@eclairevoyant
Copy link
Contributor

@rhendric I've opened #379754 as a simpler but IMO more effective approach.

@tilpner
Copy link
Member Author

tilpner commented Feb 6, 2025

@rhendric I don't think the complexity of the validation has prevented this PR from being merged. Rather, it hasn't been rebased since 24.11, and has received no review attention since.

If there still is interest, I don't mind rebasing it.

@rhendric
Copy link
Member

rhendric commented Feb 6, 2025

I'm interested in some version of this! Absent strong feelings either way, with two PRs available I'm inclined to review and merge the simpler one first, but I could be convinced that this stronger validation is worth the relatively minor maintenance cost whenever we change our release schedule or some unforeseen edge case arises.

@tilpner tilpner force-pushed the state-version-validation branch from 0f2e1cf to 174c28d Compare February 6, 2025 05:31
@ofborg ofborg bot removed the 2.status: merge conflict This PR has merge conflicts with the target branch label Feb 6, 2025
@tilpner
Copy link
Member Author

tilpner commented Feb 6, 2025

I agree that any sort of validation would be better than the current state.
As for complexity: this PR used to be a lot simpler, and then was made more rigorous after review input. It would be ironic if it was now too large to accept for that reason (but of course reviewers are not monolithic).

This version will additionally reject never-released versions like "23.12", and catch impossible versions like "24.22". Those are less problematic versions than "unstable", but could still happen from misunderstandings or typos.
It will also prevent you from setting a newer version than your nixpkgs version, though that seems fairly niche.

As a consequence of being a "generic NixOS version" option type, the description can't contain suggestions specific to stateVersion. An assertion is able to give more specific advice there.

@tilpner tilpner force-pushed the state-version-validation branch from 174c28d to 17d3052 Compare February 6, 2025 06:34
@tilpner
Copy link
Member Author

tilpner commented Feb 6, 2025

I'm not really a fan of what nixfmt does to this (turns 8 lines of versionPatterns into 66 lines), but short of committing a crime (packing version data into strings), I don't know how to keep it short. I'll try to accept it as an "ugly edge case".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: changelog 8.has: documentation This PR adds or changes documentation 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants