mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 16:17:10 +00:00
feat(v5): authorize creates, deep-link selection, list apps in v4
Restrict V5 application and resource-connection creation to team admins. Resolve project, environment, and application from query params and keep session selection in sync. Surface V5 apps on the v4 resource index and count them for project/environment emptiness. Create the flux data dir on install and upgrade.
This commit is contained in:
1 parent
772093928f
commit
a4ab69df56
23 files changed
+299
-38
No files matched your search
@@ -3,6 +3,7 @@
|
||||
use App\Events\V5RealtimeTestEvent;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use App\Models\V5\Application;
|
||||
use App\Models\V5\Application as V5Application;
|
||||
use App\Models\V5\Server as V5Server;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
@@ -356,6 +357,36 @@ it('shares existing projects and environments with the v5 dashboard page', funct
|
||||
->assertDontSee($otherEnvironment->uuid);
|
||||
});
|
||||
|
||||
it('opens a linked v5 application in its project and environment', function () {
|
||||
$this->withoutVite();
|
||||
fakeFluxHealth();
|
||||
createSharedUserAndTeamTables();
|
||||
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
[$project, $environment] = createV5ProjectWithEnvironment($team, 'linked-project', 'production');
|
||||
$application = Application::query()->create([
|
||||
'team_id' => $team->id,
|
||||
'project_id' => $project->id,
|
||||
'environment_id' => $environment->id,
|
||||
'created_by_user_id' => $user->id,
|
||||
'name' => 'linked-nginx',
|
||||
'image' => 'nginx:alpine',
|
||||
'container_name' => 'linked-v5-nginx',
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession(['currentTeam' => $team])
|
||||
->get(route('v5.dashboard', [
|
||||
'project' => $project->uuid,
|
||||
'environment' => $environment->uuid,
|
||||
'application' => $application->uuid,
|
||||
]))
|
||||
->assertSuccessful()
|
||||
->assertSee('"selectedProjectUuid":"'.$project->uuid.'"', false)
|
||||
->assertSee('"selectedEnvironmentUuid":"'.$environment->uuid.'"', false)
|
||||
->assertSee('"selectedApplicationUuid":"'.$application->uuid.'"', false);
|
||||
});
|
||||
|
||||
it('persists the selected v5 project and environment in the session', function () {
|
||||
$this->withoutVite();
|
||||
fakeFluxHealth();
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
use App\Models\V5\Application as V5Application;
|
||||
use App\Models\V5\ResourceConnection;
|
||||
|
||||
beforeEach(function () {
|
||||
resetV5DashboardTestState();
|
||||
createSharedUserAndTeamTables();
|
||||
});
|
||||
|
||||
it('prevents team members from creating v5 applications', function () {
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
$user->teams()->updateExistingPivot($team->id, ['role' => 'member']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession(['currentTeam' => $team])
|
||||
->postJson('/v5/applications/nginx')
|
||||
->assertForbidden();
|
||||
|
||||
expect(V5Application::query()->count())->toBe(0);
|
||||
});
|
||||
|
||||
it('prevents team members from creating v5 resource connections', function () {
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
$user->teams()->updateExistingPivot($team->id, ['role' => 'member']);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession(['currentTeam' => $team])
|
||||
->postJson('/v5/resource-connections')
|
||||
->assertForbidden();
|
||||
|
||||
expect(ResourceConnection::query()->count())->toBe(0);
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
use App\Models\V5\Application as V5Application;
|
||||
use App\Models\V5\ResourceConnection;
|
||||
|
||||
beforeEach(function () {
|
||||
resetV5DashboardTestState();
|
||||
createSharedUserAndTeamTables();
|
||||
});
|
||||
|
||||
it('does not consider projects or environments with v5 applications empty', function () {
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
[$project, $environment] = createV5ProjectWithEnvironment($team, 'Project', 'production');
|
||||
|
||||
V5Application::query()->create([
|
||||
'team_id' => $team->id,
|
||||
'project_id' => $project->id,
|
||||
'environment_id' => $environment->id,
|
||||
'created_by_user_id' => $user->id,
|
||||
'name' => 'nginx',
|
||||
'image' => 'nginx:alpine',
|
||||
'container_name' => 'v5-nginx',
|
||||
]);
|
||||
|
||||
expect($project->isEmpty())->toBeFalse()
|
||||
->and($environment->isEmpty())->toBeFalse();
|
||||
});
|
||||
|
||||
it('does not consider projects or environments with v5 resource connections empty', function () {
|
||||
[$user, $team] = createV5UserWithTeam();
|
||||
[$project, $environment] = createV5ProjectWithEnvironment($team, 'Project', 'production');
|
||||
|
||||
ResourceConnection::query()->create([
|
||||
'team_id' => $team->id,
|
||||
'project_id' => $project->id,
|
||||
'environment_id' => $environment->id,
|
||||
'resource_one_type' => V5Application::class,
|
||||
'resource_one_id' => 1,
|
||||
'resource_two_type' => V5Application::class,
|
||||
'resource_two_id' => 2,
|
||||
'resource_pair_key' => 'application:1|application:2',
|
||||
'created_by_user_id' => $user->id,
|
||||
]);
|
||||
|
||||
expect($project->isEmpty())->toBeFalse()
|
||||
->and($environment->isEmpty())->toBeFalse();
|
||||
});
|
||||
@@ -56,6 +56,19 @@ it('generates a dedicated flux laravel api token during install and upgrade', fu
|
||||
'nightly upgrade' => 'other/nightly/upgrade.sh',
|
||||
]);
|
||||
|
||||
it('creates a writable flux storage directory during install and upgrade', function (string $path) {
|
||||
$script = file_get_contents(getcwd().'/'.$path);
|
||||
|
||||
expect($script)
|
||||
->toContain('/data/coolify/flux')
|
||||
->toContain('chown -R 9999:root /data/coolify/flux');
|
||||
})->with([
|
||||
'stable install' => 'scripts/install.sh',
|
||||
'nightly install' => 'other/nightly/install.sh',
|
||||
'stable upgrade' => 'scripts/upgrade.sh',
|
||||
'nightly upgrade' => 'other/nightly/upgrade.sh',
|
||||
]);
|
||||
|
||||
it('uses the selected registry url when extracting upgrade images', function (string $path) {
|
||||
$script = file_get_contents(getcwd().'/'.$path);
|
||||
|
||||
|
||||
@@ -230,6 +230,8 @@ it('denies application mutations for a member of the current team as forbidden',
|
||||
$member = v5PolicyMemberUser();
|
||||
$policy = new ApplicationPolicy;
|
||||
|
||||
expect($policy->create($member, $team)->denied())->toBeTrue();
|
||||
|
||||
foreach (['update', 'updateIngress', 'delete'] as $ability) {
|
||||
$response = $policy->{$ability}($member, $application, $team);
|
||||
|
||||
@@ -244,6 +246,8 @@ it('denies resource connection mutations for a member of the current team as for
|
||||
$member = v5PolicyMemberUser();
|
||||
$policy = new ResourceConnectionPolicy;
|
||||
|
||||
expect($policy->create($member, $team)->denied())->toBeTrue();
|
||||
|
||||
foreach (['update', 'delete'] as $ability) {
|
||||
$response = $policy->{$ability}($member, $connection, $team);
|
||||
|
||||
@@ -251,3 +255,11 @@ it('denies resource connection mutations for a member of the current team as for
|
||||
->and($response->status())->toBeNull();
|
||||
}
|
||||
});
|
||||
|
||||
it('allows admins to create applications and resource connections', function () {
|
||||
$team = v5PolicyTeam(10);
|
||||
$admin = v5PolicyUser('admin');
|
||||
|
||||
expect((new ApplicationPolicy)->create($admin, $team)->allowed())->toBeTrue()
|
||||
->and((new ResourceConnectionPolicy)->create($admin, $team)->allowed())->toBeTrue();
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
it('includes v5 applications in the v4 resource index and links them to v5', function () {
|
||||
$component = file_get_contents(app_path('Livewire/Project/Resource/Index.php'));
|
||||
$view = file_get_contents(resource_path('views/livewire/project/resource/index.blade.php'));
|
||||
|
||||
expect($component)
|
||||
->toContain('V5Application')
|
||||
->toContain("route('v5.dashboard'")
|
||||
->toContain("? 'v5' : 'v4'")
|
||||
->and($view)
|
||||
->toContain("item.version === 'v5'")
|
||||
->toContain('V5');
|
||||
});
|
||||
Reference in new issue
Block a user