From 65365752d75b7c3c06610328ce1d41d37afed550 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Fri, 25 Sep 2026 07:53:04 +0200 Subject: [PATCH] fix(deployment): skip secret lookup for plain build variables --- app/Jobs/ApplicationDeploymentJob.php | 7 +++- ...ationDeploymentControlVarFilteringTest.php | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/Jobs/ApplicationDeploymentJob.php b/app/Jobs/ApplicationDeploymentJob.php index 47ad23eede..b9143ae1b0 100644 --- a/app/Jobs/ApplicationDeploymentJob.php +++ b/app/Jobs/ApplicationDeploymentJob.php @@ -1449,10 +1449,15 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue * Replace {{vault.KEY}} references with values from the configured secret * manager source. Missing keys fail the deployment with a * list — changing the source never re-checks references, so this is the - * moment problems surface. + * moment problems surface. Values without references are returned as-is + * and never fetch secrets. */ private function substitute_remote_secrets(string $value, string $envKey): string { + if (! RemoteSecretReferences::containsReference($value)) { + return $value; + } + $secrets = $this->remote_secrets(); $missing = RemoteSecretReferences::missingKeys($value, $secrets); diff --git a/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php b/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php index 35d24eedc4..da2707b7f6 100644 --- a/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php +++ b/tests/Feature/ApplicationDeploymentControlVarFilteringTest.php @@ -1031,6 +1031,42 @@ it('injects raw escaped remote secrets into Dockerfile args and hashes the same 'preview' => [99, true], ]); +it('injects Dockerfile args for plain build-time variables without a secret manager source', function (int $pullRequestId, bool $isPreview) { + [$application, $server] = makeDeploymentControlVarFixture(); + + createApplicationEnvironmentVariable($application, [ + 'key' => 'APP_ENV', + 'value' => 'production', + 'is_preview' => $isPreview, + 'is_runtime' => false, + 'is_buildtime' => true, + ]); + + [$job, $reflection] = makeControlVarFilteringJob($application, $server, [ + 'pull_request_id' => $pullRequestId, + 'saved_outputs' => [ + 'dockerfile' => "FROM php:8.4-cli\nRUN php -v", + ], + ]); + + invokeDeploymentJobMethod($job, $reflection, 'add_build_env_variables_to_dockerfile'); + + $expectedHash = invokeDeploymentJobMethod( + $job, + $reflection, + 'generate_secrets_hash', + collect(['APP_ENV' => escapeBashEnvValue('production')]), + ); + + expect($job->writtenDockerfile) + ->toContain('ARG APP_ENV') + ->toContain("ARG COOLIFY_BUILD_SECRETS_HASH={$expectedHash}"); + expect(readDeploymentJobProperty($job, $reflection, 'remote_secrets_cache'))->toBeNull(); +})->with([ + 'production' => [0, false], + 'preview' => [99, true], +]); + it('builds railpack variables from generic buildtime vars railpack vars and coolify vars only', function () { [$application, $server] = makeDeploymentControlVarFixture([ 'build_pack' => 'railpack',