From 37d0699aae5f246b44821a112c54b59df4661488 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 29 Jul 2026 15:20:52 +0200 Subject: [PATCH] chore: prepare for PR --- bootstrap/helpers/shared.php | 11 +- tests/Feature/ApplicationClearDomainsTest.php | 104 ++++++++++++++++++ tests/Unit/SslipDomainWarningTest.php | 28 +++++ 3 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/ApplicationClearDomainsTest.php create mode 100644 tests/Unit/SslipDomainWarningTest.php diff --git a/bootstrap/helpers/shared.php b/bootstrap/helpers/shared.php index 8900c0cd3..92f995728 100644 --- a/bootstrap/helpers/shared.php +++ b/bootstrap/helpers/shared.php @@ -3803,8 +3803,17 @@ function loggy($message = null, array $context = []) return app('log')->debug($message, $context); } -function sslipDomainWarning(string $domains) +/** + * Warn when any domain uses HTTPS with an sslip hostname. + * + * Empty/null domain lists are valid (domains removed) and produce no warning. + */ +function sslipDomainWarning(?string $domains): bool { + if (blank($domains)) { + return false; + } + $domains = str($domains)->trim()->explode(','); $showSslipHttpsWarning = false; $domains->each(function ($domain) use (&$showSslipHttpsWarning) { diff --git a/tests/Feature/ApplicationClearDomainsTest.php b/tests/Feature/ApplicationClearDomainsTest.php new file mode 100644 index 000000000..9a5b2576a --- /dev/null +++ b/tests/Feature/ApplicationClearDomainsTest.php @@ -0,0 +1,104 @@ +team = Team::factory()->create(); + $this->user = User::factory()->create(); + $this->team->members()->attach($this->user->id, ['role' => 'owner']); + + $this->actingAs($this->user); + session(['currentTeam' => $this->team]); + InstanceSettings::unguarded(function () { + InstanceSettings::updateOrCreate(['id' => 0], []); + }); + + $this->project = Project::factory()->create(['team_id' => $this->team->id]); + $this->environment = Environment::factory()->create(['project_id' => $this->project->id]); + $this->privateKey = PrivateKey::create([ + 'name' => 'Test Key', + 'private_key' => '-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevAAAAJi/QySHv0Mk +hwAAAAtzc2gtZWQyNTUxOQAAACBbhpqHhqv6aI67Mj9abM3DVbmcfYhZAhC7ca4d9UCevA +AAAECBQw4jg1WRT2IGHMncCiZhURCts2s24HoDS0thHnnRKVuGmoeGq/pojrsyP1pszcNV +uZx9iFkCELtxrh31QJ68AAAAEXNhaWxANzZmZjY2ZDJlMmRkAQIDBA== +-----END OPENSSH PRIVATE KEY-----', + 'team_id' => $this->team->id, + ]); + $this->server = Server::factory()->create([ + 'team_id' => $this->team->id, + 'private_key_id' => $this->privateKey->id, + ]); + $this->destination = StandaloneDocker::where('server_id', $this->server->id)->first() + ?? StandaloneDocker::factory()->create(['server_id' => $this->server->id, 'network' => 'coolify-test']); +}); + +/** + * Regression for #11079: removing all domains must save without TypeError from + * sslipDomainWarning(null) after normalizeApplicationDomains returns null. + */ +test('can clear application domains and save successfully', function () { + $application = Application::factory()->create([ + 'environment_id' => $this->environment->id, + 'destination_id' => $this->destination->id, + 'destination_type' => StandaloneDocker::class, + 'build_pack' => 'nixpacks', + 'fqdn' => 'https://example.com', + 'static_image' => 'nginx:alpine', + 'base_directory' => '/', + 'ports_exposes' => '3000', + 'is_http_basic_auth_enabled' => false, + 'redirect' => 'no', + ]); + + Livewire::test(General::class, ['application' => $application]) + ->assertSuccessful() + ->set('fqdn', null) + ->call('submit') + ->assertHasNoErrors() + ->assertNotDispatched('error') + ->assertDispatched('success'); + + $application->refresh(); + expect($application->fqdn)->toBeNull(); +}); + +test('can clear application domains via empty string and save successfully', function () { + $application = Application::factory()->create([ + 'environment_id' => $this->environment->id, + 'destination_id' => $this->destination->id, + 'destination_type' => StandaloneDocker::class, + 'build_pack' => 'nixpacks', + 'fqdn' => 'https://app.example.com,https://www.example.com', + 'static_image' => 'nginx:alpine', + 'base_directory' => '/', + 'ports_exposes' => '3000', + 'is_http_basic_auth_enabled' => false, + 'redirect' => 'no', + ]); + + Livewire::test(General::class, ['application' => $application]) + ->assertSuccessful() + ->set('fqdn', '') + ->call('submit') + ->assertHasNoErrors() + ->assertNotDispatched('error') + ->assertDispatched('success'); + + $application->refresh(); + expect($application->fqdn)->toBeNull(); +}); diff --git a/tests/Unit/SslipDomainWarningTest.php b/tests/Unit/SslipDomainWarningTest.php new file mode 100644 index 000000000..e412462f2 --- /dev/null +++ b/tests/Unit/SslipDomainWarningTest.php @@ -0,0 +1,28 @@ +toBeFalse(); +}); + +it('returns false when domains are empty or whitespace', function () { + expect(sslipDomainWarning(''))->toBeFalse(); + expect(sslipDomainWarning(' '))->toBeFalse(); +}); + +it('returns false for non-sslip https domains', function () { + expect(sslipDomainWarning('https://example.com'))->toBeFalse(); + expect(sslipDomainWarning('http://app.example.com,https://www.example.com'))->toBeFalse(); +}); + +it('returns false for http sslip domains without https', function () { + expect(sslipDomainWarning('http://app.127.0.0.1.sslip.io'))->toBeFalse(); +}); + +it('returns true when any domain uses https with sslip', function () { + expect(sslipDomainWarning('https://app.127.0.0.1.sslip.io'))->toBeTrue(); + expect(sslipDomainWarning('https://example.com,https://app.127.0.0.1.sslip.io'))->toBeTrue(); +});