feat(logging): strengthen secret redaction and add admin controls (#12151)

This commit is contained in:
Andras Bacsai
2026-10-13 20:43:19 +02:00
committed by GitHub
parent 9302395063
commit 448dc8ea0a
92 changed files with 4582 additions and 417 deletions
+52
View File
@@ -1,10 +1,20 @@
<?php
use App\Models\Application;
use App\Models\ApplicationDeploymentQueue;
use App\Models\ApplicationSetting;
use App\Models\GitlabApp;
use App\Models\InstanceSettings;
use App\Models\PrivateKey;
use App\Models\Server;
use App\Traits\ExecuteRemoteCommand;
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Process;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;
uses(TestCase::class, LazilyRefreshDatabase::class);
afterEach(function () {
Mockery::close();
@@ -66,6 +76,48 @@ it('skips logging the docker deploy key materialization command before ls-remote
->and(substr($source, $commandPosition, 200))->toContain("'skip_command_log' => true");
});
it('supports skipping command log entries without adding a hidden command entry', function () {
Storage::fake('ssh-keys');
Storage::fake('ssh-mux');
config(['constants.ssh.mux_enabled' => false]);
InstanceSettings::forceCreate(['id' => 0]);
$privateKey = PrivateKey::factory()->create();
$server = Server::factory()->create([
'team_id' => $privateKey->team_id,
'private_key_id' => $privateKey->id,
]);
$application = Application::factory()->create();
$deployment = ApplicationDeploymentQueue::query()->create([
'application_id' => $application->id,
'deployment_uuid' => fake()->uuid(),
]);
$payload = base64_encode('private-deploy-key-material');
$command = "echo '{$payload}' | base64 -d | tee /root/.ssh/id_rsa_coolify_test";
Process::fake(['*' => Process::result(output: "materialized {$payload}")]);
$job = new class($server, $application, $deployment)
{
use ExecuteRemoteCommand;
public function __construct(
public Server $server,
public Application $application,
public ApplicationDeploymentQueue $application_deployment_queue,
) {}
};
(new ReflectionMethod($job, 'executeCommandWithProcess'))->invoke(
$job, $command, false, null, true, false, true, true,
);
$storedLogs = $deployment->refresh()->getRawOriginal('logs');
$logs = json_decode($storedLogs, true, flags: JSON_THROW_ON_ERROR);
expect($logs)->toHaveCount(1)
->and($logs[0]['command'])->toBeNull()
->and($logs[0]['output'])->toBe('materialized '.REDACTED);
expect($storedLogs)->not->toContain($payload)->not->toContain($command);
Process::assertRan(fn ($process) => str_contains($process->command, $command));
});
it('writes a deploy key to a per-deployment path and cleans it up for ls-remote on the host', function () use ($keyPath) {
$privateKey = Mockery::mock(PrivateKey::class)->makePartial();
$privateKey->shouldReceive('getAttribute')->with('private_key')->andReturn('fake-private-key');