Merge: nixos/nextcloud: use LoadCredential to read secrets (#367433)

This commit is contained in:
Maximilian Bosch
2025-03-07 10:58:29 +01:00
committed by GitHub
8 changed files with 240 additions and 131 deletions
@@ -310,6 +310,8 @@
- `hardware.pulseaudio` has been renamed to `services.pulseaudio`. The deprecated option names will continue to work, but causes a warning.
- `services.nextcloud` now uses systemd's credential mechanism to read in secret files. The `nextcloud-occ` wrapper script implements this using `systemd-run`, as such it now also requires root privileges or `$CREDENTIALS_DIRECTORY` set where running it as user `nextcloud` was enough previously.
- `minetest` has been renamed to `luanti` to match the upstream name change but aliases have been added. The new name hasn't resulted in many changes as of yet but older references to minetest should be sunset. See the [new name announcement](https://blog.minetest.net/2024/10/13/Introducing-Our-New-Name/) for more details.
- `poac` has been renamed to `cabinpkg` to match the upstream name change but an alias has been added. See the [new name announcement](https://github.com/orgs/cabinpkg/discussions/1052) for more details.
@@ -78,60 +78,75 @@ in
);
config = lib.mkIf cfg.enable {
systemd.services.nextcloud-notify_push = {
description = "Push daemon for Nextcloud clients";
documentation = [ "https://github.com/nextcloud/notify_push" ];
after = [
"phpfpm-nextcloud.service"
"redis-nextcloud.service"
];
wantedBy = [ "multi-user.target" ];
environment = {
NEXTCLOUD_URL = cfg.nextcloudUrl;
SOCKET_PATH = cfg.socketPath;
DATABASE_PREFIX = cfg.dbtableprefix;
LOG = cfg.logLevel;
systemd.services = {
nextcloud-notify_push = {
description = "Push daemon for Nextcloud clients";
documentation = [ "https://github.com/nextcloud/notify_push" ];
after = [
"phpfpm-nextcloud.service"
"redis-nextcloud.service"
];
wantedBy = [ "multi-user.target" ];
environment = {
NEXTCLOUD_URL = cfg.nextcloudUrl;
SOCKET_PATH = cfg.socketPath;
DATABASE_PREFIX = cfg.dbtableprefix;
LOG = cfg.logLevel;
};
script =
let
dbType = if cfg.dbtype == "pgsql" then "postgresql" else cfg.dbtype;
dbUser = lib.optionalString (cfg.dbuser != null) cfg.dbuser;
dbPass = lib.optionalString (cfg.dbpassFile != null) ":$DATABASE_PASSWORD";
dbHostHasPrefix = prefix: lib.hasPrefix prefix (toString cfg.dbhost);
isPostgresql = dbType == "postgresql";
isMysql = dbType == "mysql";
isSocket = (isPostgresql && dbHostHasPrefix "/") || (isMysql && dbHostHasPrefix "localhost:/");
dbHost = lib.optionalString (cfg.dbhost != null) (
if isSocket then lib.optionalString isMysql "@localhost" else "@${cfg.dbhost}"
);
dbOpts = lib.optionalString (cfg.dbhost != null && isSocket) (
if isPostgresql then
"?host=${cfg.dbhost}"
else if isMysql then
"?socket=${lib.removePrefix "localhost:" cfg.dbhost}"
else
throw "unsupported dbtype"
);
dbName = lib.optionalString (cfg.dbname != null) "/${cfg.dbname}";
dbUrl = "${dbType}://${dbUser}${dbPass}${dbHost}${dbName}${dbOpts}";
in
lib.optionalString (cfg.dbpassFile != null) ''
export DATABASE_PASSWORD="$(<"$CREDENTIALS_DIRECTORY/dbpass")"
''
+ ''
export DATABASE_URL="${dbUrl}"
exec ${cfg.package}/bin/notify_push '${cfgN.datadir}/config/config.php'
'';
serviceConfig = {
User = "nextcloud";
Group = "nextcloud";
RuntimeDirectory = [ "nextcloud-notify_push" ];
Restart = "on-failure";
RestartSec = "5s";
Type = "notify";
LoadCredential = lib.optional (cfg.dbpassFile != null) "dbpass:${cfg.dbpassFile}";
};
};
postStart = ''
${cfgN.occ}/bin/nextcloud-occ notify_push:setup ${cfg.nextcloudUrl}/push
'';
script =
let
dbType = if cfg.dbtype == "pgsql" then "postgresql" else cfg.dbtype;
dbUser = lib.optionalString (cfg.dbuser != null) cfg.dbuser;
dbPass = lib.optionalString (cfg.dbpassFile != null) ":$DATABASE_PASSWORD";
dbHostHasPrefix = prefix: lib.hasPrefix prefix (toString cfg.dbhost);
isPostgresql = dbType == "postgresql";
isMysql = dbType == "mysql";
isSocket = (isPostgresql && dbHostHasPrefix "/") || (isMysql && dbHostHasPrefix "localhost:/");
dbHost = lib.optionalString (cfg.dbhost != null) (
if isSocket then lib.optionalString isMysql "@localhost" else "@${cfg.dbhost}"
);
dbOpts = lib.optionalString (cfg.dbhost != null && isSocket) (
if isPostgresql then
"?host=${cfg.dbhost}"
else if isMysql then
"?socket=${lib.removePrefix "localhost:" cfg.dbhost}"
else
throw "unsupported dbtype"
);
dbName = lib.optionalString (cfg.dbname != null) "/${cfg.dbname}";
dbUrl = "${dbType}://${dbUser}${dbPass}${dbHost}${dbName}${dbOpts}";
in
lib.optionalString (dbPass != "") ''
export DATABASE_PASSWORD="$(<"${cfg.dbpassFile}")"
''
+ ''
export DATABASE_URL="${dbUrl}"
exec ${cfg.package}/bin/notify_push '${cfgN.datadir}/config/config.php'
'';
serviceConfig = {
User = "nextcloud";
Group = "nextcloud";
RuntimeDirectory = [ "nextcloud-notify_push" ];
Restart = "on-failure";
RestartSec = "5s";
Type = "notify";
nextcloud-notify_push_setup = {
wantedBy = [ "multi-user.target" ];
requiredBy = [ "nextcloud-notify_push.service" ];
after = [ "nextcloud-notify_push.service" ];
serviceConfig = {
Type = "oneshot";
User = "nextcloud";
Group = "nextcloud";
ExecStart = "${lib.getExe cfgN.occ} notify_push:setup ${cfg.nextcloudUrl}/push";
LoadCredential = config.systemd.services.nextcloud-cron.serviceConfig.LoadCredential;
RestartMode = "direct";
Restart = "on-failure";
};
};
};
+141 -65
View File
@@ -85,18 +85,60 @@ let
"-dmemory_limit=${cfg.cli.memoryLimit}"
]);
occ = pkgs.writeScriptBin "nextcloud-occ" ''
#! ${pkgs.runtimeShell}
cd ${webroot}
sudo=exec
if [[ "$USER" != nextcloud ]]; then
sudo='exec /run/wrappers/bin/sudo -u nextcloud'
fi
$sudo ${pkgs.coreutils}/bin/env \
NEXTCLOUD_CONFIG_DIR="${datadir}/config" \
${phpCli} \
occ "$@"
'';
# NOTE: The credentials required by all services at runtime, not including things like the
# admin password which is only needed by the setup service.
runtimeSystemdCredentials = []
++ (lib.optional (cfg.config.dbpassFile != null) "dbpass:${cfg.config.dbpassFile}")
++ (lib.optional (cfg.config.objectstore.s3.enable) "s3_secret:${cfg.config.objectstore.s3.secretFile}")
++ (lib.optional (cfg.config.objectstore.s3.sseCKeyFile != null) "s3_sse_c_key:${cfg.config.objectstore.s3.sseCKeyFile}");
requiresRuntimeSystemdCredentials = (lib.length runtimeSystemdCredentials) != 0;
occ = pkgs.writeShellApplication {
name = "nextcloud-occ";
text = let
command = ''
${lib.getExe' pkgs.coreutils "env"} \
NEXTCLOUD_CONFIG_DIR="${datadir}/config" \
${phpCli} \
occ "$@"
'';
in ''
cd ${webroot}
# NOTE: This is templated at eval time
requiresRuntimeSystemdCredentials=${lib.boolToString requiresRuntimeSystemdCredentials}
# NOTE: This wrapper is both used in the internal nextcloud service units
# and by users outside a service context for administration. As such,
# when there's an existing CREDENTIALS_DIRECTORY, we inherit it for use
# in the nix_read_secret() php function.
# When there's no CREDENTIALS_DIRECTORY we try to use systemd-run to
# load the credentials just as in a service unit.
# NOTE: If there are no credentials that are required at runtime then there's no need
# to load any credentials.
if [[ $requiresRuntimeSystemdCredentials == true && -z "''${CREDENTIALS_DIRECTORY:-}" ]]; then
exec ${lib.getExe' config.systemd.package "systemd-run"} \
${lib.escapeShellArgs (map (credential: "--property=LoadCredential=${credential}") runtimeSystemdCredentials)} \
--uid=nextcloud \
--same-dir \
--pty \
--wait \
--collect \
--service-type=exec \
--quiet \
${command}
elif [[ "$USER" != nextcloud ]]; then
exec /run/wrappers/bin/sudo \
--preserve-env=CREDENTIALS_DIRECTORY \
--user=nextcloud \
${command}
else
exec ${command}
fi
'';
};
inherit (config.system) stateVersion;
@@ -120,13 +162,13 @@ let
'bucket' => '${s3.bucket}',
'autocreate' => ${boolToString s3.autocreate},
'key' => '${s3.key}',
'secret' => nix_read_secret('${s3.secretFile}'),
'secret' => nix_read_secret('s3_secret'),
${optionalString (s3.hostname != null) "'hostname' => '${s3.hostname}',"}
${optionalString (s3.port != null) "'port' => ${toString s3.port},"}
'use_ssl' => ${boolToString s3.useSsl},
${optionalString (s3.region != null) "'region' => '${s3.region}',"}
'use_path_style' => ${boolToString s3.usePathStyle},
${optionalString (s3.sseCKeyFile != null) "'sse_c_key' => nix_read_secret('${s3.sseCKeyFile}'),"}
${optionalString (s3.sseCKeyFile != null) "'sse_c_key' => nix_read_secret('s3_sse_c_key'),"}
],
]
'';
@@ -143,16 +185,26 @@ let
in pkgs.writeText "nextcloud-config.php" ''
<?php
${optionalString requiresReadSecretFunction ''
function nix_read_secret($file) {
if (!file_exists($file)) {
throw new \RuntimeException(sprintf(
"Cannot start Nextcloud, secret file %s set by NixOS doesn't seem to "
. "exist! Please make sure that the file exists and has appropriate "
. "permissions for user & group 'nextcloud'!",
$file
function nix_read_secret($credential_name) {
$credentials_directory = getenv("CREDENTIALS_DIRECTORY");
if (!$credentials_directory) {
error_log(sprintf(
"Cannot read credential '%s' passed by NixOS, \$CREDENTIALS_DIRECTORY is not set!",
$credential_name
));
exit(1);
}
return trim(file_get_contents($file));
$credential_path = $credentials_directory . "/" . $credential_name;
if (!is_readable($credential_path)) {
error_log(sprintf(
"Cannot read credential '%s' passed by NixOS, it does not exist or is not readable!",
$credential_path,
));
exit(1);
}
return trim(file_get_contents($credential_path));
}''}
function nix_decode_json_file($file, $error) {
if (!file_exists($file)) {
@@ -176,12 +228,7 @@ let
${optionalString (c.dbhost != null) "'dbhost' => '${c.dbhost}',"}
${optionalString (c.dbuser != null) "'dbuser' => '${c.dbuser}',"}
${optionalString (c.dbtableprefix != null) "'dbtableprefix' => '${toString c.dbtableprefix}',"}
${optionalString (c.dbpassFile != null) ''
'dbpassword' => nix_read_secret(
"${c.dbpassFile}"
),
''
}
${optionalString (c.dbpassFile != null) "'dbpassword' => nix_read_secret('dbpass'),"}
'dbtype' => '${c.dbtype}',
${objectstoreConfig}
];
@@ -490,9 +537,8 @@ in {
adminpassFile = mkOption {
type = types.str;
description = ''
The full path to a file that contains the admin's password. Must be
readable by user `nextcloud`. The password is set only in the initial
setup of Nextcloud by the systemd service `nextcloud-setup.service`.
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`.
'';
};
objectstore = {
@@ -530,8 +576,7 @@ in {
type = types.str;
example = "/var/nextcloud-objectstore-s3-secret";
description = ''
The full path to a file that contains the access secret. Must be
readable by user `nextcloud`.
The full path to a file that contains the access secret.
'';
};
hostname = mkOption {
@@ -592,8 +637,6 @@ in {
openssl rand 32 | base64
```
Must be readable by user `nextcloud`.
[1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html
'';
};
@@ -944,11 +987,6 @@ in {
services.nextcloud.finalPackage = webroot;
systemd.services = {
# When upgrading the Nextcloud package, Nextcloud can report errors such as
# "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
# Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround).
phpfpm-nextcloud.restartTriggers = [ webroot overrideConfig ];
nextcloud-setup = let
c = cfg.config;
occInstallCmd = let
@@ -959,12 +997,12 @@ in {
dbpass = {
arg = "DBPASS";
value = if c.dbpassFile != null
then ''"$(<"${toString c.dbpassFile}")"''
then ''"$(<"$CREDENTIALS_DIRECTORY/dbpass")"''
else ''""'';
};
adminpass = {
arg = "ADMINPASS";
value = ''"$(<"${toString c.adminpassFile}")"'';
value = ''"$(<"$CREDENTIALS_DIRECTORY/adminpass")"'';
};
installFlags = concatStringsSep " \\\n "
(mapAttrsToList (k: v: "${k} ${toString v}") {
@@ -983,12 +1021,12 @@ in {
in ''
${mkExport dbpass}
${mkExport adminpass}
${occ}/bin/nextcloud-occ maintenance:install \
${lib.getExe occ} maintenance:install \
${installFlags}
'';
occSetTrustedDomainsCmd = concatStringsSep "\n" (imap0
(i: v: ''
${occ}/bin/nextcloud-occ config:system:set trusted_domains \
${lib.getExe occ} config:system:set trusted_domains \
${toString i} --value="${toString v}"
'') ([ cfg.hostName ] ++ cfg.settings.trusted_domains));
@@ -1002,20 +1040,12 @@ in {
restartTriggers = [ overrideConfig ];
script = ''
${optionalString (c.dbpassFile != null) ''
if [ ! -r "${c.dbpassFile}" ]; then
echo "dbpassFile ${c.dbpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.dbpassFile})" ]; then
if [ -z "$(<$CREDENTIALS_DIRECTORY/dbpass)" ]; then
echo "dbpassFile ${c.dbpassFile} is empty!"
exit 1
fi
''}
if [ ! -r "${c.adminpassFile}" ]; then
echo "adminpassFile ${c.adminpassFile} is not readable by nextcloud:nextcloud! Aborting..."
exit 1
fi
if [ -z "$(<${c.adminpassFile})" ]; then
if [ -z "$(<$CREDENTIALS_DIRECTORY/adminpass)" ]; then
echo "adminpassFile ${c.adminpassFile} is empty!"
exit 1
fi
@@ -1032,57 +1062,102 @@ in {
${occInstallCmd}
fi
${occ}/bin/nextcloud-occ upgrade
${lib.getExe occ} upgrade
${occ}/bin/nextcloud-occ config:system:delete trusted_domains
${lib.getExe occ} config:system:delete trusted_domains
${optionalString (cfg.extraAppsEnable && cfg.extraApps != { }) ''
# Try to enable apps
${occ}/bin/nextcloud-occ app:enable ${concatStringsSep " " (attrNames cfg.extraApps)}
${lib.getExe occ} app:enable ${concatStringsSep " " (attrNames cfg.extraApps)}
''}
${occSetTrustedDomainsCmd}
'';
serviceConfig.Type = "oneshot";
serviceConfig.User = "nextcloud";
serviceConfig.LoadCredential = [ "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 = lib.mkIf (nextcloudGreaterOrEqualThan "26") "false";
};
nextcloud-cron = {
after = [ "nextcloud-setup.service" ];
# NOTE: In contrast to the occ wrapper script running phpCli directly will not
# set NEXTCLOUD_CONFIG_DIR by itself currently.
environment.NEXTCLOUD_CONFIG_DIR = "${datadir}/config";
script = ''
# NOTE: This early returns the script when nextcloud is in maintenance mode
# or needs `occ upgrade`. Using ExecCondition= is not possible here
# because it doesn't work with systemd credentials.
if [[ $(${lib.getExe occ} status --output=json | ${lib.getExe pkgs.jq} '. | if .maintenance or .needsDbUpgrade then "skip" else "" end' --raw-output) == "skip" ]]; then
echo "Nextcloud is in maintenance mode or needs DB upgrade, exiting."
exit 0
fi
${phpCli} -f ${webroot}/cron.php
'';
serviceConfig = {
Type = "exec";
User = "nextcloud";
ExecCondition = "${phpCli} -f ${webroot}/occ status -e";
ExecStart = "${phpCli} -f ${webroot}/cron.php";
KillMode = "process";
LoadCredential = runtimeSystemdCredentials;
};
};
nextcloud-update-plugins = mkIf cfg.autoUpdateApps.enable {
after = [ "nextcloud-setup.service" ];
serviceConfig = {
Type = "oneshot";
ExecStart = "${occ}/bin/nextcloud-occ app:update --all";
ExecStart = "${lib.getExe occ} app:update --all";
User = "nextcloud";
LoadCredential = runtimeSystemdCredentials;
};
startAt = cfg.autoUpdateApps.startAt;
};
nextcloud-update-db = {
after = [ "nextcloud-setup.service" ];
environment.NEXTCLOUD_CONFIG_DIR = "${datadir}/config";
script = ''
${occ}/bin/nextcloud-occ db:add-missing-columns
${occ}/bin/nextcloud-occ db:add-missing-indices
${occ}/bin/nextcloud-occ db:add-missing-primary-keys
# NOTE: This early returns the script when nextcloud is in maintenance mode
# or needs `occ upgrade`. Using ExecCondition= is not possible here
# because it doesn't work with systemd credentials.
if [[ $(${lib.getExe occ} status --output=json | ${lib.getExe pkgs.jq} '. | if .maintenance or .needsDbUpgrade then "skip" else "" end' --raw-output) == "skip" ]]; then
echo "Nextcloud is in maintenance mode or needs DB upgrade, exiting."
exit 0
fi
${lib.getExe occ} db:add-missing-columns
${lib.getExe occ} db:add-missing-indices
${lib.getExe occ} db:add-missing-primary-keys
'';
serviceConfig = {
Type = "exec";
User = "nextcloud";
ExecCondition = "${phpCli} -f ${webroot}/occ status -e";
LoadCredential = runtimeSystemdCredentials;
};
};
phpfpm-nextcloud = {
# When upgrading the Nextcloud package, Nextcloud can report errors such as
# "The files of the app [all apps in /var/lib/nextcloud/apps] were not replaced correctly"
# Restarting phpfpm on Nextcloud package update fixes these issues (but this is a workaround).
restartTriggers = [ webroot overrideConfig ];
} // lib.optionalAttrs requiresRuntimeSystemdCredentials {
serviceConfig.LoadCredential = runtimeSystemdCredentials;
# FIXME: We use a hack to make the credential files readable by the nextcloud
# user by copying them somewhere else and overriding CREDENTIALS_DIRECTORY
# for php. This is currently necessary as the unit runs as root.
serviceConfig.RuntimeDirectory = lib.mkForce "phpfpm phpfpm-nextcloud";
preStart = ''
umask 0077
# NOTE: Runtime directories for this service are currently preserved
# between restarts.
rm -rf /run/phpfpm-nextcloud/credentials/
mkdir -p /run/phpfpm-nextcloud/credentials/
cp "$CREDENTIALS_DIRECTORY"/* /run/phpfpm-nextcloud/credentials/
chown -R nextcloud:nextcloud /run/phpfpm-nextcloud/credentials/
'';
};
};
services.phpfpm = {
@@ -1091,6 +1166,7 @@ in {
group = "nextcloud";
phpPackage = phpPackage;
phpEnv = {
CREDENTIALS_DIRECTORY = "/run/phpfpm-nextcloud/credentials/";
NEXTCLOUD_CONFIG_DIR = "${datadir}/config";
PATH = "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin";
};
+2 -2
View File
@@ -8,10 +8,10 @@
with import ../../lib/testing-python.nix { inherit system pkgs; };
runTest (
{ config, ... }:
{ config, lib, ... }:
{
inherit name;
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [
globin
eqyiel
@@ -8,13 +8,13 @@
with import ../../lib/testing-python.nix { inherit system pkgs; };
runTest (
{ config, ... }:
{ config, lib, ... }:
let
inherit (config) adminuser;
in
{
inherit name;
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [
eqyiel
ma27
@@ -34,6 +34,13 @@ runTest (
redis = true;
memcached = false;
};
notify_push = {
enable = true;
bendDomainToLocalhost = true;
logLevel = "debug";
};
extraAppsEnable = true;
extraApps.notify_push = config.services.nextcloud.package.packages.apps.notify_push;
# This test also validates that we can use an "external" database
database.createLocally = false;
config = {
@@ -70,7 +77,7 @@ runTest (
services.postgresql = {
enable = true;
};
systemd.services.postgresql.postStart = pkgs.lib.mkAfter ''
systemd.services.postgresql.postStart = lib.mkAfter ''
password=$(cat ${config.services.nextcloud.config.dbpassFile})
${config.services.postgresql.package}/bin/psql <<EOF
CREATE ROLE ${adminuser} WITH LOGIN PASSWORD '$password' CREATEDB;
@@ -95,7 +102,13 @@ runTest (
test-helpers.extraTests = ''
with subtest("non-empty redis cache"):
# redis cache should not be empty
nextcloud.fail('test 0 -lt "$(redis-cli --pass secret --json KEYS "*" | jq "len")"')
assert nextcloud.succeed('redis-cli --pass secret --json KEYS "*" | jq length').strip() != "0", """
redis-cli for keys * returned 0 entries
"""
with subtest("notify-push"):
client.execute("${lib.getExe pkgs.nextcloud-notify_push.passthru.test_client} http://nextcloud ${config.adminuser} ${config.adminpass} >&2 &")
nextcloud.wait_until_succeeds("journalctl -u nextcloud-notify_push | grep -q \"Sending ping to ${config.adminuser}\"")
'';
}
)
@@ -8,10 +8,10 @@
with import ../../lib/testing-python.nix { inherit system pkgs; };
runTest (
{ config, ... }:
{ config, lib, ... }:
{
inherit name;
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [ eqyiel ];
};
+1 -1
View File
@@ -20,7 +20,7 @@ runTest (
in
{
inherit name;
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [
onny
ma27
@@ -8,10 +8,10 @@
with import ../../lib/testing-python.nix { inherit system pkgs; };
runTest (
{ config, ... }:
{ config, lib, ... }:
{
inherit name;
meta = with pkgs.lib.maintainers; {
meta = with lib.maintainers; {
maintainers = [
eqyiel
ma27
@@ -29,6 +29,7 @@ runTest (
...
}:
{
environment.systemPackages = [ pkgs.jq ];
services.nextcloud = {
caching = {
apcu = false;
@@ -68,12 +69,14 @@ runTest (
test-helpers.extraTests = ''
with subtest("notify-push"):
client.execute("${pkgs.lib.getExe pkgs.nextcloud-notify_push.passthru.test_client} http://nextcloud ${config.adminuser} ${config.adminpass} >&2 &")
client.execute("${lib.getExe pkgs.nextcloud-notify_push.passthru.test_client} http://nextcloud ${config.adminuser} ${config.adminpass} >&2 &")
nextcloud.wait_until_succeeds("journalctl -u nextcloud-notify_push | grep -q \"Sending ping to ${config.adminuser}\"")
with subtest("Redis is used for caching"):
# redis cache should not be empty
nextcloud.fail('test "[]" = "$(redis-cli --json KEYS "*")"')
assert nextcloud.succeed('redis-cli --json KEYS "*" | jq length').strip() != "0", """
redis-cli for keys * returned 0 entries
"""
with subtest("No code is returned when requesting PHP files (regression test)"):
nextcloud.fail("curl -f http://nextcloud/nix-apps/notes/lib/AppInfo/Application.php")