nixos/nextcloud: Allow disabling initial admin user creation on Nextcloud >= 32 (#418378)

This commit is contained in:
Maximilian Bosch 2025-10-27 11:24:44 +00:00 committed by GitHub
commit c3615b0f5d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 103 additions and 26 deletions

View file

@ -647,7 +647,7 @@ in
'';
};
adminuser = lib.mkOption {
type = lib.types.str;
type = lib.types.nullOr lib.types.str;
default = "root";
description = ''
Username for the admin account. The username is only set during the
@ -656,7 +656,7 @@ in
'';
};
adminpassFile = lib.mkOption {
type = lib.types.str;
type = lib.types.nullOr lib.types.str;
description = ''
The full path to a file that contains the admin's password. The password is
set only in the initial setup of Nextcloud by the systemd service `nextcloud-setup.service`.
@ -1124,6 +1124,26 @@ in
https://docs.nextcloud.com/server/latest/admin_manual/configuration_database/db_conversion.html
'';
}
{
assertion =
lib.versionAtLeast overridePackage.version "32.0.0"
|| (cfg.config.adminuser != null && cfg.config.adminpassFile != null);
message = ''
Disabling initial admin user creation is only available on Nextcloud >= 32.0.0.
'';
}
{
assertion = cfg.config.adminuser == null -> cfg.config.adminpassFile == null;
message = ''
If `services.nextcloud.config.adminuser` is null, `services.nextcloud.config.adminpassFile` must be null as well in order to disable initial admin user creation.
'';
}
{
assertion = cfg.config.adminpassFile == null -> cfg.config.adminuser == null;
message = ''
If `services.nextcloud.config.adminpassFile` is null, `services.nextcloud.config.adminuser` must be null as well in order to disable initial admin user creation.
'';
}
];
}
@ -1167,10 +1187,14 @@ in
arg = "DBPASS";
value = if c.dbpassFile != null then ''"$(<"$CREDENTIALS_DIRECTORY/dbpass")"'' else ''""'';
};
adminpass = {
arg = "ADMINPASS";
value = ''"$(<"$CREDENTIALS_DIRECTORY/adminpass")"'';
};
adminpass =
if c.adminpassFile != null then
{
arg = "ADMINPASS";
value = ''"$(<"$CREDENTIALS_DIRECTORY/adminpass")"'';
}
else
null;
installFlags = lib.concatStringsSep " \\\n " (
lib.mapAttrsToList (k: v: "${k} ${toString v}") {
"--database" = ''"${c.dbtype}"'';
@ -1181,15 +1205,16 @@ in
${if c.dbhost != null then "--database-host" else null} = ''"${c.dbhost}"'';
${if c.dbuser != null then "--database-user" else null} = ''"${c.dbuser}"'';
"--database-pass" = "\"\$${dbpass.arg}\"";
"--admin-user" = ''"${c.adminuser}"'';
"--admin-pass" = "\"\$${adminpass.arg}\"";
${if c.adminuser != null then "--admin-user" else null} = ''"${c.adminuser}"'';
${if adminpass != null then "--admin-pass" else null} = "\"\$${adminpass.arg}\"";
${if c.adminuser == null && adminpass == null then "--disable-admin-user" else null} = "";
"--data-dir" = ''"${datadir}/data"'';
}
);
in
''
${mkExport dbpass}
${mkExport adminpass}
${lib.optionalString (adminpass != null) (mkExport adminpass)}
${lib.getExe occ} maintenance:install \
${installFlags}
'';
@ -1216,10 +1241,12 @@ in
exit 1
fi
''}
if [ -z "$(<"$CREDENTIALS_DIRECTORY/adminpass")" ]; then
echo "adminpassFile ${c.adminpassFile} is empty!"
exit 1
fi
${lib.optionalString (c.adminpassFile != null) ''
if [ -z "$(<"$CREDENTIALS_DIRECTORY/adminpass")" ]; then
echo "adminpassFile ${c.adminpassFile} is empty!"
exit 1
fi
''}
# Check if systemd-tmpfiles setup worked correctly
if [[ ! -O "${datadir}/config" ]]; then
@ -1261,10 +1288,9 @@ in
'';
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
serviceConfig.LoadCredential = [
"adminpass:${cfg.config.adminpassFile}"
]
++ runtimeSystemdCredentials;
serviceConfig.LoadCredential =
lib.optional (cfg.config.adminpassFile != null) "adminpass:${cfg.config.adminpassFile}"
++ runtimeSystemdCredentials;
# On Nextcloud ≥ 26, it is not necessary to patch the database files to prevent
# an automatic creation of the database user.
environment.NC_setup_create_db_user = "false";

View file

@ -30,8 +30,8 @@ let
}
];
adminuser = "root";
adminpass = "hunter2";
adminuser = pkgs.lib.mkDefault "root";
adminpass = pkgs.lib.mkDefault "hunter2";
test-helpers.rclone = "${pkgs.writeShellScript "rclone" ''
set -euo pipefail
@ -129,13 +129,16 @@ let
}
);
in
map callNextcloudTest [
./basic.nix
./with-declarative-redis-and-secrets.nix
./with-mysql-and-memcached.nix
./with-postgresql-and-redis.nix
./with-objectstore.nix
];
map callNextcloudTest (
[
./basic.nix
./with-declarative-redis-and-secrets.nix
./with-mysql-and-memcached.nix
./with-postgresql-and-redis.nix
./with-objectstore.nix
]
++ (pkgs.lib.optional (version >= 32) ./without-admin-user.nix)
);
in
listToAttrs (
concatMap genTests [

View file

@ -0,0 +1,48 @@
{
name,
pkgs,
testBase,
system,
...
}:
with import ../../lib/testing-python.nix { inherit system pkgs; };
runTest (
{
config,
lib,
...
}:
rec {
inherit name;
meta.maintainers = lib.teams.nextcloud.members;
imports = [ testBase ];
nodes = {
nextcloud =
{ config, pkgs, ... }:
{
services.nextcloud = {
config = {
dbtype = "sqlite";
adminuser = null;
adminpassFile = lib.mkForce null;
};
};
};
};
adminuser = "root";
# This needs to be a "secure" password, since the password_policy app is enabled after installation and will forbid "simple" passwords.
adminpass = "+CVpTwaOEktxsFc6";
# Manually create the adminuser to make the default set of tests pass.
# If adminuser was already created during the installation this command would not succeed.
# This user name must always match the default value in services.nextcloud.config.adminuser!
test-helpers.init = ''
nextcloud.succeed("OC_PASS=${adminpass} nextcloud-occ user:add ${adminuser} --password-from-env")
'';
}
)