mirror of
https://github.com/coollabsio/coolify.git
synced 2026-06-19 07:35:25 +00:00
fix(api): apply private_key_uuid in update_server (#10416)
This commit is contained in:
@@ -705,17 +705,17 @@ class ServersController extends Controller
|
||||
$validProxyTypes = collect(ProxyTypes::cases())->map(function ($proxyType) {
|
||||
return str($proxyType->value)->lower();
|
||||
});
|
||||
if ($validProxyTypes->contains(str($request->proxy_type)->lower())) {
|
||||
$server->changeProxy($request->proxy_type, async: true);
|
||||
} else {
|
||||
if (! $validProxyTypes->contains(str($request->proxy_type)->lower())) {
|
||||
return response()->json(['message' => 'Invalid proxy type.'], 422);
|
||||
}
|
||||
}
|
||||
$server->update($request->only(['name', 'description', 'ip', 'port', 'user']));
|
||||
if ($request->is_build_server) {
|
||||
$server->settings()->update([
|
||||
'is_build_server' => $request->is_build_server,
|
||||
]);
|
||||
$updateFields = $request->only(['name', 'description', 'ip', 'port', 'user']);
|
||||
if ($request->filled('private_key_uuid')) {
|
||||
$privateKey = PrivateKey::whereTeamId($teamId)->whereUuid($request->private_key_uuid)->first();
|
||||
if (! $privateKey) {
|
||||
return response()->json(['message' => 'Private key not found.'], 404);
|
||||
}
|
||||
$updateFields['private_key_id'] = $privateKey->id;
|
||||
}
|
||||
|
||||
if ($request->has('server_disk_usage_check_frequency') && ! validate_cron_expression($request->server_disk_usage_check_frequency)) {
|
||||
@@ -725,11 +725,22 @@ class ServersController extends Controller
|
||||
], 422);
|
||||
}
|
||||
|
||||
$server->update($updateFields);
|
||||
if ($request->has('is_build_server')) {
|
||||
$server->settings()->update([
|
||||
'is_build_server' => $request->boolean('is_build_server'),
|
||||
]);
|
||||
}
|
||||
|
||||
$advancedSettings = $request->only(['concurrent_builds', 'dynamic_timeout', 'deployment_queue_limit', 'server_disk_usage_notification_threshold', 'server_disk_usage_check_frequency', 'connection_timeout']);
|
||||
if (! empty($advancedSettings)) {
|
||||
$server->settings()->update(array_filter($advancedSettings, fn ($value) => ! is_null($value)));
|
||||
}
|
||||
|
||||
if ($request->proxy_type) {
|
||||
$server->changeProxy($request->proxy_type, async: true);
|
||||
}
|
||||
|
||||
if ($request->instant_validate) {
|
||||
ValidateServer::dispatch($server);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\PrivateKey;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
config()->set('app.maintenance.driver', 'file');
|
||||
config()->set('cache.default', 'array');
|
||||
|
||||
InstanceSettings::forceCreate(['id' => 0, 'is_api_enabled' => true]);
|
||||
|
||||
$this->team = Team::factory()->create();
|
||||
$this->user = User::factory()->create();
|
||||
$this->team->members()->attach($this->user->id, ['role' => 'owner']);
|
||||
session(['currentTeam' => $this->team]);
|
||||
|
||||
$this->oldPrivateKey = createServerUpdatePrivateKeyApiKey($this->team, 'Old Key');
|
||||
$this->newPrivateKey = createServerUpdatePrivateKeyApiKey($this->team, 'New Key');
|
||||
|
||||
$this->server = Server::factory()->create([
|
||||
'team_id' => $this->team->id,
|
||||
'private_key_id' => $this->oldPrivateKey->id,
|
||||
]);
|
||||
|
||||
$token = $this->user->createToken('write-token', ['write']);
|
||||
$token->accessToken->forceFill(['team_id' => $this->team->id])->save();
|
||||
$this->bearerToken = $token->plainTextToken;
|
||||
});
|
||||
|
||||
function createServerUpdatePrivateKeyApiKey(Team $team, string $name): PrivateKey
|
||||
{
|
||||
return PrivateKey::create([
|
||||
'name' => $name,
|
||||
'private_key' => generateSSHKey('ed25519')['private'],
|
||||
'team_id' => $team->id,
|
||||
]);
|
||||
}
|
||||
|
||||
function patchServerUpdatePrivateKeyApi(object $test, Server $server, string $bearerToken, array $payload): TestResponse
|
||||
{
|
||||
return $test->withHeaders([
|
||||
'Authorization' => 'Bearer '.$bearerToken,
|
||||
'Content-Type' => 'application/json',
|
||||
])->patchJson('/api/v1/servers/'.$server->uuid, $payload);
|
||||
}
|
||||
|
||||
it('updates the server private key from private_key_uuid', function () {
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'private_key_uuid' => $this->newPrivateKey->uuid,
|
||||
])->assertCreated()
|
||||
->assertJson(['uuid' => $this->server->uuid]);
|
||||
|
||||
expect($this->server->fresh()->private_key_id)->toBe($this->newPrivateKey->id);
|
||||
});
|
||||
|
||||
it('returns not found for an unknown private_key_uuid and leaves the key unchanged', function () {
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'private_key_uuid' => 'unknown-private-key-uuid',
|
||||
])->assertNotFound()
|
||||
->assertJson(['message' => 'Private key not found.']);
|
||||
|
||||
expect($this->server->fresh()->private_key_id)->toBe($this->oldPrivateKey->id);
|
||||
});
|
||||
|
||||
it('does not allow attaching a private key from another team', function () {
|
||||
$otherTeam = Team::factory()->create();
|
||||
$otherTeamPrivateKey = createServerUpdatePrivateKeyApiKey($otherTeam, 'Other Team Key');
|
||||
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'private_key_uuid' => $otherTeamPrivateKey->uuid,
|
||||
])->assertNotFound()
|
||||
->assertJson(['message' => 'Private key not found.']);
|
||||
|
||||
expect($this->server->fresh()->private_key_id)->toBe($this->oldPrivateKey->id);
|
||||
});
|
||||
|
||||
it('keeps the existing private key when private_key_uuid is omitted', function () {
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'name' => 'Renamed Server',
|
||||
])->assertCreated()
|
||||
->assertJson(['uuid' => $this->server->uuid]);
|
||||
|
||||
$server = $this->server->fresh();
|
||||
|
||||
expect($server->name)->toBe('Renamed Server')
|
||||
->and($server->private_key_id)->toBe($this->oldPrivateKey->id);
|
||||
});
|
||||
|
||||
it('can disable build server mode via API', function () {
|
||||
$this->server->settings()->update(['is_build_server' => true]);
|
||||
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'is_build_server' => false,
|
||||
])->assertCreated()
|
||||
->assertJson(['uuid' => $this->server->uuid]);
|
||||
|
||||
expect($this->server->settings->fresh()->is_build_server)->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects an invalid disk usage check frequency without partially updating the server', function () {
|
||||
$this->server->proxy->set('type', 'TRAEFIK');
|
||||
$this->server->save();
|
||||
$this->server->settings()->update(['is_build_server' => false]);
|
||||
|
||||
patchServerUpdatePrivateKeyApi($this, $this->server, $this->bearerToken, [
|
||||
'name' => 'Renamed Server',
|
||||
'is_build_server' => true,
|
||||
'proxy_type' => 'none',
|
||||
'server_disk_usage_check_frequency' => 'not a valid schedule',
|
||||
])->assertUnprocessable()
|
||||
->assertJson([
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => [
|
||||
'server_disk_usage_check_frequency' => ['Invalid Cron / Human expression for Disk Usage Check Frequency.'],
|
||||
],
|
||||
]);
|
||||
|
||||
$server = $this->server->fresh();
|
||||
|
||||
expect($server->name)->not->toBe('Renamed Server')
|
||||
->and($server->settings->is_build_server)->toBeFalse()
|
||||
->and($server->proxy->get('type'))->toBe('TRAEFIK');
|
||||
});
|
||||
Reference in New Issue
Block a user