mirror of
https://github.com/coollabsio/coolify.git
synced 2026-09-26 09:20:54 -04:00
Improve deployment log value handling
This commit is contained in:
@@ -192,7 +192,7 @@ class ApplicationDeploymentQueue extends Model
|
||||
$lockedVars = $lockedVars->merge(
|
||||
$app->environment_variables
|
||||
->where('is_shown_once', true)
|
||||
->pluck('real_value', 'key')
|
||||
->flatMap(fn (EnvironmentVariable $variable): array => $variable->logRedactionValues())
|
||||
->filter()
|
||||
);
|
||||
}
|
||||
@@ -201,7 +201,7 @@ class ApplicationDeploymentQueue extends Model
|
||||
$lockedVars = $lockedVars->merge(
|
||||
$app->environment_variables_preview
|
||||
->where('is_shown_once', true)
|
||||
->pluck('real_value', 'key')
|
||||
->flatMap(fn (EnvironmentVariable $variable): array => $variable->logRedactionValues())
|
||||
->filter()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -309,6 +309,30 @@ class EnvironmentVariable extends BaseModel
|
||||
return $real_value;
|
||||
}
|
||||
|
||||
/** @return array<int, string> */
|
||||
public function logRedactionValues(): array
|
||||
{
|
||||
$value = $this->real_value;
|
||||
if (! is_string($value) || $value === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$values = [$value];
|
||||
if ($this->is_multiline || $this->is_literal) {
|
||||
$unquoted = str_starts_with($value, "'") && str_ends_with($value, "'")
|
||||
? substr($value, 1, -1)
|
||||
: $value;
|
||||
$values[] = $unquoted;
|
||||
$values[] = escapeBashEnvValue($unquoted);
|
||||
$values[] = str_replace(["\r\n", "\r", "\n"], ['\\n', '\\n', '\\n'], $unquoted);
|
||||
if ($this->is_multiline) {
|
||||
$values = array_merge($values, preg_split('/\r\n|\r|\n/', $unquoted) ?: []);
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique(array_filter($values, static fn (string $item): bool => $item !== '')));
|
||||
}
|
||||
|
||||
public function resolveReferencedValue(): ?string
|
||||
{
|
||||
$value = $this->value;
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Traits;
|
||||
use App\Enums\ApplicationDeploymentStatus;
|
||||
use App\Exceptions\DeploymentException;
|
||||
use App\Helpers\SshMultiplexingHelper;
|
||||
use App\Models\EnvironmentVariable;
|
||||
use App\Models\Server;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -33,7 +34,7 @@ trait ExecuteRemoteCommand
|
||||
$lockedVars = $lockedVars->merge(
|
||||
$this->application->environment_variables
|
||||
->where('is_shown_once', true)
|
||||
->pluck('real_value', 'key')
|
||||
->flatMap(fn (EnvironmentVariable $variable): array => $variable->logRedactionValues())
|
||||
->filter()
|
||||
);
|
||||
}
|
||||
@@ -42,7 +43,7 @@ trait ExecuteRemoteCommand
|
||||
$lockedVars = $lockedVars->merge(
|
||||
$this->application->environment_variables_preview
|
||||
->where('is_shown_once', true)
|
||||
->pluck('real_value', 'key')
|
||||
->flatMap(fn (EnvironmentVariable $variable): array => $variable->logRedactionValues())
|
||||
->filter()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\EnvironmentVariable;
|
||||
use App\Models\Project;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
@@ -64,6 +65,75 @@ it('redacts resolved remote secrets from command output', function () {
|
||||
->toBe('token='.REDACTED);
|
||||
});
|
||||
|
||||
it('does not retain locked values from generated build-time debug logs', function () {
|
||||
config()->set('app.env', 'local');
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
|
||||
createApplicationEnvironmentVariable($application, [
|
||||
'key' => 'SINGLE_MARKER',
|
||||
'value' => 'harmless-single-marker',
|
||||
'is_shown_once' => true,
|
||||
]);
|
||||
createApplicationEnvironmentVariable($application, [
|
||||
'key' => 'MULTILINE_MARKER',
|
||||
'value' => "harmless-first-marker\nharmless-second-marker",
|
||||
'is_multiline' => true,
|
||||
'is_shown_once' => true,
|
||||
]);
|
||||
|
||||
[$job, $reflection] = makeControlVarFilteringJob($application, $server);
|
||||
invokeDeploymentJobMethod($job, $reflection, 'generate_buildtime_environment_variables');
|
||||
|
||||
$deployment = ApplicationDeploymentQueue::create([
|
||||
'deployment_uuid' => 'harmless-debug-log-deployment',
|
||||
'application_id' => $application->id,
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
foreach ($job->recordedLogEntries as $entry) {
|
||||
$deployment->addLogEntry($entry);
|
||||
}
|
||||
|
||||
$retainedLogs = $deployment->fresh()->logs;
|
||||
expect($retainedLogs)
|
||||
->not->toContain('harmless-single-marker')
|
||||
->not->toContain('harmless-first-marker')
|
||||
->not->toContain('harmless-second-marker')
|
||||
->toContain(REDACTED);
|
||||
|
||||
$member = User::factory()->create();
|
||||
$application->team()->members()->attach($member->id, ['role' => 'member']);
|
||||
$application->settings->update(['is_debug_enabled' => true]);
|
||||
$this->actingAs($member);
|
||||
|
||||
$visibleLines = decode_remote_command_output($deployment->fresh())->pluck('line')->implode("\n");
|
||||
expect($visibleLines)
|
||||
->toContain('[DEBUG]')
|
||||
->not->toContain('harmless-first-marker')
|
||||
->not->toContain('harmless-second-marker');
|
||||
});
|
||||
|
||||
it('redacts generated multiline forms in remote command and output logging', function () {
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
createApplicationEnvironmentVariable($application, [
|
||||
'key' => 'MULTILINE_MARKER',
|
||||
'value' => "harmless-first-marker\nharmless-second-marker",
|
||||
'is_multiline' => true,
|
||||
'is_shown_once' => true,
|
||||
]);
|
||||
|
||||
[$job, $reflection] = makeControlVarFilteringJob($application, $server);
|
||||
$generated = invokeDeploymentJobMethod($job, $reflection, 'generate_buildtime_environment_variables')
|
||||
->first(fn (string $line): bool => str_starts_with($line, 'MULTILINE_MARKER='));
|
||||
|
||||
foreach ([$generated, str_replace("\n", '\\n', $generated), 'harmless-second-marker'] as $loggedForm) {
|
||||
$redacted = invokeDeploymentJobMethod($job, $reflection, 'redact_sensitive_info', 'output: '.$loggedForm);
|
||||
expect($redacted)
|
||||
->not->toContain('harmless-first-marker')
|
||||
->not->toContain('harmless-second-marker')
|
||||
->toContain('output: ');
|
||||
}
|
||||
});
|
||||
|
||||
it('ignores empty and non-string remote secrets when redacting command output', function () {
|
||||
[$application, $server] = makeDeploymentControlVarFixture();
|
||||
[$job, $reflection] = makeControlVarFilteringJob($application, $server, [
|
||||
|
||||
Reference in New Issue
Block a user