From 0accdf4e202066fee97312fb68bf182dbfb02b9f Mon Sep 17 00:00:00 2001 From: Lily Foster Date: Mon, 30 Jan 2023 15:36:51 -0500 Subject: [PATCH] types,module,tests: run shellcheck on scripts before running them in NixOS tests --- default.nix | 19 +++++++------------ module.nix | 17 ++++++++++++----- tests/default.nix | 4 ++-- tests/lib.nix | 14 ++++++++------ types/default.nix | 9 +++++++++ 5 files changed, 38 insertions(+), 25 deletions(-) diff --git a/default.nix b/default.nix index 33473bf..c352481 100644 --- a/default.nix +++ b/default.nix @@ -1,5 +1,6 @@ { lib ? import , rootMountPoint ? "/mnt" +, checked ? false }: let types = import ./types { inherit lib rootMountPoint; }; @@ -18,33 +19,27 @@ in { types = types; create = cfg: types.diskoLib.create (eval cfg).config.devices; - createScript = cfg: pkgs: pkgs.writeScript "disko-create" '' - #!/usr/bin/env bash + createScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-create" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.create (eval cfg).config.devices} ''; - createScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-create" '' - #!/usr/bin/env bash + createScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-create" '' ${types.diskoLib.create (eval cfg).config.devices} ''; mount = cfg: types.diskoLib.mount (eval cfg).config.devices; - mountScript = cfg: pkgs: pkgs.writeScript "disko-mount" '' - #!/usr/bin/env bash + mountScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.mount (eval cfg).config.devices} ''; - mountScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-mount" '' - #!/usr/bin/env bash + mountScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-mount" '' ${types.diskoLib.mount (eval cfg).config.devices} ''; zapCreateMount = cfg: types.diskoLib.zapCreateMount (eval cfg).config.devices; - zapCreateMountScript = cfg: pkgs: pkgs.writeScript "disko-zap-create-mount" '' - #!/usr/bin/env bash + zapCreateMountScript = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-zap-create-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages (eval cfg).config.devices pkgs)}:$PATH ${types.diskoLib.zapCreateMount (eval cfg).config.devices} ''; - zapCreateMountScriptNoDeps = cfg: pkgs: pkgs.writeScript "disko-zap-create-mount" '' - #!/usr/bin/env bash + zapCreateMountScriptNoDeps = cfg: pkgs: (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko-zap-create-mount" '' ${types.diskoLib.zapCreateMount (eval cfg).config.devices} ''; config = cfg: { imports = types.diskoLib.config (eval cfg).config.devices; }; diff --git a/module.nix b/module.nix index 820d985..afdd315 100644 --- a/module.nix +++ b/module.nix @@ -5,6 +5,7 @@ let rootMountPoint = config.disko.rootMountPoint; }; cfg = config.disko; + checked = cfg.checkScripts; in { options.disko = { @@ -27,26 +28,32 @@ in type = lib.types.bool; default = true; }; + checkScripts = lib.mkOption { + description = '' + Whether to run shellcheck on script outputs + ''; + type = lib.types.bool; + default = false; + }; }; config = lib.mkIf (cfg.devices.disk != { }) { - system.build.formatScript = pkgs.writers.writeBash "disko-create" '' + system.build.formatScript = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-create" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.create cfg.devices} ''; - system.build.mountScript = pkgs.writers.writeBash "disko-mount" '' + system.build.mountScript = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko-mount" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.mount cfg.devices} ''; - system.build.disko = pkgs.writers.writeBash "disko" '' + system.build.disko = (types.diskoLib.writeCheckedBash { inherit pkgs checked; }) "disko" '' export PATH=${lib.makeBinPath (types.diskoLib.packages cfg.devices pkgs)}:$PATH ${types.diskoLib.zapCreateMount cfg.devices} ''; # This is useful to skip copying executables uploading a script to an in-memory installer - system.build.diskoNoDeps = pkgs.writeScript "disko" '' - #!/usr/bin/env bash + system.build.diskoNoDeps = (types.diskoLib.writeCheckedBash { inherit pkgs checked; noDeps = true; }) "disko" '' ${types.diskoLib.zapCreateMount cfg.devices} ''; diff --git a/tests/default.nix b/tests/default.nix index 1efc16c..3a9e072 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -11,8 +11,8 @@ let disko-config = import configFile; in { - "${name}-tsp-create" = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create disko-config); - "${name}-tsp-mount" = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount disko-config); + "${name}-tsp-create" = (pkgs.callPackage ../. { checked = true; }).createScript disko-config pkgs; + "${name}-tsp-mount" = (pkgs.callPackage ../. { checked = true; }).mountScript disko-config pkgs; }; allTestFilenames = diff --git a/tests/lib.nix b/tests/lib.nix index 43b6607..c3d8957 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -24,10 +24,11 @@ inherit (pkgs) system; }; disks = [ "/dev/vda" "/dev/vdb" "/dev/vdc" "/dev/vdd" "/dev/vde" "/dev/vdf" ]; - tsp-create = pkgs.writeScript "create" ((pkgs.callPackage ../. { }).create (import disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-mount = pkgs.writeScript "mount" ((pkgs.callPackage ../. { }).mount (import disko-config { disks = builtins.tail disks; inherit lib; })); - tsp-config = (pkgs.callPackage ../. { }).config (import disko-config { inherit disks; inherit lib; }); - tsp-disko = pkgs.writeScript "disko" ((pkgs.callPackage ../. { }).zapCreateMount (import disko-config { disks = builtins.tail disks; inherit lib; })); + tsp-generator = pkgs.callPackage ../. { checked = true; }; + tsp-create = (tsp-generator.createScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-mount = (tsp-generator.mountScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-disko = (tsp-generator.zapCreateMountScript (import disko-config { disks = builtins.tail disks; inherit lib; })) pkgs; + tsp-config = tsp-generator.config (import disko-config { inherit disks; inherit lib; }); num-disks = builtins.length (lib.attrNames (import disko-config { inherit lib; }).disk); installed-system = { modulesPath, ... }: { imports = [ @@ -78,14 +79,15 @@ imports = [ ../module.nix ]; disko = { enableConfig = false; + checkScripts = true; devices = import disko-config { disks = builtins.tail disks; inherit lib; }; }; }) (lib.optionalAttrs (testMode == "cli") { imports = [ (modulesPath + "/installer/cd-dvd/channel.nix") ]; system.extraDependencies = [ - ((pkgs.callPackage ../. { }).createScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) - ((pkgs.callPackage ../. { }).mountScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ((pkgs.callPackage ../. { checked = true; }).createScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) + ((pkgs.callPackage ../. { checked = true; }).mountScript (import disko-config { disks = builtins.tail disks; inherit lib; }) pkgs) ]; }) (modulesPath + "/profiles/base.nix") diff --git a/types/default.nix b/types/default.nix index 2c967f6..d4082f2 100644 --- a/types/default.nix +++ b/types/default.nix @@ -193,6 +193,15 @@ rec { description = "Mount script"; }; + /* Writer for optionally checking bash scripts before writing them to the store + + writeCheckedBash :: AttrSet -> str -> str -> derivation + */ + writeCheckedBash = { pkgs, checked ? false, noDeps ? false }: pkgs.writers.makeScriptWriter { + interpreter = if noDeps then "/usr/bin/env bash" else "${pkgs.bash}/bin/bash"; + check = lib.optionalString checked "${pkgs.shellcheck}/bin/shellcheck"; + }; + /* Takes a disko device specification, returns an attrset with metadata