diff --git a/app/Livewire/Server/Security/Patches.php b/app/Livewire/Server/Security/Patches.php index c7228760bf..bcb7cf882c 100644 --- a/app/Livewire/Server/Security/Patches.php +++ b/app/Livewire/Server/Security/Patches.php @@ -181,10 +181,14 @@ class Patches extends Component $this->authorize('update', $this->server); $settings = $this->server->settings; $enabled = ! $settings->is_auto_security_updates_enabled; - $time = $settings->auto_security_updates_time ?: '03:00'; + $time = trim($this->autoSecurityUpdatesTime); + if (preg_match(ConfigureAutomaticSecurityUpdates::TIME_PATTERN, $time) !== 1) { + throw new \Exception('Invalid time. Use the 24-hour format HH:MM, for example 03:00.'); + } $this->applyAutomaticSecurityUpdates($enabled, $time); $settings->is_auto_security_updates_enabled = $enabled; + $settings->auto_security_updates_time = $time; $settings->save(); $this->syncSettings(); $this->dispatch('success', $enabled ? 'Automatic security updates turned on.' : 'Automatic security updates turned off.'); diff --git a/resources/views/livewire/server/security/patches.blade.php b/resources/views/livewire/server/security/patches.blade.php index 99b6973962..0b1d557b35 100644 --- a/resources/views/livewire/server/security/patches.blade.php +++ b/resources/views/livewire/server/security/patches.blade.php @@ -123,7 +123,7 @@ submitAction="toggleAutomaticSecurityUpdates" temporaryDisableTwoStepConfirmation :confirmWithText="false" :confirmWithPassword="false" :actions="[ - 'Every day at ' . $autoSecurityUpdatesTime . ' (time zone of the server), the server installs security updates without asking.', + 'Every day at the time in Maintenance window (time zone of the server), the server installs security updates without asking.', 'If Docker comes from the operating system packages (for example docker.io or moby-engine), a security update of Docker restarts it, and all containers on this server stop and start again. Docker from the Docker repository (docker-ce, as Coolify installs it) has no security updates there and is not updated.', 'Services that use an updated library (for example OpenSSL or glibc) can restart.', 'A new kernel is installed, but the server is not rebooted. Coolify then shows Reboot required.', diff --git a/tests/Feature/Server/ServerPatchesTest.php b/tests/Feature/Server/ServerPatchesTest.php index e8e69287ec..b65c74c4fc 100644 --- a/tests/Feature/Server/ServerPatchesTest.php +++ b/tests/Feature/Server/ServerPatchesTest.php @@ -23,6 +23,7 @@ use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Queue; use Illuminate\Support\Facades\Storage; +use Livewire\Features\SupportLockedProperties\CannotUpdateLockedPropertyException; use Livewire\Livewire; use Spatie\Activitylog\Models\Activity; @@ -370,7 +371,7 @@ describe('automatic security updates', function () { ConfigureAutomaticSecurityUpdates::shouldRun()->never(); expect(fn () => Livewire::test(Patches::class, ['server_uuid' => $this->server->uuid])->set('autoSecurityUpdates', true)) - ->toThrow(\Livewire\Features\SupportLockedProperties\CannotUpdateLockedPropertyException::class); + ->toThrow(CannotUpdateLockedPropertyException::class); }); it('applies a new maintenance window only when automatic updates are on', function () { @@ -391,6 +392,20 @@ describe('automatic security updates', function () { expect($this->server->settings->fresh()->auto_security_updates_time)->toBe('05:00'); }); + it('turns on automatic updates with the time in the field, also when it is not saved yet', function () { + ConfigureAutomaticSecurityUpdates::shouldRun()->once() + ->with(Mockery::on(fn ($server) => $server->is($this->server)), 'apt', true, '05:45'); + + Livewire::test(Patches::class, ['server_uuid' => $this->server->uuid]) + ->set('autoSecurityUpdatesTime', '05:45') + ->call('toggleAutomaticSecurityUpdates') + ->assertDispatched('success'); + + expect($this->server->settings->fresh()) + ->is_auto_security_updates_enabled->toBeTrue() + ->auto_security_updates_time->toBe('05:45'); + }); + it('keeps the setting off when the server commands fail', function () { ConfigureAutomaticSecurityUpdates::shouldRun()->once()->andThrow(new RuntimeException('apt-get failed'));