nixos/kanidm: merge recursively with extraJsonFile

Previously, if you set group memberships in both locations, they will
get replaced by the ones in extraJsonFile, which is unexpected as it
kicks users from the group. Now the state files get merged recursively,
including the arrays.
This commit is contained in:
Ilan Joselevich 2025-05-27 18:06:34 +03:00
parent 84937b29d6
commit 3b6b50dfad
No known key found for this signature in database
2 changed files with 46 additions and 4 deletions

View file

@ -185,7 +185,9 @@ let
finalJson =
if cfg.provision.extraJsonFile != null then
"<(${lib.getExe pkgs.jq} -s '.[0] * .[1]' ${provisionStateJson} ${cfg.provision.extraJsonFile})"
''
<(${lib.getExe pkgs.yq-go} '. *+ load("${cfg.provision.extraJsonFile}") | (.. | select(type == "!!seq")) |= unique' ${provisionStateJson})
''
else
provisionStateJson;
@ -442,10 +444,8 @@ in
description = ''
A JSON file for provisioning persons, groups & systems.
Options set in this file take precedence over values set using the other options.
In the case of duplicates, `jq` will remove all but the last one
when merging this file with the options.
The files get deeply merged, and deduplicated.
The accepted JSON schema can be found at <https://github.com/oddlama/kanidm-provision#json-schema>.
Note: theoretically `jq` cannot merge nested types, but this does not pose an issue as kanidm-provision's JSON scheme does not use nested types.
'';
type = types.nullOr types.path;
default = null;

View file

@ -234,6 +234,29 @@ in
};
};
specialisation.extraJsonFile.configuration =
{ ... }:
{
services.kanidm.provision = lib.mkForce {
enable = true;
idmAdminPasswordFile = pkgs.writeText "idm-admin-pw" provisionIdmAdminPassword;
extraJsonFile = pkgs.writeText "extra-json.json" (
builtins.toJSON {
persons.testuser2.displayName = "Test User 2";
groups.testgroup1.members = [ "testuser2" ];
}
);
groups.testgroup1 = { };
persons.testuser1 = {
displayName = "Test User 1";
groups = [ "testgroup1" ];
};
};
};
security.pki.certificateFiles = [ certs.ca.cert ];
networking.hosts."::1" = [ serverDomain ];
@ -515,6 +538,25 @@ in
out = provision.succeed("kanidm system oauth2 get service2")
assert_lacks(out, "name: service2")
provision.succeed("kanidm logout -D idm_admin")
with subtest("Test Provisioning - extraJsonFile"):
provision.succeed('${specialisations}/extraJsonFile/bin/switch-to-configuration test')
provision_login("${provisionIdmAdminPassword}")
out = provision.succeed("kanidm group get testgroup1")
assert_contains(out, "name: testgroup1")
out = provision.succeed("kanidm person get testuser1")
assert_contains(out, "name: testuser1")
out = provision.succeed("kanidm person get testuser2")
assert_contains(out, "name: testuser2")
out = provision.succeed("kanidm group get testgroup1")
assert_contains(out, "member: testuser1")
assert_contains(out, "member: testuser2")
provision.succeed("kanidm logout -D idm_admin")
'';
}