mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-04 10:42:23 +00:00
251 lines
11 KiB
PHP
251 lines
11 KiB
PHP
<?php
|
|
|
|
use App\Models\Application;
|
|
use App\Models\GitlabApp;
|
|
use App\Models\PrivateKey;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Encryption\Encrypter;
|
|
use Illuminate\Support\Collection;
|
|
|
|
beforeEach(function () {
|
|
Model::encryptUsing(new Encrypter(str_repeat('a', 32), 'AES-256-CBC'));
|
|
});
|
|
|
|
afterEach(function () {
|
|
Model::encryptUsing(null);
|
|
Mockery::close();
|
|
});
|
|
|
|
function gitlabCommandStrings(array|Collection|string $commands): Collection
|
|
{
|
|
if (is_string($commands)) {
|
|
return collect([$commands]);
|
|
}
|
|
|
|
return collect($commands)->map(fn ($command) => data_get($command, 'command') ?? $command[0] ?? $command);
|
|
}
|
|
|
|
function expectGitlabCommandListToContain(array|Collection|string $commands, string $expected): void
|
|
{
|
|
expect(gitlabCommandStrings($commands)->implode(' && '))->toContain($expected);
|
|
}
|
|
|
|
function expectGitlabCommandListNotToContain(array|Collection|string $commands, string $expected): void
|
|
{
|
|
expect(gitlabCommandStrings($commands)->implode(' && '))->not->toContain($expected);
|
|
}
|
|
|
|
function expectGitlabPrivateKeyMaterializationCommandsSkipLogging(array|Collection|string $commands): void
|
|
{
|
|
if (is_string($commands)) {
|
|
$commands = [$commands];
|
|
}
|
|
|
|
$keyCommands = collect($commands)->filter(fn ($command) => str(data_get($command, 'command') ?? $command[0] ?? $command)->contains('base64 -d | tee /root/.ssh/id_rsa_coolify_'));
|
|
|
|
expect($keyCommands)->not->toBeEmpty();
|
|
$keyCommands->each(function ($command): void {
|
|
expect(data_get($command, 'skip_command_log'))->toBeTrue();
|
|
});
|
|
}
|
|
|
|
it('generates ls-remote commands for GitLab source with private key', function () {
|
|
$deploymentUuid = 'test-deployment-uuid';
|
|
|
|
$privateKey = Mockery::mock(PrivateKey::class)->makePartial();
|
|
$privateKey->shouldReceive('getAttribute')->with('private_key')->andReturn('fake-private-key');
|
|
|
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(GitlabApp::class);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('html_url')->andReturn('https://gitlab.com');
|
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn($privateKey);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(1);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('custom_port')->andReturn(22);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('access_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('refresh_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('isConnected')->andReturn(false);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'git@gitlab.com:user/repo.git',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->source = $gitlabSource;
|
|
|
|
$result = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
|
|
|
expect($result)->toBeArray();
|
|
expect($result)->toHaveKey('commands');
|
|
expectGitlabCommandListToContain($result['commands'], 'git ls-remote');
|
|
expectGitlabCommandListToContain($result['commands'], 'id_rsa');
|
|
expectGitlabCommandListToContain($result['commands'], 'mkdir -p /root/.ssh');
|
|
expectGitlabPrivateKeyMaterializationCommandsSkipLogging($result['commands']);
|
|
});
|
|
|
|
it('generates ls-remote commands for GitLab source without private key', function () {
|
|
$deploymentUuid = 'test-deployment-uuid';
|
|
|
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(GitlabApp::class);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('html_url')->andReturn('https://gitlab.com');
|
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('access_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('refresh_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('isConnected')->andReturn(false);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'https://gitlab.com/user/repo.git',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->source = $gitlabSource;
|
|
|
|
$result = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
|
|
|
expect($result)->toBeArray();
|
|
expect($result)->toHaveKey('commands');
|
|
expectGitlabCommandListToContain($result['commands'], 'git ls-remote');
|
|
expectGitlabCommandListToContain($result['commands'], 'https://gitlab.com/user/repo.git');
|
|
// Should NOT contain SSH key setup
|
|
expectGitlabCommandListNotToContain($result['commands'], 'id_rsa');
|
|
});
|
|
|
|
it('does not return null for GitLab source type', function () {
|
|
$deploymentUuid = 'test-deployment-uuid';
|
|
|
|
$gitlabSource = Mockery::mock(GitlabApp::class)->makePartial();
|
|
$gitlabSource->shouldReceive('getMorphClass')->andReturn(GitlabApp::class);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('html_url')->andReturn('https://gitlab.com');
|
|
$gitlabSource->shouldReceive('getAttribute')->with('privateKey')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('private_key_id')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('access_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('getAttribute')->with('refresh_token')->andReturn(null);
|
|
$gitlabSource->shouldReceive('isConnected')->andReturn(false);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'https://gitlab.com/user/repo.git',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->source = $gitlabSource;
|
|
|
|
$lsRemoteResult = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
|
expect($lsRemoteResult)->not->toBeNull();
|
|
expect($lsRemoteResult)->toHaveKeys(['commands', 'branch', 'fullRepoUrl']);
|
|
});
|
|
|
|
it('preserves custom GitLab http port for connected OAuth sources', function () {
|
|
$deploymentUuid = 'test-deployment-uuid';
|
|
|
|
$gitlabSource = new GitlabApp([
|
|
'html_url' => 'http://gitlab.example.test:8081',
|
|
'access_token' => 'gitlab-access-token',
|
|
'refresh_token' => 'gitlab-refresh-token',
|
|
'expires_at' => time() + 3600,
|
|
]);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'root/qa-private-app',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->source = $gitlabSource;
|
|
|
|
$result = $application->generateGitLsRemoteCommands($deploymentUuid, false);
|
|
|
|
expect($result['fullRepoUrl'])
|
|
->toContain('gitlab.example.test:8081')
|
|
->toBe('http://oauth2:gitlab-access-token@gitlab.example.test:8081/root/qa-private-app.git');
|
|
expect($result['commands'])->toContain('gitlab.example.test:8081/root/qa-private-app.git');
|
|
});
|
|
|
|
it('applies OAuth git config to GitLab merge-request fetch and submodule checkout', function () {
|
|
$deploymentUuid = 'test-deployment-uuid';
|
|
|
|
$gitlabSource = new GitlabApp([
|
|
'html_url' => 'https://gitlab.example.test',
|
|
'access_token' => 'gitlab-access-token',
|
|
'refresh_token' => 'gitlab-refresh-token',
|
|
'expires_at' => time() + 3600,
|
|
]);
|
|
|
|
$settings = (object) [
|
|
'is_git_shallow_clone_enabled' => false,
|
|
'is_git_submodules_enabled' => true,
|
|
];
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'root/qa-private-app',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->shouldReceive('getAttribute')->with('settings')->andReturn($settings);
|
|
$application->source = $gitlabSource;
|
|
|
|
$result = $application->generateGitImportCommands(
|
|
deployment_uuid: $deploymentUuid,
|
|
pull_request_id: 2,
|
|
exec_in_docker: false,
|
|
only_checkout: true,
|
|
custom_base_dir: '/artifacts/test',
|
|
);
|
|
|
|
$commands = $result['commands'];
|
|
// The MR-ref fetch and submodule update must run through the OAuth-rewritten git, or private same-host submodules fail.
|
|
expect($commands)
|
|
->toContain('oauth2:gitlab-access-token@gitlab.example.test')
|
|
->toContain(".insteadOf=https://gitlab.example.test/' fetch origin 'merge-requests/2/head:pr-2-coolify'")
|
|
->toContain(".insteadOf=https://gitlab.example.test/' submodule update --init --recursive");
|
|
});
|
|
|
|
it('uses a GitLab source private key only when it belongs to the source team', function (int $keyTeamId, bool $expectKey) {
|
|
$privateKey = new PrivateKey;
|
|
$privateKey->forceFill(['team_id' => $keyTeamId, 'private_key' => 'fake-private-key']);
|
|
|
|
$gitlabSource = new GitlabApp(['html_url' => 'https://gitlab.com', 'custom_port' => 22]);
|
|
$gitlabSource->forceFill(['team_id' => 1]);
|
|
$gitlabSource->setRelation('privateKey', $privateKey);
|
|
|
|
$application = Mockery::mock(Application::class)->makePartial();
|
|
$application->git_branch = 'main';
|
|
$application->shouldReceive('deploymentType')->andReturn('source');
|
|
$application->shouldReceive('customRepository')->andReturn([
|
|
'repository' => 'git@gitlab.com:user/repo.git',
|
|
'port' => 22,
|
|
]);
|
|
$application->shouldReceive('getAttribute')->with('source')->andReturn($gitlabSource);
|
|
$application->shouldReceive('getAttribute')->with('settings')->andReturn((object) [
|
|
'is_git_shallow_clone_enabled' => false,
|
|
'is_git_submodules_enabled' => false,
|
|
]);
|
|
$application->source = $gitlabSource;
|
|
|
|
$lsRemote = $application->generateGitLsRemoteCommands('test-deployment-uuid', false)['commands'];
|
|
$import = $application->generateGitImportCommands(deployment_uuid: 'test-deployment-uuid', exec_in_docker: false)['commands'];
|
|
|
|
foreach ([$lsRemote, $import] as $commands) {
|
|
$expectKey
|
|
? expectGitlabCommandListToContain($commands, 'id_rsa_coolify_')
|
|
: expectGitlabCommandListNotToContain($commands, 'id_rsa_coolify_');
|
|
}
|
|
})->with([
|
|
'same team' => [1, true],
|
|
'other team' => [2, false],
|
|
]);
|