How to modify module default option instead of redefine

Specifically, this is when the options attribute is not set for the module but value is. For example, I need to add an entry to services.openssh.settings.Macs but I can’t seem to set it such that it includes the modules’s default list.

Typically I would reference the module default option like this:

Macs = ++ [ "MyValue" ];

But that attribute doesn’t exist, instead value does.

Macs = ++ [ "MyValue" ];

But this results in infinite recursion. Is there a lib function that just makes any assignment a merge instead of a re-assignment? I’ve tried some of the mkMerge, mkOrder, etc. but I don’t think any work like this.

Looking at the Modularity section in the manual, it seems this is achieved by mkBefore:

Macs = lib.mkBefore [ "MyValue" ];

Not 100% sure this works, I’m not on a NixOS system right now.

I think you want to use lib.mkOptionDefault

@Sandro Jup, you’re right. I tried it out in the repl:

$ nix repl
Welcome to Nix 2.15.1. Type :? for help.

nix-repl> :lf nixpkgs
Added 15 variables.

nix-repl> conf = lib.nixosSystem { 
            modules = [ 
              ({ config, pkgs, lib, options, ... }: 
                nixpkgs.system = "aarch64-linux";
                services.openssh = { 
                  enable = true;
                  settings.Macs = lib.mkOptionDefault [ "AAAAA" ]; 

[ "" "" "" "AAAAA" ]

But you can combine it with mkBefore in case the order matters. Changing the relevant line above:

settings.Macs = lib.mkOptionDefault (lib.mkBefore [ "AAAAA" ]);

Results in this output:

[ "AAAAA" "" "" "" ]

This is super under-documented, and reading through the code didn’t help at all, either.

Interesting. I guess this means the 23.05 Release Notes notes are a little misleading since the example would set the MACs to only what is listed instead of adding.

I’ll have to test mkOptionDefault a bit more. i think if you had another but regular MACs = [ "AA" ] assignment (e.g. in separate files that are recursively merged) then it would silently override both the module default and mkOptionDefault instead of throwing due to conflicting definitions. (For now I’m just adding my own check via config.asserts.)