mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-28 02:06:37 -04:00
fix(deployments): allow legacy runtime-only env var names to deploy
Runtime-only environment variables whose names new variables can no longer use (e.g. my-var) no longer fail the deployment. They are still passed to the container through the .env file, and the deployment log now shows a warning with a suggested valid name. Build-time variables, and names that would break a .env line (empty or containing =, newline, carriage return or NUL), are still rejected.
This commit is contained in:
@@ -2066,17 +2066,42 @@ class ApplicationDeploymentJob implements ShouldBeEncrypted, ShouldQueue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build-time names go into shell and Docker build commands, so they must be valid. Runtime-only
|
||||
* variables only go into the .env file: existing ones with names that new variables can no longer
|
||||
* use (such as my-var) keep working, unless the name would break a .env line.
|
||||
*/
|
||||
private function validateDeploymentEnvironmentVariableKeys(): void
|
||||
{
|
||||
$environmentVariables = $this->pull_request_id === 0
|
||||
? $this->application->environment_variables()->get(['key'])
|
||||
: $this->application->environment_variables_preview()->get(['key']);
|
||||
? $this->application->environment_variables()->get(['key', 'is_buildtime'])
|
||||
: $this->application->environment_variables_preview()->get(['key', 'is_buildtime']);
|
||||
|
||||
foreach ($environmentVariables as $environmentVariable) {
|
||||
$this->validatedBuildtimeEnvironmentVariableKey((string) $environmentVariable->key, 'the deployment environment');
|
||||
$key = (string) $environmentVariable->key;
|
||||
$isEnvFileSafe = $key !== '' && strpbrk($key, "=\n\r\0") === false;
|
||||
if ($environmentVariable->is_buildtime || ! $isEnvFileSafe) {
|
||||
$this->validatedBuildtimeEnvironmentVariableKey($key, 'the deployment environment');
|
||||
|
||||
continue;
|
||||
}
|
||||
if (! ValidationPatterns::isValidEnvironmentVariableKey($key)) {
|
||||
$this->logLegacyRuntimeEnvironmentVariableKey($key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function logLegacyRuntimeEnvironmentVariableKey(string $key): void
|
||||
{
|
||||
$suggestedKey = (string) preg_replace('/[^A-Za-z0-9_]/', '_', $key);
|
||||
if (preg_match('/\A[0-9]/', $suggestedKey) === 1) {
|
||||
$suggestedKey = '_'.$suggestedKey;
|
||||
}
|
||||
|
||||
$this->application_deployment_queue->addLogEntry('⚠️ Runtime variable '.ValidationPatterns::displayShellEnvironmentVariableKey($key).' uses a name that new variables cannot use. It is still passed to the container, but shell scripts cannot read it.', 'stderr');
|
||||
$this->application_deployment_queue->addLogEntry(' Suggested name: '.ValidationPatterns::displayShellEnvironmentVariableKey($suggestedKey), type: 'info');
|
||||
}
|
||||
|
||||
private function logInvalidBuildtimeEnvironmentVariableKey(string $key, string $origin): void
|
||||
{
|
||||
$displayKey = ValidationPatterns::displayShellEnvironmentVariableKey($key);
|
||||
|
||||
@@ -992,6 +992,44 @@ it('rejects an unsafe stored key before running a deployment command', function
|
||||
expect($job->recordedCommands)->toBeEmpty();
|
||||
});
|
||||
|
||||
it('keeps deploying existing runtime-only variables whose names new variables cannot use', function () {
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
$environmentVariable = createApplicationEnvironmentVariable($application, [
|
||||
'key' => 'SAFE_KEY',
|
||||
'value' => 'secret',
|
||||
'is_buildtime' => false,
|
||||
]);
|
||||
// Names like my-var were accepted before the current rules; the model no longer allows them.
|
||||
DB::table('environment_variables')->where('id', $environmentVariable->id)->update(['key' => 'my-var']);
|
||||
|
||||
[$job, $reflection] = makeControlVarFilteringJob($application->fresh(), $server);
|
||||
invokeDeploymentJobMethod($job, $reflection, 'validateDeploymentEnvironmentVariableKeys');
|
||||
|
||||
expect(collect($job->recordedLogEntries)->implode("\n"))
|
||||
->toContain('my-var')
|
||||
->toContain('Suggested name: my_var');
|
||||
expect($job->recordedCommands)->toBeEmpty();
|
||||
});
|
||||
|
||||
it('rejects existing variable names that would break the .env file or build commands', function (string $key, bool $isBuildtime) {
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
$environmentVariable = createApplicationEnvironmentVariable($application, [
|
||||
'key' => 'SAFE_KEY',
|
||||
'value' => 'secret',
|
||||
'is_buildtime' => $isBuildtime,
|
||||
]);
|
||||
DB::table('environment_variables')->where('id', $environmentVariable->id)->update(['key' => $key]);
|
||||
|
||||
[$job, $reflection] = makeControlVarFilteringJob($application->fresh(), $server);
|
||||
|
||||
expect(fn () => invokeDeploymentJobMethod($job, $reflection, 'validateDeploymentEnvironmentVariableKeys'))
|
||||
->toThrow(DeploymentException::class, 'Invalid environment variable name from the deployment environment');
|
||||
})->with([
|
||||
'runtime-only name with =' => ['A=B', false],
|
||||
'runtime-only name with a newline' => ["A\nB", false],
|
||||
'build-time name with a hyphen' => ['my-var', true],
|
||||
]);
|
||||
|
||||
it('injects raw escaped remote secrets into Dockerfile args and hashes the same values', function (int $pullRequestId, bool $isPreview) {
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user