feat: Make modules evauluate without dependencies
Previously, module checks would stop us from evaluating if we didn't
include all of our dependencies' modules too. This became cumbersome if
someone was importing our flake, especially since as Nix doesn't stop
duplicate dependencies from being imported twice...
...by using optionalAttrs anywhere a dependency is needed, we stop Nix
being able to check that our options are valid, working around the issue
---
It's way too easy to make a mistake here, a first version of this change
had a bug where due to something like this...
x = lib.mkIf cfg.enable { } // { foo = lib.optionalAttrs ... }
...which evaluates as...
x = { _type = "if"; value = ...; foo = lib.optionalAttrs ...; ...; }
...we ended up dropping the impermanence options which mount our storage
It's really critical, therefore, to check that you aren't munging
attrsets into mkIf statements when you start using a mix of them
Change-Id: I7b786af965b3fd1012d956262aea72305b60db27
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/811
Reviewed-by: Skyler Grey <minion@clicks.codes>
Tested-by: Skyler Grey <minion@clicks.codes>
diff --git a/README.md b/README.md
index 9725dcb..cd7b87e 100644
--- a/README.md
+++ b/README.md
@@ -32,3 +32,47 @@
```bash
$ deploy .#MACHINE_NAME
```
+
+## Assumed dependencies
+
+If you're importing our modules, even if you don't enable most of them, you'll
+find it easiest and best to import them all. This is because the nixpkgs module
+system checks if all given options are defined, even if they aren't enabled in
+your specific configuration.
+
+The module system doesn't do this with traditional `if` statements or
+`lib.optionalAttrs`, only `lib.mkIf`, so we've made sure to use
+`lib.optionalAttrs` for anything that depends on things not in this list:
+
+- all modules defined in `nixpkgs`
+- all modules exported from this flake, which include only modules defined here
+
+We expect the majority of you will already have all of these imported. We use
+and test against `stateVersion = "24.05"`, and while we expect these modules to
+generally work with earlier or later `stateVersion`s, please be aware that this
+could cause unexpcted effects
+
+We may also depend on:
+
+- the standard arguments provided by `lib.nixosSystem` (`lib`, `pkgs`, etc.)
+ being passed into our modules
+- `lib` being extended such that `lib.clicks` is equal to the `lib` exported
+ from our flake
+
+We expect the `lib` extension to be a minor change, and providing standard
+arguments to modules to already be the case.
+
+This means that, provided you don't enable any options, importing the Clicks
+modules will be safe so long as your flake fulfils all of these factors: we
+won't break eval and we won't change any of your settings. If you'd like to see
+how we test that, please check out `./modules.spec.nix`
+
+We expect no additions to this list, except a potential future change of adding
+[auxolotl](https://auxolotl.org) modules to this list when we consider them
+stable and easily-importable. Additions to this list will always be considered
+breaking changes.
+
+(n.b. If you're wondering why we didn't use `lib.optionalAttrs` everywhere, it's
+because using it loses us some laziness, making it much easier to make infinite
+recursions. If we replaced every `lib.mkIf` with `lib.optionalAttrs` in our own
+config, for instance, it would no longer evaluate)
diff --git a/lib/modules/default.nix b/lib/modules/default.nix
deleted file mode 100644
index f0b6092..0000000
--- a/lib/modules/default.nix
+++ /dev/null
@@ -1,9 +0,0 @@
-# SPDX-FileCopyrightText: 2024 Clicks Codes
-#
-# SPDX-License-Identifier: GPL-3.0-only
-
-{ lib, ... }: {
- modules = {
- unset = lib.modules.mkIf false null;
- };
-}
diff --git a/modules/nixos/clicks/nix/default.nix b/modules/nixos/clicks/nix/default.nix
index 742980d..5403d54 100644
--- a/modules/nixos/clicks/nix/default.nix
+++ b/modules/nixos/clicks/nix/default.nix
@@ -67,7 +67,7 @@
let
users = [ "root" ];
in
- {
+ ({
package = cfg.package;
settings = {
@@ -95,9 +95,10 @@
};
# flake-utils-plus
+ } // (lib.optionalAttrs cfg.enable {
generateRegistryFromInputs = true;
generateNixPathFromInputs = true;
linkInputs = true;
- };
+ }));
};
}
diff --git a/modules/nixos/clicks/security/secrets/default.nix b/modules/nixos/clicks/security/secrets/default.nix
index 332efbe..8a120f9 100644
--- a/modules/nixos/clicks/security/secrets/default.nix
+++ b/modules/nixos/clicks/security/secrets/default.nix
@@ -12,8 +12,10 @@
default = config.clicks.defaults.enable;
};
- config = lib.mkIf cfg.enable {
- age.rekey = {
+ options.age = {}; # Required definition for lib.optionalAttrs...
+
+ config.age = lib.optionalAttrs cfg.enable {
+ rekey = {
masterIdentities = [
"${inputs.self}/secrets/keys/minion/collabora-yubikey.pub"
"${inputs.self}/secrets/keys/minion/tiny-yubikey.pub"
@@ -24,7 +26,7 @@
localStorageDir = lib.snowfall.fs.get-snowfall-file "secrets/rekeyed/${config.networking.hostName}";
};
- age.identityPaths = lib.mkIf config.clicks.storage.impermanence.enable [
+ identityPaths = lib.mkIf config.clicks.storage.impermanence.enable [
"/persist/data/etc/ssh/ssh_host_ed25519_key"
"/persist/data/etc/ssh/ssh_host_rsa_key"
];
diff --git a/modules/nixos/clicks/security/secrets/groupPerms/default.nix b/modules/nixos/clicks/security/secrets/groupPerms/default.nix
index 1f176ac..8337643 100644
--- a/modules/nixos/clicks/security/secrets/groupPerms/default.nix
+++ b/modules/nixos/clicks/security/secrets/groupPerms/default.nix
@@ -15,11 +15,8 @@
options.age = {
secrets = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule (submodule: {
- config = {
- mode = lib.pipe "0440" [
- (lib.mkOverride 999)
- (lib.mkIf config.clicks.security.secrets.groupPerms.enable)
- ];
+ config = lib.optionalAttrs config.clicks.security.secrets.groupPerms.enable {
+ mode = lib.mkOverride 999 "0440";
};
}));
};
diff --git a/modules/nixos/clicks/security/secrets/instability/default.nix b/modules/nixos/clicks/security/secrets/instability/default.nix
index f1362a4..e276c13 100644
--- a/modules/nixos/clicks/security/secrets/instability/default.nix
+++ b/modules/nixos/clicks/security/secrets/instability/default.nix
@@ -20,6 +20,9 @@
secrets = lib.mkOption {
type = lib.types.attrsOf (lib.types.submodule (submodule: {
options = {
+ name = lib.mkOption {
+ type = lib.types.str;
+ };
unstableName = lib.mkOption {
type = lib.types.bool;
default = config.clicks.security.secrets.instability.enable;
@@ -38,12 +41,12 @@
'';
};
};
- config = {
+ config = lib.mkIf submodule.config.unstableName {
# Calculate the name as the sha256 hash of the rekeyFile or file... whichever happens to exist for this secret
name = let
dependency = submodule.config.rekeyFile or submodule.config.file;
hash = builtins.hashFile "sha256" dependency;
- in lib.mkIf submodule.config.unstableName hash;
+ in hash;
};
}));
};
diff --git a/modules/nixos/clicks/storage/impermanence/default.nix b/modules/nixos/clicks/storage/impermanence/default.nix
index 646e7b5..7d2a94b 100644
--- a/modules/nixos/clicks/storage/impermanence/default.nix
+++ b/modules/nixos/clicks/storage/impermanence/default.nix
@@ -64,7 +64,7 @@
};
};
- config = lib.mkIf cfg.enable {
+ config = lib.mkIf cfg.enable ({
boot.initrd.postDeviceCommands = lib.mkAfter ''
mkdir /impermanent_fs
mount ${cfg.devices.root} /impermanent_fs
@@ -102,18 +102,20 @@
neededForBoot = true;
fsType = "btrfs";
};
-
- environment.persistence."/persist/${cfg.volumes.persistent_data}" = {
- directories = [
- "/var/lib/nixos" # https://github.com/nix-community/impermanence/issues/178
- ] ++ cfg.persist.directories;
- files = [
- "/etc/machine-id"
- "/etc/ssh/ssh_host_ed25519_key"
- "/etc/ssh/ssh_host_ed25519_key.pub"
- "/etc/ssh/ssh_host_rsa_key"
- "/etc/ssh/ssh_host_rsa_key.pub"
- ] ++ cfg.persist.files;
+ } // {
+ environment = lib.optionalAttrs cfg.enable {
+ persistence."/persist/${cfg.volumes.persistent_data}" = {
+ directories = [
+ "/var/lib/nixos" # https://github.com/nix-community/impermanence/issues/178
+ ] ++ cfg.persist.directories;
+ files = [
+ "/etc/machine-id"
+ "/etc/ssh/ssh_host_ed25519_key"
+ "/etc/ssh/ssh_host_ed25519_key.pub"
+ "/etc/ssh/ssh_host_rsa_key"
+ "/etc/ssh/ssh_host_rsa_key.pub"
+ ] ++ cfg.persist.files;
+ };
};
- };
+ });
}