feat(security): add editable cloud credential pages

Add dedicated show/edit pages for cloud provider tokens and cloud-init
scripts, including descriptions and UUID routes.

Generate private keys directly from the index and surface cloud provider
API loading errors in server creation flows.
This commit is contained in:
Andras Bacsai committed 2026-07-08 12:58:27 +02:00
1 parent 7236cb8228
commit e200d881f5
36 files changed
+1196 -126

No files matched your search

@@ -1,6 +1,8 @@
<?php
use App\Livewire\Security\CloudProviderTokenForm;
use App\Livewire\Security\CloudProviderTokens;
use App\Models\CloudProviderToken;
use App\Models\InstanceSettings;
use App\Models\Team;
use App\Models\User;
@@ -52,3 +54,36 @@ test('adding a digitalocean token from a modal closes the modal and refreshes di
->and($dispatches->contains(fn (array $dispatch) => $dispatch['name'] === 'tokenAdded'
&& data_get($dispatch, 'to') === 'security.cloud-provider-tokens'))->toBeTrue();
});
test('adding a cloud provider token stores an optional description', function () {
Http::fake([
'https://api.hetzner.cloud/v1/servers' => Http::response([], 200),
]);
Livewire::test(CloudProviderTokenForm::class)
->set('provider', 'hetzner')
->set('name', 'Production Hetzner')
->set('description', 'Used for production servers in the EU region.')
->set('token', 'hetzner-token')
->call('addToken')
->assertHasNoErrors();
$this->assertDatabaseHas('cloud_provider_tokens', [
'team_id' => $this->team->id,
'provider' => 'hetzner',
'name' => 'Production Hetzner',
'description' => 'Used for production servers in the EU region.',
]);
});
test('saved cloud provider tokens show descriptions when present', function () {
CloudProviderToken::factory()->create([
'team_id' => $this->team->id,
'name' => 'Production Hetzner',
'description' => 'Used for production servers in the EU region.',
]);
Livewire::test(CloudProviderTokens::class)
->assertSee('Production Hetzner')
->assertSee('Used for production servers in the EU region.');
});