Clone of https://github.com/NixOS/nixpkgs.git (to stress-test knotserver)

nixos/bootspec: adopt the merged RFC-0125

This removes the feature preview warning, enable by default bootspec,
adds a validation flag to prevent Go to go into build-time closure.

This will break all downstream users of bootspec as those changes are
not backward-compatible.

authored by Raito Bezarius and committed by helbling.dev bc502d0a b76b960e

+49 -39
+2
nixos/doc/manual/release-notes/rl-2305.section.md
··· 28 28 29 29 - `libxcrypt`, the library providing the `crypt(3)` password hashing function, is now built without support for algorithms not flagged [`strong`](https://github.com/besser82/libxcrypt/blob/v4.4.33/lib/hashes.conf#L48). This affects the availability of password hashing algorithms used for system login (`login(1)`, `passwd(1)`), but also Apache2 Basic-Auth, Samba, OpenLDAP, Dovecot, and [many other packages](https://github.com/search?q=repo%3ANixOS%2Fnixpkgs%20libxcrypt&type=code). 30 30 31 + - `boot.bootspec.enable` (internal option) is now enabled by default because [RFC-0125](https://github.com/NixOS/rfcs/pull/125) was merged. This means you will have a bootspec document called `boot.json` generated for each system and specialisation in the top-level. This is useful to enable advanced boot usecases in NixOS such as SecureBoot. 32 + 31 33 ## New Services {#sec-release-23.05-new-services} 32 34 33 35 <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
+20 -7
nixos/modules/system/activation/bootspec.cue
··· 1 - #V1: { 1 + import "struct" 2 + 3 + #BootspecV1: { 2 4 system: string 3 5 init: string 4 6 initrd?: string ··· 7 9 kernelParams: [...string] 8 10 label: string 9 11 toplevel: string 10 - specialisation?: { 11 - [=~"^"]: #V1 12 - } 13 - extensions?: {...} 12 + } 13 + 14 + // A restricted document does not allow any official specialisation 15 + // information in it to avoid "recursive specialisations". 16 + #RestrictedDocument: struct.MinFields(1) & { 17 + "org.nixos.bootspec.v1": #BootspecV1 18 + [=~"^"]: #BootspecExtension 14 19 } 15 20 16 - Document: { 17 - v1: #V1 21 + // Specialisations are a hashmap of strings 22 + #BootspecSpecialisationV1: [string]: #RestrictedDocument 23 + 24 + // Bootspec extensions are defined by the extension author. 25 + #BootspecExtension: {...} 26 + 27 + // A "full" document allows official specialisation information 28 + // in the top-level with a reserved namespaced key. 29 + Document: #RestrictedDocument & { 30 + "org.nixos.specialisation.v1"?: #BootspecSpecialisationV1 18 31 }
+18 -26
nixos/modules/system/activation/bootspec.nix
··· 16 16 filename = "boot.json"; 17 17 json = 18 18 pkgs.writeText filename 19 - (builtins.toJSON 19 + (builtins.toJSON 20 + # Merge extensions first to not let them shadow NixOS bootspec data. 21 + (cfg.extensions // 20 22 { 21 - v1 = { 23 + "org.nixos.bootspec.v1" = { 22 24 system = config.boot.kernelPackages.stdenv.hostPlatform.system; 23 25 kernel = "${config.boot.kernelPackages.kernel}/${config.system.boot.loader.kernelFile}"; 24 26 kernelParams = config.boot.kernelParams; 25 27 label = "${config.system.nixos.distroName} ${config.system.nixos.codeName} ${config.system.nixos.label} (Linux ${config.boot.kernelPackages.kernel.modDirVersion})"; 26 - 27 - inherit (cfg) extensions; 28 28 } // lib.optionalAttrs config.boot.initrd.enable { 29 29 initrd = "${config.system.build.initialRamdisk}/${config.system.boot.loader.initrdFile}"; 30 30 initrdSecrets = "${config.system.build.initialRamdiskSecretAppender}/bin/append-initrd-secrets"; 31 31 }; 32 - }); 32 + })); 33 33 34 34 generator = 35 35 let ··· 42 42 toplevelInjector = lib.escapeShellArgs [ 43 43 "${pkgs.jq}/bin/jq" 44 44 '' 45 - .v1.toplevel = $toplevel | 46 - .v1.init = $init 45 + ."org.nixos.bootspec.v1".toplevel = $toplevel | 46 + ."org.nixos.bootspec.v1".init = $init 47 47 '' 48 48 "--sort-keys" 49 49 "--arg" "toplevel" "${placeholder "out"}" ··· 62 62 lib.escapeShellArgs [ 63 63 "${pkgs.jq}/bin/jq" 64 64 "--sort-keys" 65 - ".v1.specialisation = ($ARGS.named | map_values(. | first | .v1))" 65 + ''."org.nixos.specialisation.v1" = ($ARGS.named | map_values(. | first))'' 66 66 ] + " ${lib.concatStringsSep " " specialisationLoader}"; 67 67 in 68 - '' 69 - mkdir -p $out/bootspec 70 - 71 - ${toplevelInjector} | ${specialisationInjector} > $out/${filename} 72 - ''; 68 + "${toplevelInjector} | ${specialisationInjector} > $out/${filename}"; 73 69 74 70 validator = pkgs.writeCueValidator ./bootspec.cue { 75 71 document = "Document"; # Universal validator for any version as long the schema is correctly set. ··· 79 75 in 80 76 { 81 77 options.boot.bootspec = { 82 - enable = lib.mkEnableOption (lib.mdDoc "Enable generation of RFC-0125 bootspec in $system/bootspec, e.g. /run/current-system/bootspec"); 78 + enable = lib.mkEnableOption (lib.mdDoc "the generation of RFC-0125 bootspec in $system/boot.json, e.g. /run/current-system/boot.json") 79 + // { default = true; internal = true; }; 80 + enableValidation = lib.mkEnableOption (lib.mdDoc ''the validation of bootspec documents for each build. 81 + This will introduce Go in the build-time closure as we are relying on [Cuelang](https://cuelang.org/) for schema validation. 82 + Enable this option if you want to ascertain that your documents are correct. 83 + '' 84 + ); 83 85 84 86 extensions = lib.mkOption { 85 - type = lib.types.attrsOf lib.types.attrs; # <namespace>: { ...namespace-specific fields } 87 + # NOTE(RaitoBezarius): this is not enough to validate: extensions."osRelease" = drv; those are picked up by cue validation. 88 + type = lib.types.attrsOf lib.types.anything; # <namespace>: { ...namespace-specific fields } 86 89 default = { }; 87 90 description = lib.mdDoc '' 88 91 User-defined data that extends the bootspec document. ··· 111 114 internal = true; 112 115 default = schemas.v1.filename; 113 116 }; 114 - }; 115 - 116 - config = lib.mkIf (cfg.enable) { 117 - warnings = [ 118 - ''RFC-0125 is not merged yet, this is a feature preview of bootspec. 119 - The schema is not definitive and features are not guaranteed to be stable until RFC-0125 is merged. 120 - See: 121 - - https://github.com/NixOS/nixpkgs/pull/172237 to track merge status in nixpkgs. 122 - - https://github.com/NixOS/rfcs/pull/125 to track RFC status. 123 - '' 124 - ]; 125 117 }; 126 118 }
+2 -1
nixos/modules/system/activation/top-level.nix
··· 82 82 83 83 ${optionalString (!config.boot.isContainer && config.boot.bootspec.enable) '' 84 84 ${config.boot.bootspec.writer} 85 - ${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}" 85 + ${optionalString config.boot.bootspec.enableValidation 86 + ''${config.boot.bootspec.validator} "$out/${config.boot.bootspec.filename}"''} 86 87 ''} 87 88 88 89 ${config.system.extraSystemBuilderCmds}
+7 -5
nixos/tests/bootspec.nix
··· 110 110 111 111 machine.succeed("test -e /run/current-system/boot.json") 112 112 113 - bootspec = json.loads(machine.succeed("jq -r '.v1' /run/current-system/boot.json")) 113 + bootspec = json.loads(machine.succeed("jq -r '.\"org.nixos.bootspec.v1\"' /run/current-system/boot.json")) 114 114 115 115 assert all(key in bootspec for key in ('initrd', 'initrdSecrets')), "Bootspec should contain initrd or initrdSecrets field when initrd is enabled" 116 116 ''; ··· 136 136 machine.succeed("test -e /run/current-system/boot.json") 137 137 machine.succeed("test -e /run/current-system/specialisation/something/boot.json") 138 138 139 - sp_in_parent = json.loads(machine.succeed("jq -r '.v1.specialisation.something' /run/current-system/boot.json")) 139 + sp_in_parent = json.loads(machine.succeed("jq -r '.\"org.nixos.specialisation.v1\".something' /run/current-system/boot.json")) 140 140 sp_in_fs = json.loads(machine.succeed("cat /run/current-system/specialisation/something/boot.json")) 141 141 142 - assert sp_in_parent == sp_in_fs['v1'], "Bootspecs of the same specialisation are different!" 142 + assert sp_in_parent['org.nixos.bootspec.v1'] == sp_in_fs['org.nixos.bootspec.v1'], "Bootspecs of the same specialisation are different!" 143 143 ''; 144 144 }; 145 145 ··· 152 152 imports = [ standard ]; 153 153 environment.systemPackages = [ pkgs.jq ]; 154 154 boot.bootspec.extensions = { 155 - osRelease = config.environment.etc."os-release".source; 155 + "org.nix-tests.product" = { 156 + osRelease = config.environment.etc."os-release".source; 157 + }; 156 158 }; 157 159 }; 158 160 ··· 161 163 machine.wait_for_unit("multi-user.target") 162 164 163 165 current_os_release = machine.succeed("cat /etc/os-release") 164 - bootspec_os_release = machine.succeed("cat $(jq -r '.v1.extensions.osRelease' /run/current-system/boot.json)") 166 + bootspec_os_release = machine.succeed("cat $(jq -r '.\"org.nix-tests.product\".osRelease' /run/current-system/boot.json)") 165 167 166 168 assert current_os_release == bootspec_os_release, "Filename referenced by extension has unexpected contents" 167 169 '';