diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 098cf7804..09068fba4 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1293,12 +1293,8 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue $sorted_environment_variables_preview = $this->application->runtime_environment_variables_preview->sortBy('id'); } if ($this->build_pack === 'dockercompose') { - $sorted_environment_variables = $sorted_environment_variables->filter(function ($env) { - return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_') && ! str($env->key)->startsWith('SERVICE_NAME_'); - }); - $sorted_environment_variables_preview = $sorted_environment_variables_preview->filter(function ($env) { - return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_') && ! str($env->key)->startsWith('SERVICE_NAME_'); - }); + $sorted_environment_variables = $sorted_environment_variables->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); + $sorted_environment_variables_preview = $sorted_environment_variables_preview->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); } $ports = $this->application->main_port(); $coolify_envs = $this->generate_coolify_env_variables(); @@ -1451,6 +1447,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue return $envs; } + private function isGeneratedDockerComposeEnvironmentVariable(EnvironmentVariable $environmentVariable): bool + { + $key = str($environmentVariable->key); + + return $key->startsWith('SERVICE_FQDN_') + || $key->startsWith('SERVICE_URL_') + || $key->startsWith('SERVICE_NAME_'); + } + private function save_runtime_environment_variables() { // This method saves the .env file with ALL runtime variables @@ -1666,11 +1671,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id') ->get(); - // For Docker Compose, filter out SERVICE_FQDN and SERVICE_URL as we generate these + // For Docker Compose, filter out generated SERVICE_* variables as we generate these if ($this->build_pack === 'dockercompose') { - $sorted_environment_variables = $sorted_environment_variables->filter(function ($env) { - return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_'); - }); + $sorted_environment_variables = $sorted_environment_variables->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); } foreach ($sorted_environment_variables as $env) { @@ -1719,11 +1722,9 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue ->orderBy($this->application->settings->is_env_sorting_enabled ? 'key' : 'id') ->get(); - // For Docker Compose, filter out SERVICE_FQDN and SERVICE_URL as we generate these with PR-specific values + // For Docker Compose, filter out generated SERVICE_* variables as we generate these with PR-specific values if ($this->build_pack === 'dockercompose') { - $sorted_environment_variables = $sorted_environment_variables->filter(function ($env) { - return ! str($env->key)->startsWith('SERVICE_FQDN_') && ! str($env->key)->startsWith('SERVICE_URL_'); - }); + $sorted_environment_variables = $sorted_environment_variables->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); } foreach ($sorted_environment_variables as $env) { @@ -3019,6 +3020,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); ->where('is_buildtime', true) ->get(); + if ($this->build_pack === 'dockercompose') { + $envs = $envs->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); + } + foreach ($envs as $env) { $resolvedValue = $env->getResolvedValueWithServer($this->mainServer); if (! is_null($resolvedValue)) { @@ -3031,6 +3036,10 @@ COPY ./nginx.conf /etc/nginx/conf.d/default.conf"); ->where('is_buildtime', true) ->get(); + if ($this->build_pack === 'dockercompose') { + $envs = $envs->reject(fn (EnvironmentVariable $env) => $this->isGeneratedDockerComposeEnvironmentVariable($env)); + } + foreach ($envs as $env) { $resolvedValue = $env->getResolvedValueWithServer($this->mainServer); if (! is_null($resolvedValue)) { diff --git a/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php b/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php index d728f5ad7..83244c567 100644 --- a/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php +++ b/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php @@ -205,6 +205,127 @@ it('filters buildpack control vars from preview build-time env files', function expect($buildtimeEnvs->contains(fn (string $env) => str($env)->startsWith('RAILPACK_NODE_VERSION=')))->toBeFalse(); }); +it('does not let preview docker compose service names override generated build-time service names', function () { + $compose = <<<'YAML' +services: + app: + image: nginx + postgresapp: + image: postgres:16-alpine +YAML; + + [$application, $server] = makeDeploymentControlVarFixture([ + 'build_pack' => 'dockercompose', + 'docker_compose_raw' => $compose, + 'docker_compose' => $compose, + 'docker_compose_domains' => '[]', + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'SERVICE_NAME_POSTGRESAPP', + 'value' => '', + 'is_preview' => true, + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'SERVICE_URL_APP', + 'value' => '', + 'is_preview' => true, + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + [$job, $reflection] = makeControlVarFilteringJob($application, $server, [ + 'pull_request_id' => 241, + ]); + + /** @var Collection $buildtimeEnvs */ + $buildtimeEnvs = invokeDeploymentJobMethod($job, $reflection, 'generate_buildtime_environment_variables'); + $envString = $buildtimeEnvs->implode("\n"); + + expect($envString)->toContain("SERVICE_NAME_POSTGRESAPP='postgresapp-pr-241'"); + expect($envString)->not->toContain('SERVICE_NAME_POSTGRESAPP=""'); + expect($envString)->not->toContain('SERVICE_URL_APP='); +}); + +it('does not let production docker compose service names override generated build-time service names', function () { + $compose = <<<'YAML' +services: + app: + image: nginx + postgresapp: + image: postgres:16-alpine +YAML; + + [$application, $server] = makeDeploymentControlVarFixture([ + 'build_pack' => 'dockercompose', + 'docker_compose_raw' => $compose, + 'docker_compose' => $compose, + 'docker_compose_domains' => '[]', + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'SERVICE_NAME_POSTGRESAPP', + 'value' => 'stale-postgresapp', + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + [$job, $reflection] = makeControlVarFilteringJob($application, $server); + + /** @var Collection $buildtimeEnvs */ + $buildtimeEnvs = invokeDeploymentJobMethod($job, $reflection, 'generate_buildtime_environment_variables'); + $envString = $buildtimeEnvs->implode("\n"); + + expect($envString)->toContain("SERVICE_NAME_POSTGRESAPP='postgresapp'"); + expect($envString)->not->toContain('stale-postgresapp'); +}); + +it('filters docker compose generated service variables from build args', function () { + [$application, $server] = makeDeploymentControlVarFixture([ + 'build_pack' => 'dockercompose', + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'APP_ENV', + 'value' => 'production', + 'is_preview' => true, + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'SERVICE_NAME_POSTGRESAPP', + 'value' => '', + 'is_preview' => true, + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'SERVICE_URL_APP', + 'value' => 'https://preview.example.com', + 'is_preview' => true, + 'is_runtime' => true, + 'is_buildtime' => true, + ]); + + [$job, $reflection] = makeControlVarFilteringJob($application, $server, [ + 'pull_request_id' => 241, + ]); + + invokeDeploymentJobMethod($job, $reflection, 'generate_env_variables'); + + /** @var Collection $envArgs */ + $envArgs = readDeploymentJobProperty($job, $reflection, 'env_args'); + + expect($envArgs->get('APP_ENV'))->toBe('production'); + expect($envArgs->has('SERVICE_NAME_POSTGRESAPP'))->toBeFalse(); + expect($envArgs->has('SERVICE_URL_APP'))->toBeFalse(); +}); + it('filters buildpack control vars from preview runtime env fallback', function () { [$application, $server] = makeDeploymentControlVarFixture();