Compare commits

..

6 Commits

Author SHA1 Message Date
Simon L.
e9ab05c5b7 Merge pull request #7571 from nextcloud/aio-helm-update
Helm Chart updates
2026-02-11 15:28:17 +01:00
szaimen
67814f32d8 Helm Chart updates
Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-02-11 14:26:18 +00:00
Simon L.
270ad0ecea fix the update-helm workflow
Signed-off-by: Simon L. <szaimen@e.mail.de>
2026-02-11 15:25:31 +01:00
Simon L.
a803d1c098 Merge pull request #7554 from nextcloud/dependabot/github_actions/dot-github/workflows/astral-sh/setup-uv-7.2.1
build(deps): bump astral-sh/setup-uv from 7.2.0 to 7.2.1 in /.github/workflows
2026-02-06 13:24:29 +01:00
dependabot[bot]
2df9b8af50 build(deps): bump astral-sh/setup-uv in /.github/workflows
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.2.0 to 7.2.1.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](61cb8a9741...803947b9bd)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 7.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-06 12:07:10 +00:00
Simon L.
a16c7e28c2 Clean up pull request template
Removed unnecessary lines from the pull request template.

Signed-off-by: Simon L. <szaimen@e.mail.de>
2026-02-04 23:11:04 +01:00
28 changed files with 63 additions and 178 deletions

View File

