From 01ea05959ea457e5ddb14d313a59de91bf0ec1e5 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Mon, 5 Oct 2026 15:09:25 +0200 Subject: [PATCH] fix(api): skip domain generation for Docker Compose applications --- .../Api/ApplicationsController.php | 13 ++++++------ ...licationComposeInjectionValidationTest.php | 20 +++++++++++++++++++ .../ApplicationPublicApiGitRepositoryTest.php | 6 ++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Api/ApplicationsController.php b/app/Http/Controllers/Api/ApplicationsController.php index 238a318ce3..a611a60f4f 100644 --- a/app/Http/Controllers/Api/ApplicationsController.php +++ b/app/Http/Controllers/Api/ApplicationsController.php @@ -428,7 +428,7 @@ class ApplicationsController extends Controller 'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'], 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'], 'force_domain_override' => ['type' => 'boolean', 'description' => 'Force domain usage even if conflicts are detected. Default is false.'], - 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Default: true.'], + 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Ignored for the dockercompose build pack, which uses docker_compose_domains. Default: true.'], 'is_container_label_escape_enabled' => ['type' => 'boolean', 'default' => true, 'description' => 'Escape special characters in labels. By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$. If you want to use env variables inside the labels, turn this off.'], 'tags' => ['type' => 'array', 'items' => new OA\Items(type: 'string'), 'description' => 'Tags to assign to the application.'], 'is_preserve_repository_enabled' => ['type' => 'boolean', 'default' => false, 'description' => 'Preserve repository during deployment.'], @@ -623,7 +623,7 @@ class ApplicationsController extends Controller 'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'], 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'], 'force_domain_override' => ['type' => 'boolean', 'description' => 'Force domain usage even if conflicts are detected. Default is false.'], - 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Default: true.'], + 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Ignored for the dockercompose build pack, which uses docker_compose_domains. Default: true.'], 'is_container_label_escape_enabled' => ['type' => 'boolean', 'default' => true, 'description' => 'Escape special characters in labels. By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$. If you want to use env variables inside the labels, turn this off.'], 'tags' => ['type' => 'array', 'items' => new OA\Items(type: 'string'), 'description' => 'Tags to assign to the application.'], 'is_preserve_repository_enabled' => ['type' => 'boolean', 'default' => false, 'description' => 'Preserve repository during deployment.'], @@ -818,7 +818,7 @@ class ApplicationsController extends Controller 'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'], 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'], 'force_domain_override' => ['type' => 'boolean', 'description' => 'Force domain usage even if conflicts are detected. Default is false.'], - 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Default: true.'], + 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Ignored for the dockercompose build pack, which uses docker_compose_domains. Default: true.'], 'is_container_label_escape_enabled' => ['type' => 'boolean', 'default' => true, 'description' => 'Escape special characters in labels. By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$. If you want to use env variables inside the labels, turn this off.'], 'tags' => ['type' => 'array', 'items' => new OA\Items(type: 'string'), 'description' => 'Tags to assign to the application.'], 'is_preserve_repository_enabled' => ['type' => 'boolean', 'default' => false, 'description' => 'Preserve repository during deployment.'], @@ -984,7 +984,7 @@ class ApplicationsController extends Controller 'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'], 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'], 'force_domain_override' => ['type' => 'boolean', 'description' => 'Force domain usage even if conflicts are detected. Default is false.'], - 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Default: true.'], + 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Ignored for the dockercompose build pack, which uses docker_compose_domains. Default: true.'], 'is_container_label_escape_enabled' => ['type' => 'boolean', 'default' => true, 'description' => 'Escape special characters in labels. By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$. If you want to use env variables inside the labels, turn this off.'], 'tags' => ['type' => 'array', 'items' => new OA\Items(type: 'string'), 'description' => 'Tags to assign to the application.'], ], @@ -1146,7 +1146,7 @@ class ApplicationsController extends Controller 'http_basic_auth_password' => ['type' => 'string', 'nullable' => true, 'description' => 'Password for HTTP Basic Authentication'], 'connect_to_docker_network' => ['type' => 'boolean', 'description' => 'The flag to connect the service to the predefined Docker network.'], 'force_domain_override' => ['type' => 'boolean', 'description' => 'Force domain usage even if conflicts are detected. Default is false.'], - 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Default: true.'], + 'autogenerate_domain' => ['type' => 'boolean', 'default' => true, 'description' => 'If true and domains is empty, auto-generate a domain using the server\'s wildcard domain or sslip.io fallback. Ignored for the dockercompose build pack, which uses docker_compose_domains. Default: true.'], 'is_container_label_escape_enabled' => ['type' => 'boolean', 'default' => true, 'description' => 'Escape special characters in labels. By default, $ (and other chars) is escaped. So if you write $ in the labels, it will be saved as $$. If you want to use env variables inside the labels, turn this off.'], 'tags' => ['type' => 'array', 'items' => new OA\Items(type: 'string'), 'description' => 'Tags to assign to the application.'], ], @@ -1296,7 +1296,8 @@ class ApplicationsController extends Controller $fqdn = ValidationPatterns::normalizeApplicationDomains($request->domains); $request->offsetSet('domains', $fqdn); } - $autogenerateDomain = $request->boolean('autogenerate_domain', true); + // A Docker Compose application uses per-service domains; a top-level domain is never routed. + $autogenerateDomain = $request->boolean('autogenerate_domain', true) && $request->build_pack !== 'dockercompose'; $instantDeploy = $request->instant_deploy; $githubAppUuid = $request->github_app_uuid; $useBuildServer = $request->use_build_server; diff --git a/tests/Feature/ApplicationComposeInjectionValidationTest.php b/tests/Feature/ApplicationComposeInjectionValidationTest.php index 4db2d25dad..3af9f50506 100644 --- a/tests/Feature/ApplicationComposeInjectionValidationTest.php +++ b/tests/Feature/ApplicationComposeInjectionValidationTest.php @@ -266,6 +266,26 @@ test('API create accepts a safe docker_compose_raw', function () { ->assertCreated(); }); +test('API create does not generate a domain for a docker compose application', function () { + Queue::fake(); + + $response = $this->withHeaders(['Authorization' => 'Bearer '.$this->token]) + ->postJson('/api/v1/applications/public', [ + 'project_uuid' => $this->project->uuid, + 'environment_uuid' => $this->environment->uuid, + 'server_uuid' => $this->server->uuid, + 'git_repository' => 'https://gitlab.com/coolify/compose-app', + 'git_branch' => 'main', + 'build_pack' => 'dockercompose', + 'ports_exposes' => '80', + 'autogenerate_domain' => true, + 'docker_compose_raw' => SAFE_APPLICATION_COMPOSE, + ]) + ->assertCreated(); + + expect(Application::query()->where('uuid', $response->json('uuid'))->value('fqdn'))->toBeNull(); +}); + test('API update does not accept docker_compose_raw', function () { $this->withHeaders(['Authorization' => 'Bearer '.$this->token]) ->patchJson("/api/v1/applications/{$this->application->uuid}", [ diff --git a/tests/Feature/ApplicationPublicApiGitRepositoryTest.php b/tests/Feature/ApplicationPublicApiGitRepositoryTest.php index eb105e6764..00f41b2a6e 100644 --- a/tests/Feature/ApplicationPublicApiGitRepositoryTest.php +++ b/tests/Feature/ApplicationPublicApiGitRepositoryTest.php @@ -86,3 +86,9 @@ test('public github repositories are stored as owner and repository with the pub ->and($application->source_type)->toBe(GithubApp::class) ->and($application->source_id)->toBe(0); }); + +test('a public application gets a generated domain by default', function () { + $application = createPublicGitApplication(['autogenerate_domain' => true]); + + expect($application->fqdn)->not->toBeEmpty(); +});