@@ -3,6 +3,3 @@
-
- Before sending a pull request that fixes a security issue please report it via our HackerOne page (https://hackerone.com/nextcloud) following our security policy (https://nextcloud.com/security/). This allows us to coordinate the fix and release without potentially exposing all Nextcloud servers and users in the meantime.
-->
* Resolves: # <!-- related github issue -->
* [Sign-off message](https://github.com/src-d/guide/blob/master/developer-community/fix-DCO.md) is added to all commits

View File

@@ -36,7 +36,7 @@ jobs:
line-length: warning
- name: Install the latest version of uv
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7.2.1
- name: Check GitHub actions
run: uvx zizmor --min-severity medium .github/workflows/*.yml

View File

@@ -1,6 +1,6 @@
name: nextcloud-aio-helm-chart
description: A generated Helm Chart for Nextcloud AIO from Skippbox Kompose
version: 12.5.0
version: 12.6.1
apiVersion: v2
keywords:
- latest

View File

@@ -61,7 +61,7 @@ spec:
value: "{{ .Values.TIMEZONE }}"
- name: WHITEBOARD_HOST
value: nextcloud-aio-whiteboard
image: ghcr.io/nextcloud-releases/aio-apache:20260122_105751
image: ghcr.io/nextcloud-releases/aio-apache:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -36,7 +36,7 @@ spec:
{{- end }}
initContainers:
- name: init-subpath
image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
command:
- mkdir
- "-p"
@@ -59,7 +59,7 @@ spec:
value: "{{ .Values.NEXTCLOUD_UPLOAD_LIMIT }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-clamav:20260122_105751
image: ghcr.io/nextcloud-releases/aio-clamav:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -36,9 +36,9 @@ spec:
- name: server_name
value: "{{ .Values.NC_DOMAIN }}"
{{- if contains "--o:support_key=" (join " " (.Values.ADDITIONAL_COLLABORA_OPTIONS | default list)) }}
image: ghcr.io/nextcloud-releases/aio-collabora-online:20260122_105751
image: ghcr.io/nextcloud-releases/aio-collabora-online:20260211_141900
{{- else }}
image: ghcr.io/nextcloud-releases/aio-collabora:20260122_105751
image: ghcr.io/nextcloud-releases/aio-collabora:20260211_141900
{{- end }}
readinessProbe:
exec:

View File

@@ -35,7 +35,7 @@ spec:
{{- end }}
initContainers:
- name: init-subpath
image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
command:
- mkdir
- "-p"
@@ -64,7 +64,7 @@ spec:
value: nextcloud
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-postgresql:20260122_105751
image: ghcr.io/nextcloud-releases/aio-postgresql:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -24,7 +24,7 @@ spec:
spec:
initContainers:
- name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
command:
- chmod
- "777"
@@ -54,7 +54,7 @@ spec:
value: basic
- name: xpack.security.enabled
value: "false"
image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260122_105751
image: ghcr.io/nextcloud-releases/aio-fulltextsearch:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -38,7 +38,7 @@ spec:
value: "{{ .Values.IMAGINARY_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-imaginary:20260122_105751
image: ghcr.io/nextcloud-releases/aio-imaginary:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -38,7 +38,7 @@ spec:
# AIO settings start # Do not remove or change this line!
initContainers:
- name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
command:
- chmod
- "777"
@@ -190,7 +190,7 @@ spec:
value: "{{ .Values.WHITEBOARD_ENABLED }}"
- name: WHITEBOARD_SECRET
value: "{{ .Values.WHITEBOARD_SECRET }}"
image: ghcr.io/nextcloud-releases/aio-nextcloud:20260122_105751
image: ghcr.io/nextcloud-releases/aio-nextcloud:20260211_141900
{{- if eq (.Values.RPSS_ENABLED | default "no") "yes" }} # AIO-config - do not change this comment!
securityContext:
# The items below only work in container context

View File

@@ -57,7 +57,7 @@ spec:
value: "6379"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-notify-push:20260122_105751
image: ghcr.io/nextcloud-releases/aio-notify-push:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -24,7 +24,7 @@ spec:
spec:
initContainers:
- name: init-volumes
image: ghcr.io/nextcloud-releases/aio-alpine:20260122_105751
image: ghcr.io/nextcloud-releases/aio-alpine:20260211_141900
command:
- chmod
- "777"
@@ -42,7 +42,7 @@ spec:
value: "{{ .Values.ONLYOFFICE_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260122_105751
image: ghcr.io/nextcloud-releases/aio-onlyoffice:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -39,7 +39,7 @@ spec:
value: "{{ .Values.REDIS_PASSWORD }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-redis:20260122_105751
image: ghcr.io/nextcloud-releases/aio-redis:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -52,7 +52,7 @@ spec:
value: "{{ .Values.TURN_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-talk:20260122_105751
image: ghcr.io/nextcloud-releases/aio-talk:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -44,7 +44,7 @@ spec:
value: "{{ .Values.RECORDING_SECRET }}"
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-talk-recording:20260122_105751
image: ghcr.io/nextcloud-releases/aio-talk-recording:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -50,7 +50,7 @@ spec:
value: redis
- name: TZ
value: "{{ .Values.TIMEZONE }}"
image: ghcr.io/nextcloud-releases/aio-whiteboard:20260122_105751
image: ghcr.io/nextcloud-releases/aio-whiteboard:20260211_141900
readinessProbe:
exec:
command:

View File

@@ -407,7 +407,7 @@ rm latest.yml
mv latest.yml.backup latest.yml
# Get version of AIO
AIO_VERSION="$(grep 'Nextcloud AIO ' ../php/templates/includes/aio-version.twig | grep -oP '[0-9]+.[0-9]+.[0-9]+')"
AIO_VERSION="$(grep -oP '[0-9]+.[0-9]+.[0-9]+' ../php/templates/includes/aio-version.twig)"
sed -i "s|^version:.*|version: $AIO_VERSION|" ../helm-chart/Chart.yaml
# Conversion of sample.conf

View File

@@ -1,38 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="6.14.3@d0b040a91f280f071c1abcb1b77ce3822058725a">
<file src="public/index.php">
<MixedArgument>
<code><![CDATA[$container->get(Guard::class)]]></code>
<code><![CDATA[$container->get(\AIO\Auth\AuthManager::class)]]></code>
<code><![CDATA[$container->get(\AIO\Data\ConfigurationManager::class)]]></code>
</MixedArgument>
</file>
<file src="src/ContainerDefinitionFetcher.php">
<MixedArgumentTypeCoercion>
<code><![CDATA[$backupVolumes]]></code>
<code><![CDATA[$capAdd]]></code>
<code><![CDATA[$devices]]></code>
</MixedArgumentTypeCoercion>
</file>
<file src="src/Controller/ConfigurationController.php">
<PossiblyNullIterator>
<code><![CDATA[$request->getParsedBody()]]></code>
</PossiblyNullIterator>
</file>
<file src="src/DependencyInjection.php">
<MixedArgument>
<code><![CDATA[$container->get(DockerHubManager::class)]]></code>
<code><![CDATA[$container->get(GitHubContainerRegistryManager::class)]]></code>
<code><![CDATA[$container->get(\AIO\Auth\PasswordGenerator::class)]]></code>
<code><![CDATA[$container->get(\AIO\ContainerDefinitionFetcher::class)]]></code>
<code><![CDATA[$container->get(\AIO\Data\ConfigurationManager::class)]]></code>
<code><![CDATA[$container->get(\AIO\Data\ConfigurationManager::class)]]></code>
<code><![CDATA[$container->get(\AIO\Data\ConfigurationManager::class)]]></code>
</MixedArgument>
</file>
<file src="src/Docker/DockerActionManager.php">
<MixedOperand>
<code><![CDATA[$output['Config']['Image']]]></code>
</MixedOperand>
</file>
</files>
<files psalm-version="6.14.3@d0b040a91f280f071c1abcb1b77ce3822058725a"/>

View File

@@ -6,7 +6,6 @@
errorBaseline="psalm-baseline.xml"
findUnusedBaselineEntry="true"
findUnusedCode="false"
errorLevel="1"
>
<projectFiles>
<directory name="templates"/>

View File

@@ -20,9 +20,7 @@ use Psr\Http\Message\ServerRequestInterface as Request;
require __DIR__ . '/../vendor/autoload.php';
/** @var \DI\Container */
$container = \AIO\DependencyInjection::GetContainer();
/** @var \AIO\Data\DataConst */
$dataConst = $container->get(\AIO\Data\DataConst::class);
ini_set('session.save_path', $dataConst->GetSessionDirectory());

View File

@@ -22,10 +22,8 @@ readonly class ContainerDefinitionFetcher {
public function GetContainerById(string $id): Container
{
/** @var array */
$containers = $this->FetchDefinition();
/** @psalm-var \AIO\Container\Container $container */
foreach ($containers as $container) {
if ($container->identifier === $id) {
return $container;
@@ -40,26 +38,22 @@ readonly class ContainerDefinitionFetcher {
*/
private function GetDefinition(): array
{
/** @psalm-var array $data */
$data = json_decode((string)file_get_contents(DataConst::GetContainersDefinitionPath()), true, 512, JSON_THROW_ON_ERROR);
$additionalContainerNames = [];
/** @psalm-var string $communityContainer */
foreach ($this->configurationManager->aioCommunityContainers as $communityContainer) {
if ($communityContainer !== '') {
$path = DataConst::GetCommunityContainersDirectory() . '/' . $communityContainer . '/' . $communityContainer . '.json';
/** @psalm-var array $additionalData */
$additionalData = json_decode((string)file_get_contents($path), true, 512, JSON_THROW_ON_ERROR);
$data = array_merge_recursive($data, $additionalData);
if (isset($additionalData['aio_services_v1'][0]['display_name']) && $additionalData['aio_services_v1'][0]['display_name'] !== '') {
// Store container_name of community containers in variable for later
$additionalContainerNames[] = (string) $additionalData['aio_services_v1'][0]['container_name'];
$additionalContainerNames[] = $additionalData['aio_services_v1'][0]['container_name'];
}
}
}
$containers = [];
/** @psalm-var array $entry */
foreach ($data['aio_services_v1'] as $entry) {
if ($entry['container_name'] === 'nextcloud-aio-clamav') {
if (!$this->configurationManager->isClamavEnabled) {
@@ -104,13 +98,12 @@ readonly class ContainerDefinitionFetcher {
$ports = new ContainerPorts();
if (isset($entry['ports'])) {
/** @psalm-var array $value */
foreach ($entry['ports'] as $value) {
$ports->AddPort(
new ContainerPort(
(string) $value['port_number'],
(string) $value['ip_binding'],
(string) $value['protocol']
$value['port_number'],
$value['ip_binding'],
$value['protocol']
)
);
}
@@ -118,7 +111,6 @@ readonly class ContainerDefinitionFetcher {
$volumes = new ContainerVolumes();
if (isset($entry['volumes'])) {
/** @psalm-var array $value */
foreach ($entry['volumes'] as $value) {
if($value['source'] === '%BORGBACKUP_HOST_LOCATION%') {
$value['source'] = $this->configurationManager->borgBackupHostLocation;
@@ -155,9 +147,9 @@ readonly class ContainerDefinitionFetcher {
}
$volumes->AddVolume(
new ContainerVolume(
(string) $value['source'],
(string) $value['destination'],
(bool) $value['writeable']
$value['source'],
$value['destination'],
$value['writeable']
)
);
}
@@ -165,18 +157,15 @@ readonly class ContainerDefinitionFetcher {
$dependsOn = [];
if (isset($entry['depends_on'])) {
/** @var array */
$valueDependsOn = $entry['depends_on'];
if ($entry['container_name'] === 'nextcloud-aio-apache') {
// Add community containers first and default ones last so that aio_variables works correctly
$valueDependsOnTemp = [];
/** @psalm-var string $containerName */
foreach ($additionalContainerNames as $containerName) {
$valueDependsOnTemp[] = $containerName;
}
$valueDependsOn = array_merge_recursive($valueDependsOnTemp, $valueDependsOn);
}
/** @psalm-var string $value */
foreach ($valueDependsOn as $value) {
if ($value === 'nextcloud-aio-clamav') {
if (!$this->configurationManager->isClamavEnabled) {
@@ -221,7 +210,6 @@ readonly class ContainerDefinitionFetcher {
$variables = new ContainerEnvironmentVariables();
if (isset($entry['environment'])) {
/** @psalm-var string $value */
foreach ($entry['environment'] as $value) {
$variables->AddVariable($value);
}
@@ -229,7 +217,6 @@ readonly class ContainerDefinitionFetcher {
$aioVariables = new AioVariables();
if (isset($entry['aio_variables'])) {
/** @psalm-var string $value */
foreach ($entry['aio_variables'] as $value) {
$aioVariables->AddVariable($value);
}
@@ -237,28 +224,27 @@ readonly class ContainerDefinitionFetcher {
$displayName = '';
if (isset($entry['display_name'])) {
$displayName = (string) $entry['display_name'];
$displayName = $entry['display_name'];
}
$restartPolicy = '';
if (isset($entry['restart'])) {
$restartPolicy = (string) $entry['restart'];
$restartPolicy = $entry['restart'];
}
$maxShutdownTime = 10;
if (isset($entry['stop_grace_period'])) {
$maxShutdownTime = (int) $entry['stop_grace_period'];
$maxShutdownTime = $entry['stop_grace_period'];
}
$internalPort = '';
if (isset($entry['internal_port'])) {
$internalPort = (string) $entry['internal_port'];
$internalPort = $entry['internal_port'];
}
if (isset($entry['secrets'])) {
// All secrets are registered with the configuration when they
// are discovered so they can be later generated at time-of-use.
/** @psalm-var string $secret */
foreach ($entry['secrets'] as $secret) {
$this->configurationManager->registerSecret($secret);
}
@@ -266,78 +252,73 @@ readonly class ContainerDefinitionFetcher {
$uiSecret = '';
if (isset($entry['ui_secret'])) {
$uiSecret = (string) $entry['ui_secret'];
$uiSecret = $entry['ui_secret'];
}
$devices = [];
if (isset($entry['devices'])) {
/** @var array */
$devices = $entry['devices'];
}
$enableNvidiaGpu = false;
if (isset($entry['enable_nvidia_gpu'])) {
$enableNvidiaGpu = (bool) $entry['enable_nvidia_gpu'];
$enableNvidiaGpu = $entry['enable_nvidia_gpu'];
}
$capAdd = [];
if (isset($entry['cap_add'])) {
/** @var array */
$capAdd = $entry['cap_add'];
}
$shmSize = -1;
if (isset($entry['shm_size'])) {
$shmSize = (int) $entry['shm_size'];
$shmSize = $entry['shm_size'];
}
$apparmorUnconfined = false;
if (isset($entry['apparmor_unconfined'])) {
$apparmorUnconfined = (bool) $entry['apparmor_unconfined'];
$apparmorUnconfined = $entry['apparmor_unconfined'];
}
$backupVolumes = [];
if (isset($entry['backup_volumes'])) {
/** @var array */
$backupVolumes = $entry['backup_volumes'];
}
$nextcloudExecCommands = [];
if (isset($entry['nextcloud_exec_commands'])) {
/** @var array */
$nextcloudExecCommands = $entry['nextcloud_exec_commands'];
}
$readOnlyRootFs = false;
if (isset($entry['read_only'])) {
$readOnlyRootFs = (bool) $entry['read_only'];
$readOnlyRootFs = $entry['read_only'];
}
$tmpfs = [];
if (isset($entry['tmpfs'])) {
/** @var array */
$tmpfs = $entry['tmpfs'];
}
$init = true;
if (isset($entry['init'])) {
$init = (bool) $entry['init'];
$init = $entry['init'];
}
$imageTag = '%AIO_CHANNEL%';
if (isset($entry['image_tag'])) {
$imageTag = (string) $entry['image_tag'];
$imageTag = $entry['image_tag'];
}
$documentation = '';
if (isset($entry['documentation'])) {
$documentation = (string) $entry['documentation'];
$documentation = $entry['documentation'];
}
$containers[] = new Container(
(string) $entry['container_name'],
$entry['container_name'],
$displayName,
(string) $entry['image'],
$entry['image'],
$restartPolicy,
$maxShutdownTime,
$ports,

View File

@@ -19,34 +19,26 @@ readonly class ConfigurationController {
try {
$this->configurationManager->startTransaction();
if (isset($request->getParsedBody()['domain'])) {
/** @var string */
$domain = $request->getParsedBody()['domain'] ?? '';
$skipDomainValidation = isset($request->getParsedBody()['skip_domain_validation']);
$this->configurationManager->setDomain($domain, $skipDomainValidation);
}
if (isset($request->getParsedBody()['current-master-password']) || isset($request->getParsedBody()['new-master-password'])) {
/** @var string */
$currentMasterPassword = $request->getParsedBody()['current-master-password'] ?? '';
/** @var string */
$newMasterPassword = $request->getParsedBody()['new-master-password'] ?? '';
$this->configurationManager->changeMasterPassword($currentMasterPassword, $newMasterPassword);
}
if (isset($request->getParsedBody()['borg_backup_host_location']) || isset($request->getParsedBody()['borg_remote_repo'])) {
/** @var string */
$location = $request->getParsedBody()['borg_backup_host_location'] ?? '';
/** @var string */
$borgRemoteRepo = $request->getParsedBody()['borg_remote_repo'] ?? '';
$this->configurationManager->setBorgLocationVars($location, $borgRemoteRepo);
}
if (isset($request->getParsedBody()['borg_restore_host_location']) || isset($request->getParsedBody()['borg_restore_remote_repo']) || isset($request->getParsedBody()['borg_restore_password'])) {
/** @var string */
$restoreLocation = $request->getParsedBody()['borg_restore_host_location'] ?? '';
/** @var string */
$borgRemoteRepo = $request->getParsedBody()['borg_restore_remote_repo'] ?? '';
/** @var string */
$borgPassword = $request->getParsedBody()['borg_restore_password'] ?? '';
$this->configurationManager->setBorgRestoreLocationVarsAndPassword($restoreLocation, $borgRemoteRepo, $borgPassword);
}
@@ -62,7 +54,6 @@ readonly class ConfigurationController {
} else {
$successNotification = false;
}
/** @var string */
$dailyBackupTime = $request->getParsedBody()['daily_backup_time'] ?? '';
$this->configurationManager->setDailyBackupTime($dailyBackupTime, $enableAutomaticUpdates, $successNotification);
}
@@ -72,7 +63,6 @@ readonly class ConfigurationController {
}
if (isset($request->getParsedBody()['additional_backup_directories'])) {
/** @var string */
$additionalBackupDirectories = $request->getParsedBody()['additional_backup_directories'] ?? '';
$this->configurationManager->setAdditionalBackupDirectories($additionalBackupDirectories);
}
@@ -82,13 +72,11 @@ readonly class ConfigurationController {
}
if (isset($request->getParsedBody()['timezone'])) {
/** @var string */
$timezone = $request->getParsedBody()['timezone'] ?? '';
$this->configurationManager->timezone = $timezone;
}
if (isset($request->getParsedBody()['options-form'])) {
/** @var string */
$officeSuiteChoice = $request->getParsedBody()['office_suite_choice'] ?? '';
if ($officeSuiteChoice === 'collabora') {
@@ -114,7 +102,7 @@ readonly class ConfigurationController {
$cc = $this->configurationManager->listAvailableCommunityContainers();
$enabledCC = [];
/**
* @psalm-var string $item
* @psalm-suppress PossiblyNullIterator
*/
foreach ($request->getParsedBody() as $item) {
if (array_key_exists($item , $cc)) {
@@ -129,7 +117,6 @@ readonly class ConfigurationController {
}
if (isset($request->getParsedBody()['collabora_dictionaries'])) {
/** @var string */
$collaboraDictionaries = $request->getParsedBody()['collabora_dictionaries'] ?? '';
$this->configurationManager->collaboraDictionaries = $collaboraDictionaries;
}
@@ -139,7 +126,6 @@ readonly class ConfigurationController {
}
if (isset($request->getParsedBody()['collabora_additional_options'])) {
/** @var string */
$additionalCollaboraOptions = $request->getParsedBody()['collabora_additional_options'] ?? '';
$this->configurationManager->collaboraAdditionalOptions = $additionalCollaboraOptions;
}

View File

@@ -125,7 +125,6 @@ readonly class DockerController {
public function StartBackupContainerRestore(Request $request, Response $response, array $args) : Response {
$this->configurationManager->startTransaction();
$this->configurationManager->backupMode = 'restore';
/** @var string */
$this->configurationManager->selectedRestoreTime = $request->getParsedBody()['selected_restore_time'] ?? '';
$this->configurationManager->restoreExcludePreviews = isset($request->getParsedBody()['restore-exclude-previews']);
$this->configurationManager->commitTransaction();
@@ -172,7 +171,6 @@ readonly class DockerController {
$uri = $request->getUri();
$host = $uri->getHost();
$port = $uri->getPort();
/** @var string */
$path = $request->getParsedBody()['base_path'] ?? '';
if ($port === 8000) {
error_log('The AIO_URL-port was discovered to be 8000 which is not expected. It is now set to 443.');
@@ -286,7 +284,6 @@ readonly class DockerController {
return;
// Don't start if domaincheck is already running
} elseif ($domaincheckContainer->GetRunningState() === ContainerState::Running) {
/** @psalm-var mixed $domaincheckWasStarted */
$domaincheckWasStarted = apcu_fetch($cacheKey);
// Start domaincheck again when 10 minutes are over by not returning here
if($domaincheckWasStarted !== false && is_string($domaincheckWasStarted)) {

View File

@@ -21,7 +21,6 @@ readonly class LoginController {
$response->getBody()->write("The login is blocked since Nextcloud is running.");
return $response->withHeader('Location', '.')->withStatus(422);
}
/** @var string */
$password = $request->getParsedBody()['password'] ?? '';
if($this->authManager->CheckCredentials($password)) {
$this->authManager->SetAuthState(true);
@@ -33,7 +32,6 @@ readonly class LoginController {
}
public function GetTryLogin(Request $request, Response $response, array $args) : Response {
/** @var string */
$token = $request->getQueryParams()['token'] ?? '';
if($this->authManager->CheckToken($token)) {
$this->authManager->SetAuthState(true);

View File

@@ -288,7 +288,6 @@ class ConfigurationManager
if ($this->config === [] && file_exists(DataConst::GetConfigFile()))
{
$configContent = (string)file_get_contents(DataConst::GetConfigFile());
/** @var array */
$this->config = json_decode($configContent, true, 512, JSON_THROW_ON_ERROR);
}
@@ -333,7 +332,6 @@ class ConfigurationManager
return '';
}
/** @var array */
$secrets = $this->get('secrets', []);
if (!isset($secrets[$secretId])) {
$secrets[$secretId] = bin2hex(random_bytes(24));
@@ -341,10 +339,10 @@ class ConfigurationManager
}
if ($secretId === 'BORGBACKUP_PASSWORD' && !file_exists(DataConst::GetBackupSecretFile())) {
$this->doubleSafeBackupSecret((string)$secrets[$secretId]);
$this->doubleSafeBackupSecret($secrets[$secretId]);
}
return (string)$secrets[$secretId];
return $secrets[$secretId];
}
public function getRegisteredSecret(string $secretId) : string {
@@ -468,17 +466,15 @@ class ConfigurationManager
if ($this->shouldDomainValidationBeSkipped($skipDomainValidation)) {
error_log('Skipping domain validation');
} else {
/** @var string */
$dnsRecordIP = gethostbyname($domain);
if ($dnsRecordIP === $domain) {
$dnsRecordIP = '';
}
if (empty($dnsRecordIP)) {
/** @var array */
$record = dns_get_record($domain, DNS_AAAA);
if (isset($record[0]['ipv6']) && !empty($record[0]['ipv6'])) {
$dnsRecordIP = (string) $record[0]['ipv6'];
$dnsRecordIP = $record[0]['ipv6'];
}
}
@@ -698,13 +694,12 @@ class ConfigurationManager
private function getEnvironmentalVariableOrConfig(string $envVariableName, string $configName, string $defaultValue) : string {
$envVariableOutput = getenv($envVariableName);
/** @var mixed */
$configValue = $this->get($configName, '');
if ($envVariableOutput === false) {
if ($configValue === '') {
return $defaultValue;
}
return (string) $configValue;
return $configValue;
}
if (file_exists(DataConst::GetConfigFile())) {
@@ -924,7 +919,6 @@ class ConfigurationManager
$dir = array_diff($dir, array('..', '.', 'readme.md'));
foreach ($dir as $id) {
$filePath = DataConst::GetCommunityContainersDirectory() . '/' . $id . '/' . $id . '.json';
/** @psalm-var mixed $fileContents */
$fileContents = apcu_fetch($filePath);
if (!is_string($fileContents)) {
$fileContents = file_get_contents($filePath);
@@ -932,11 +926,8 @@ class ConfigurationManager
apcu_add($filePath, $fileContents);
}
}
/** @psalm-var array $json */
$json = is_string($fileContents) ? json_decode($fileContents, true, 512, JSON_THROW_ON_ERROR) : false;
if(isset($json['aio_services_v1']) && is_array($json['aio_services_v1'])) {
/** @psalm-var array $service */
if(is_array($json) && is_array($json['aio_services_v1'])) {
foreach ($json['aio_services_v1'] as $service) {
$documentation = is_string($service['documentation']) ? $service['documentation'] : '';
if (is_string($service['display_name'])) {
@@ -969,9 +960,8 @@ class ConfigurationManager
return;
}
$this->startTransaction();
/** @psalm-var string $variable */
foreach ($input as $variable) {
if (!str_contains($variable, '=')) {
if (!is_string($variable) || !str_contains($variable, '=')) {
error_log("Invalid input: '$variable' is not a string or does not contain an equal sign ('=')");
continue;
}

View File

@@ -54,10 +54,9 @@ readonly class DockerActionManager {
throw $e;
}
/** @var array */
$responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
if ($responseBody['State']['Running'] ?? false === true) {
if ($responseBody['State']['Running'] === true) {
return ContainerState::Running;
} else {
return ContainerState::Stopped;
@@ -75,10 +74,9 @@ readonly class DockerActionManager {
throw $e;
}
/** @var array */
$responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
if ($responseBody['State']['Restarting'] ?? false === true) {
if ($responseBody['State']['Restarting'] === true) {
return ContainerState::Restarting;
} else {
return ContainerState::NotRestarting;
@@ -100,7 +98,6 @@ readonly class DockerActionManager {
return VersionState::Equal;
}
/** @psalm-var string $runningDigest */
foreach ($runningDigests as $runningDigest) {
if ($runningDigest === $remoteDigest) {
return VersionState::Equal;
@@ -337,7 +334,6 @@ readonly class DockerActionManager {
}
$tmpfs = [];
/** @psalm-var string $tmp */
foreach ($container->tmpfs as $tmp) {
$mode = "";
if (str_contains($tmp, ':')) {
@@ -378,7 +374,6 @@ readonly class DockerActionManager {
// Special things for the backup container which should not be exposed in the containers.json
if (str_starts_with($container->identifier, 'nextcloud-aio-borgbackup')) {
// Additional backup directories
/** @psalm-var string $additionalBackupVolumes */
foreach ($this->getAllBackupVolumes() as $additionalBackupVolumes) {
if ($additionalBackupVolumes !== '') {
$mounts[] = ["Type" => "volume", "Source" => $additionalBackupVolumes, "Target" => "/nextcloud_aio_volumes/" . $additionalBackupVolumes, "ReadOnly" => false];
@@ -388,7 +383,6 @@ readonly class DockerActionManager {
// Make volumes read only in case of borgbackup container. The viewer makes them writeable
$isReadOnly = $container->identifier === 'nextcloud-aio-borgbackup';
/** @psalm-var string $additionalBackupDirectories */
foreach ($this->configurationManager->getAdditionalBackupDirectoriesArray() as $additionalBackupDirectories) {
if ($additionalBackupDirectories !== '') {
if (!str_starts_with($additionalBackupDirectories, '/')) {
@@ -584,7 +578,6 @@ readonly class DockerActionManager {
$container = $this->containerDefinitionFetcher->GetContainerById($id);
$nextcloudExecCommands = '';
/** @psalm-var string $execCommand */
foreach ($container->nextcloudExecCommands as $execCommand) {
$nextcloudExecCommands .= $execCommand . PHP_EOL;
}
@@ -602,12 +595,10 @@ readonly class DockerActionManager {
private function GetRepoDigestsOfContainer(string $containerName): ?array {
try {
$containerUrl = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
/** @var array */
$containerOutput = json_decode($this->guzzleClient->get($containerUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$imageName = (string) $containerOutput['Image'];
$imageName = $containerOutput['Image'];
$imageUrl = $this->BuildApiUrl(sprintf('images/%s/json', $imageName));
/** @var array */
$imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (!isset($imageOutput['RepoDigests'])) {
@@ -622,7 +613,6 @@ readonly class DockerActionManager {
$repoDigestArray = [];
$oneDigestGiven = false;
/** @psalm-var string $repoDigest */
foreach ($imageOutput['RepoDigests'] as $repoDigest) {
$digestPosition = strpos($repoDigest, '@');
if ($digestPosition === false) {
@@ -645,7 +635,6 @@ readonly class DockerActionManager {
private function GetCurrentImageName(): string {
$cacheKey = 'aio-image-name';
/** @psalm-var mixed $imageName */
$imageName = apcu_fetch($cacheKey);
if ($imageName !== false && is_string($imageName)) {
return $imageName;
@@ -654,14 +643,13 @@ readonly class DockerActionManager {
$containerName = 'nextcloud-aio-mastercontainer';
$url = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
try {
/** @var array */
$output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$imageNameArray = explode(':', (string) $output['Config']['Image']);
$imageNameArray = explode(':', $output['Config']['Image']);
if (count($imageNameArray) === 2) {
$imageName = $imageNameArray[0];
} else {
error_log("No tag was found when getting the current channel. You probably did not follow the documentation correctly. Changing the imageName to the default " . (string) $output['Config']['Image']);
$imageName = (string) $output['Config']['Image'];
error_log("No tag was found when getting the current channel. You probably did not follow the documentation correctly. Changing the imageName to the default " . $output['Config']['Image']);
$imageName = $output['Config']['Image'];
}
apcu_add($cacheKey, $imageName);
return $imageName;
@@ -674,7 +662,6 @@ readonly class DockerActionManager {
public function GetCurrentChannel(): string {
$cacheKey = 'aio-ChannelName';
/** @psalm-var mixed $channelName */
$channelName = apcu_fetch($cacheKey);
if ($channelName !== false && is_string($channelName)) {
return $channelName;
@@ -683,9 +670,8 @@ readonly class DockerActionManager {
$containerName = 'nextcloud-aio-mastercontainer';
$url = $this->BuildApiUrl(sprintf('containers/%s/json', $containerName));
try {
/** @var array */
$output = json_decode($this->guzzleClient->get($url)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
$tagArray = explode(':', (string) $output['Config']['Image']);
$tagArray = explode(':', $output['Config']['Image']);
if (count($tagArray) === 2) {
$tag = $tagArray[1];
} else {
@@ -716,7 +702,6 @@ readonly class DockerActionManager {
return false;
}
/** @psalm-var string $runningDigest */
foreach ($runningDigests as $runningDigest) {
if ($remoteDigest === $runningDigest) {
return false;
@@ -732,7 +717,6 @@ readonly class DockerActionManager {
// schedule the exec
$url = $this->BuildApiUrl(sprintf('containers/%s/exec', urlencode($containerName)));
/** @var array */
$response = json_decode(
$this->guzzleClient->request(
'POST',
@@ -755,7 +739,7 @@ readonly class DockerActionManager {
JSON_THROW_ON_ERROR,
);
$id = (string) $response['Id'];
$id = $response['Id'];
// start the exec
$url = $this->BuildApiUrl(sprintf('exec/%s/start', $id));
@@ -894,11 +878,9 @@ readonly class DockerActionManager {
throw $e;
}
/** @var array */
$responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
/** @var null|int */
$exitCode = $responseBody['State']['ExitCode'] ?? null;
$exitCode = $responseBody['State']['ExitCode'];
if (is_int($exitCode)) {
return $exitCode;
} else {
@@ -918,11 +900,9 @@ readonly class DockerActionManager {
throw $e;
}
/** @var array */
$responseBody = json_decode((string)$response->getBody(), true, 512, JSON_THROW_ON_ERROR);
/** @var null|int */
$exitCode = $responseBody['State']['ExitCode'] ?? null;
$exitCode = $responseBody['State']['ExitCode'];
if (is_int($exitCode)) {
return $exitCode;
} else {
@@ -952,7 +932,6 @@ readonly class DockerActionManager {
$imageName = $imageName . ':' . $this->GetCurrentChannel();
try {
$imageUrl = $this->BuildApiUrl(sprintf('images/%s/json', $imageName));
/** @var array */
$imageOutput = json_decode($this->guzzleClient->get($imageUrl)->getBody()->getContents(), true, 512, JSON_THROW_ON_ERROR);
if (!isset($imageOutput['Created'])) {

View File

@@ -17,7 +17,6 @@ readonly class DockerHubManager {
public function GetLatestDigestOfTag(string $name, string $tag) : ?string {
$cacheKey = 'dockerhub-manifest-' . $name . $tag;
/** @psalm-var mixed $cachedVersion */
$cachedVersion = apcu_fetch($cacheKey);
if($cachedVersion !== false && is_string($cachedVersion)) {
return $cachedVersion;
@@ -31,10 +30,9 @@ readonly class DockerHubManager {
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:' . $name . ':pull'
);
$body = $authTokenRequest->getBody()->getContents();
/** @var array */
$decodedBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if(isset($decodedBody['token'])) {
$authToken = (string) $decodedBody['token'];
$authToken = $decodedBody['token'];
$manifestRequest = $this->guzzleClient->request(
'HEAD',
'https://registry-1.docker.io/v2/'.$name.'/manifests/' . $tag,

View File

@@ -18,7 +18,6 @@ readonly class GitHubContainerRegistryManager
{
$cacheKey = 'ghcr-manifest-' . $name . $tag;
/** @psalm-var mixed $cachedVersion */
$cachedVersion = apcu_fetch($cacheKey);
if ($cachedVersion !== false && is_string($cachedVersion)) {
return $cachedVersion;
@@ -32,10 +31,9 @@ readonly class GitHubContainerRegistryManager
'https://ghcr.io/token?scope=repository:' . $name . ':pull'
);
$body = $authTokenRequest->getBody()->getContents();
/** @var array */
$decodedBody = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
if (isset($decodedBody['token'])) {
$authToken = (string) $decodedBody['token'];
$authToken = $decodedBody['token'];
$manifestRequest = $this->guzzleClient->request(
'HEAD',
'https://ghcr.io/v2/' . $name . '/manifests/' . $tag,