mirror of
https://github.com/coollabsio/coolify.git
synced 2026-11-06 13:10:37 -04:00
fix(api): require deploy ability to run scheduled tasks (#12194)
This commit is contained in:
@@ -33,6 +33,20 @@ class ScheduledTasksController extends Controller
|
||||
return request()->attributes->get('can_read_sensitive', false) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scheduler runs an enabled task's command in the resource's containers, so the token needs the deploy permission.
|
||||
*/
|
||||
private function enabledTaskForbiddenResponse(Request $request, bool $enabled): ?JsonResponse
|
||||
{
|
||||
if (! $enabled || $request->user()->tokenCan('deploy') || $request->user()->tokenCan('root')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Missing required permissions: deploy. An enabled scheduled task runs commands in the resource containers, so it needs a token with the deploy permission.',
|
||||
], 403);
|
||||
}
|
||||
|
||||
private function resolveApplication(Request $request, int $teamId): ?Application
|
||||
{
|
||||
return Application::ownedByCurrentTeamAPI($teamId)->where('uuid', $request->uuid)->first();
|
||||
@@ -96,6 +110,11 @@ class ScheduledTasksController extends Controller
|
||||
], 422);
|
||||
}
|
||||
|
||||
$enabled = $request->has('enabled') ? $request->boolean('enabled') : true;
|
||||
if ($response = $this->enabledTaskForbiddenResponse($request, $enabled)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$teamId = getTeamIdFromToken();
|
||||
|
||||
$task = new ScheduledTask;
|
||||
@@ -104,7 +123,7 @@ class ScheduledTasksController extends Controller
|
||||
$task->frequency = $request->frequency;
|
||||
$task->container = $request->container;
|
||||
$task->timeout = $request->has('timeout') ? $request->timeout : 300;
|
||||
$task->enabled = $request->has('enabled') ? $request->enabled : true;
|
||||
$task->enabled = $enabled;
|
||||
$task->team_id = $teamId;
|
||||
|
||||
if ($resource instanceof Application) {
|
||||
@@ -177,6 +196,11 @@ class ScheduledTasksController extends Controller
|
||||
return response()->json(['message' => 'Scheduled task not found.'], 404);
|
||||
}
|
||||
|
||||
$enabled = $request->has('enabled') ? $request->boolean('enabled') : $task->enabled;
|
||||
if ($response = $this->enabledTaskForbiddenResponse($request, $enabled)) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$task->update($request->only($allowedFields));
|
||||
|
||||
auditLog('api.scheduled_task.updated', [
|
||||
@@ -351,7 +375,7 @@ class ScheduledTasksController extends Controller
|
||||
'frequency' => ['type' => 'string', 'description' => 'The frequency of the scheduled task.'],
|
||||
'container' => ['type' => 'string', 'nullable' => true, 'description' => 'The container where the command should be executed.'],
|
||||
'timeout' => ['type' => 'integer', 'description' => 'The timeout of the scheduled task in seconds.', 'default' => 300, 'maximum' => 36000],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled.', 'default' => true],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.', 'default' => true],
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -375,6 +399,10 @@ class ScheduledTasksController extends Controller
|
||||
response: 404,
|
||||
ref: '#/components/responses/404',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 403,
|
||||
description: 'The token needs the deploy ability for an enabled task.',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 422,
|
||||
ref: '#/components/responses/422',
|
||||
@@ -438,7 +466,7 @@ class ScheduledTasksController extends Controller
|
||||
'frequency' => ['type' => 'string', 'description' => 'The frequency of the scheduled task.'],
|
||||
'container' => ['type' => 'string', 'nullable' => true, 'description' => 'The container where the command should be executed.'],
|
||||
'timeout' => ['type' => 'integer', 'description' => 'The timeout of the scheduled task in seconds.', 'default' => 300, 'maximum' => 36000],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled.', 'default' => true],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.', 'default' => true],
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -462,6 +490,10 @@ class ScheduledTasksController extends Controller
|
||||
response: 404,
|
||||
ref: '#/components/responses/404',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 403,
|
||||
description: 'The token needs the deploy ability for an enabled task.',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 422,
|
||||
ref: '#/components/responses/422',
|
||||
@@ -714,7 +746,7 @@ class ScheduledTasksController extends Controller
|
||||
'frequency' => ['type' => 'string', 'description' => 'The frequency of the scheduled task.'],
|
||||
'container' => ['type' => 'string', 'nullable' => true, 'description' => 'The container where the command should be executed.'],
|
||||
'timeout' => ['type' => 'integer', 'description' => 'The timeout of the scheduled task in seconds.', 'default' => 300, 'maximum' => 36000],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled.', 'default' => true],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.', 'default' => true],
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -738,6 +770,10 @@ class ScheduledTasksController extends Controller
|
||||
response: 404,
|
||||
ref: '#/components/responses/404',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 403,
|
||||
description: 'The token needs the deploy ability for an enabled task.',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 422,
|
||||
ref: '#/components/responses/422',
|
||||
@@ -801,7 +837,7 @@ class ScheduledTasksController extends Controller
|
||||
'frequency' => ['type' => 'string', 'description' => 'The frequency of the scheduled task.'],
|
||||
'container' => ['type' => 'string', 'nullable' => true, 'description' => 'The container where the command should be executed.'],
|
||||
'timeout' => ['type' => 'integer', 'description' => 'The timeout of the scheduled task in seconds.', 'default' => 300, 'maximum' => 36000],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled.', 'default' => true],
|
||||
'enabled' => ['type' => 'boolean', 'description' => 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.', 'default' => true],
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -825,6 +861,10 @@ class ScheduledTasksController extends Controller
|
||||
response: 404,
|
||||
ref: '#/components/responses/404',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 403,
|
||||
description: 'The token needs the deploy ability for an enabled task.',
|
||||
),
|
||||
new OA\Response(
|
||||
response: 422,
|
||||
ref: '#/components/responses/422',
|
||||
@@ -986,7 +1026,7 @@ class ScheduledTasksController extends Controller
|
||||
|
||||
#[OA\Post(
|
||||
summary: 'Execute Task',
|
||||
description: 'Queue immediate execution of a scheduled task for an application.',
|
||||
description: 'Queue immediate execution of a scheduled task for an application. Requires the deploy ability.',
|
||||
path: '/applications/{uuid}/scheduled-tasks/{task_uuid}/execute',
|
||||
operationId: 'execute-scheduled-task-by-application-uuid',
|
||||
security: [['bearerAuth' => []]],
|
||||
@@ -998,6 +1038,7 @@ class ScheduledTasksController extends Controller
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Scheduled task execution queued.'),
|
||||
new OA\Response(response: 401, ref: '#/components/responses/401'),
|
||||
new OA\Response(response: 403, description: 'The token needs the deploy ability.'),
|
||||
new OA\Response(response: 404, ref: '#/components/responses/404'),
|
||||
]
|
||||
)]
|
||||
@@ -1018,7 +1059,7 @@ class ScheduledTasksController extends Controller
|
||||
|
||||
#[OA\Post(
|
||||
summary: 'Execute Task',
|
||||
description: 'Queue immediate execution of a scheduled task for a service.',
|
||||
description: 'Queue immediate execution of a scheduled task for a service. Requires the deploy ability.',
|
||||
path: '/services/{uuid}/scheduled-tasks/{task_uuid}/execute',
|
||||
operationId: 'execute-scheduled-task-by-service-uuid',
|
||||
security: [['bearerAuth' => []]],
|
||||
@@ -1030,6 +1071,7 @@ class ScheduledTasksController extends Controller
|
||||
responses: [
|
||||
new OA\Response(response: 200, description: 'Scheduled task execution queued.'),
|
||||
new OA\Response(response: 401, ref: '#/components/responses/401'),
|
||||
new OA\Response(response: 403, description: 'The token needs the deploy ability.'),
|
||||
new OA\Response(response: 404, ref: '#/components/responses/404'),
|
||||
]
|
||||
)]
|
||||
|
||||
+24
-6
@@ -14642,7 +14642,7 @@
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "The flag to indicate if the scheduled task is enabled.",
|
||||
"description": "The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
@@ -14668,6 +14668,9 @@
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability for an enabled task."
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#\/components\/responses\/422"
|
||||
}
|
||||
@@ -14796,7 +14799,7 @@
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "The flag to indicate if the scheduled task is enabled.",
|
||||
"description": "The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
@@ -14822,6 +14825,9 @@
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability for an enabled task."
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#\/components\/responses\/422"
|
||||
}
|
||||
@@ -14990,7 +14996,7 @@
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "The flag to indicate if the scheduled task is enabled.",
|
||||
"description": "The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
@@ -15016,6 +15022,9 @@
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability for an enabled task."
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#\/components\/responses\/422"
|
||||
}
|
||||
@@ -15144,7 +15153,7 @@
|
||||
},
|
||||
"enabled": {
|
||||
"type": "boolean",
|
||||
"description": "The flag to indicate if the scheduled task is enabled.",
|
||||
"description": "The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.",
|
||||
"default": true
|
||||
}
|
||||
},
|
||||
@@ -15170,6 +15179,9 @@
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability for an enabled task."
|
||||
},
|
||||
"422": {
|
||||
"$ref": "#\/components\/responses\/422"
|
||||
}
|
||||
@@ -15243,7 +15255,7 @@
|
||||
"Scheduled Tasks"
|
||||
],
|
||||
"summary": "Execute Task",
|
||||
"description": "Queue immediate execution of a scheduled task for an application.",
|
||||
"description": "Queue immediate execution of a scheduled task for an application. Requires the deploy ability.",
|
||||
"operationId": "execute-scheduled-task-by-application-uuid",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -15272,6 +15284,9 @@
|
||||
"401": {
|
||||
"$ref": "#\/components\/responses\/401"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability."
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
}
|
||||
@@ -15289,7 +15304,7 @@
|
||||
"Scheduled Tasks"
|
||||
],
|
||||
"summary": "Execute Task",
|
||||
"description": "Queue immediate execution of a scheduled task for a service.",
|
||||
"description": "Queue immediate execution of a scheduled task for a service. Requires the deploy ability.",
|
||||
"operationId": "execute-scheduled-task-by-service-uuid",
|
||||
"parameters": [
|
||||
{
|
||||
@@ -15318,6 +15333,9 @@
|
||||
"401": {
|
||||
"$ref": "#\/components\/responses\/401"
|
||||
},
|
||||
"403": {
|
||||
"description": "The token needs the deploy ability."
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#\/components\/responses\/404"
|
||||
}
|
||||
|
||||
+18
-6
@@ -9335,7 +9335,7 @@ paths:
|
||||
maximum: 36000
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 'The flag to indicate if the scheduled task is enabled.'
|
||||
description: 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.'
|
||||
default: true
|
||||
type: object
|
||||
responses:
|
||||
@@ -9349,6 +9349,8 @@ paths:
|
||||
$ref: '#/components/responses/401'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability for an enabled task.'
|
||||
'422':
|
||||
$ref: '#/components/responses/422'
|
||||
security:
|
||||
@@ -9440,7 +9442,7 @@ paths:
|
||||
maximum: 36000
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 'The flag to indicate if the scheduled task is enabled.'
|
||||
description: 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.'
|
||||
default: true
|
||||
type: object
|
||||
responses:
|
||||
@@ -9454,6 +9456,8 @@ paths:
|
||||
$ref: '#/components/responses/401'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability for an enabled task.'
|
||||
'422':
|
||||
$ref: '#/components/responses/422'
|
||||
security:
|
||||
@@ -9573,7 +9577,7 @@ paths:
|
||||
maximum: 36000
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 'The flag to indicate if the scheduled task is enabled.'
|
||||
description: 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.'
|
||||
default: true
|
||||
type: object
|
||||
responses:
|
||||
@@ -9587,6 +9591,8 @@ paths:
|
||||
$ref: '#/components/responses/401'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability for an enabled task.'
|
||||
'422':
|
||||
$ref: '#/components/responses/422'
|
||||
security:
|
||||
@@ -9678,7 +9684,7 @@ paths:
|
||||
maximum: 36000
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 'The flag to indicate if the scheduled task is enabled.'
|
||||
description: 'The flag to indicate if the scheduled task is enabled. An enabled task requires the deploy ability.'
|
||||
default: true
|
||||
type: object
|
||||
responses:
|
||||
@@ -9692,6 +9698,8 @@ paths:
|
||||
$ref: '#/components/responses/401'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability for an enabled task.'
|
||||
'422':
|
||||
$ref: '#/components/responses/422'
|
||||
security:
|
||||
@@ -9740,7 +9748,7 @@ paths:
|
||||
tags:
|
||||
- 'Scheduled Tasks'
|
||||
summary: 'Execute Task'
|
||||
description: 'Queue immediate execution of a scheduled task for an application.'
|
||||
description: 'Queue immediate execution of a scheduled task for an application. Requires the deploy ability.'
|
||||
operationId: execute-scheduled-task-by-application-uuid
|
||||
parameters:
|
||||
-
|
||||
@@ -9762,6 +9770,8 @@ paths:
|
||||
description: 'Scheduled task execution queued.'
|
||||
'401':
|
||||
$ref: '#/components/responses/401'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability.'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
security:
|
||||
@@ -9772,7 +9782,7 @@ paths:
|
||||
tags:
|
||||
- 'Scheduled Tasks'
|
||||
summary: 'Execute Task'
|
||||
description: 'Queue immediate execution of a scheduled task for a service.'
|
||||
description: 'Queue immediate execution of a scheduled task for a service. Requires the deploy ability.'
|
||||
operationId: execute-scheduled-task-by-service-uuid
|
||||
parameters:
|
||||
-
|
||||
@@ -9794,6 +9804,8 @@ paths:
|
||||
description: 'Scheduled task execution queued.'
|
||||
'401':
|
||||
$ref: '#/components/responses/401'
|
||||
'403':
|
||||
description: 'The token needs the deploy ability.'
|
||||
'404':
|
||||
$ref: '#/components/responses/404'
|
||||
security:
|
||||
|
||||
+2
-2
@@ -438,14 +438,14 @@ Route::group([
|
||||
Route::patch('/applications/{uuid}/scheduled-tasks/{task_uuid}', [ScheduledTasksController::class, 'update_scheduled_task_by_application_uuid'])->middleware(['api.ability:write']);
|
||||
Route::delete('/applications/{uuid}/scheduled-tasks/{task_uuid}', [ScheduledTasksController::class, 'delete_scheduled_task_by_application_uuid'])->middleware(['api.ability:write']);
|
||||
Route::get('/applications/{uuid}/scheduled-tasks/{task_uuid}/executions', [ScheduledTasksController::class, 'executions_by_application_uuid'])->middleware(['api.ability:read']);
|
||||
Route::post('/applications/{uuid}/scheduled-tasks/{task_uuid}/execute', [ScheduledTasksController::class, 'execute_scheduled_task_by_application_uuid'])->middleware(['api.ability:write']);
|
||||
Route::post('/applications/{uuid}/scheduled-tasks/{task_uuid}/execute', [ScheduledTasksController::class, 'execute_scheduled_task_by_application_uuid'])->middleware(['api.ability:deploy']);
|
||||
|
||||
Route::get('/services/{uuid}/scheduled-tasks', [ScheduledTasksController::class, 'scheduled_tasks_by_service_uuid'])->middleware(['api.ability:read']);
|
||||
Route::post('/services/{uuid}/scheduled-tasks', [ScheduledTasksController::class, 'create_scheduled_task_by_service_uuid'])->middleware(['api.ability:write']);
|
||||
Route::patch('/services/{uuid}/scheduled-tasks/{task_uuid}', [ScheduledTasksController::class, 'update_scheduled_task_by_service_uuid'])->middleware(['api.ability:write']);
|
||||
Route::delete('/services/{uuid}/scheduled-tasks/{task_uuid}', [ScheduledTasksController::class, 'delete_scheduled_task_by_service_uuid'])->middleware(['api.ability:write']);
|
||||
Route::get('/services/{uuid}/scheduled-tasks/{task_uuid}/executions', [ScheduledTasksController::class, 'executions_by_service_uuid'])->middleware(['api.ability:read']);
|
||||
Route::post('/services/{uuid}/scheduled-tasks/{task_uuid}/execute', [ScheduledTasksController::class, 'execute_scheduled_task_by_service_uuid'])->middleware(['api.ability:write']);
|
||||
Route::post('/services/{uuid}/scheduled-tasks/{task_uuid}/execute', [ScheduledTasksController::class, 'execute_scheduled_task_by_service_uuid'])->middleware(['api.ability:deploy']);
|
||||
});
|
||||
|
||||
Route::group([
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
use App\Jobs\ScheduledTaskJob;
|
||||
use App\Models\Application;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Project;
|
||||
use App\Models\ScheduledTask;
|
||||
use App\Models\Server;
|
||||
use App\Models\Service;
|
||||
use App\Models\StandaloneDocker;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Queue;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
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]);
|
||||
|
||||
$server = Server::factory()->create(['team_id' => $this->team->id]);
|
||||
$destination = StandaloneDocker::where('server_id', $server->id)->firstOrFail();
|
||||
$environment = Project::factory()->create(['team_id' => $this->team->id])->environments()->first();
|
||||
|
||||
$this->application = Application::factory()->create([
|
||||
'environment_id' => $environment->id,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination->getMorphClass(),
|
||||
]);
|
||||
$this->service = Service::factory()->create([
|
||||
'server_id' => $server->id,
|
||||
'destination_id' => $destination->id,
|
||||
'destination_type' => $destination->getMorphClass(),
|
||||
'environment_id' => $environment->id,
|
||||
]);
|
||||
|
||||
Queue::fake();
|
||||
});
|
||||
|
||||
function scheduledTaskAbilityHeaders(User $user, int $teamId, array $abilities): array
|
||||
{
|
||||
$plainTextToken = Str::random(40);
|
||||
$token = $user->tokens()->create([
|
||||
'name' => 'scheduled-task-ability-test',
|
||||
'token' => hash('sha256', $plainTextToken),
|
||||
'abilities' => $abilities,
|
||||
'team_id' => $teamId,
|
||||
]);
|
||||
|
||||
return ['Authorization' => 'Bearer '.$token->getKey().'|'.$plainTextToken];
|
||||
}
|
||||
|
||||
describe('execute', function () {
|
||||
test('write-only token cannot execute an application or service task', function () {
|
||||
$headers = scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']);
|
||||
$applicationTask = ScheduledTask::factory()->create(['application_id' => $this->application->id, 'team_id' => $this->team->id]);
|
||||
$serviceTask = ScheduledTask::factory()->create(['service_id' => $this->service->id, 'team_id' => $this->team->id]);
|
||||
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$applicationTask->uuid}/execute")
|
||||
->assertForbidden();
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/services/{$this->service->uuid}/scheduled-tasks/{$serviceTask->uuid}/execute")
|
||||
->assertForbidden();
|
||||
|
||||
Queue::assertNotPushed(ScheduledTaskJob::class);
|
||||
});
|
||||
|
||||
test('deploy token can execute an application or service task', function () {
|
||||
$headers = scheduledTaskAbilityHeaders($this->user, $this->team->id, ['deploy']);
|
||||
$applicationTask = ScheduledTask::factory()->create(['application_id' => $this->application->id, 'team_id' => $this->team->id]);
|
||||
$serviceTask = ScheduledTask::factory()->create(['service_id' => $this->service->id, 'team_id' => $this->team->id]);
|
||||
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$applicationTask->uuid}/execute")
|
||||
->assertOk();
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/services/{$this->service->uuid}/scheduled-tasks/{$serviceTask->uuid}/execute")
|
||||
->assertOk();
|
||||
|
||||
Queue::assertPushed(ScheduledTaskJob::class, 2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('create', function () {
|
||||
test('write-only token cannot create an enabled task', function (array $payload) {
|
||||
$headers = scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']);
|
||||
$task = ['name' => 'nightly', 'command' => 'id', 'frequency' => '0 0 1 1 *'] + $payload;
|
||||
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks", $task)
|
||||
->assertForbidden();
|
||||
$this->withHeaders($headers)
|
||||
->postJson("/api/v1/services/{$this->service->uuid}/scheduled-tasks", $task)
|
||||
->assertForbidden();
|
||||
|
||||
expect(ScheduledTask::count())->toBe(0);
|
||||
})->with([
|
||||
'enabled by default' => [[]],
|
||||
'enabled explicitly' => [['enabled' => true]],
|
||||
]);
|
||||
|
||||
test('write-only token can create a disabled task', function () {
|
||||
$this->withHeaders(scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']))
|
||||
->postJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks", [
|
||||
'name' => 'draft',
|
||||
'command' => 'id',
|
||||
'frequency' => '0 0 1 1 *',
|
||||
'enabled' => false,
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('enabled', false);
|
||||
});
|
||||
|
||||
test('write and deploy token can create an enabled task', function () {
|
||||
$this->withHeaders(scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write', 'deploy']))
|
||||
->postJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks", [
|
||||
'name' => 'nightly',
|
||||
'command' => 'id',
|
||||
'frequency' => '0 0 1 1 *',
|
||||
])
|
||||
->assertCreated()
|
||||
->assertJsonPath('enabled', true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('update', function () {
|
||||
test('write-only token cannot change an enabled task', function () {
|
||||
$task = ScheduledTask::factory()->create([
|
||||
'application_id' => $this->application->id,
|
||||
'team_id' => $this->team->id,
|
||||
'command' => 'echo safe',
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
||||
$this->withHeaders(scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']))
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$task->uuid}", ['command' => 'id'])
|
||||
->assertForbidden();
|
||||
|
||||
expect($task->fresh()->command)->toBe('echo safe');
|
||||
});
|
||||
|
||||
test('write-only token cannot enable a disabled task', function () {
|
||||
$task = ScheduledTask::factory()->create([
|
||||
'service_id' => $this->service->id,
|
||||
'team_id' => $this->team->id,
|
||||
'enabled' => false,
|
||||
]);
|
||||
|
||||
$this->withHeaders(scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']))
|
||||
->patchJson("/api/v1/services/{$this->service->uuid}/scheduled-tasks/{$task->uuid}", ['enabled' => true])
|
||||
->assertForbidden();
|
||||
|
||||
expect($task->fresh()->enabled)->toBeFalse();
|
||||
});
|
||||
|
||||
test('write-only token can change or disable a task that stays disabled', function () {
|
||||
$task = ScheduledTask::factory()->create([
|
||||
'application_id' => $this->application->id,
|
||||
'team_id' => $this->team->id,
|
||||
'enabled' => true,
|
||||
]);
|
||||
$headers = scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write']);
|
||||
|
||||
$this->withHeaders($headers)
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$task->uuid}", ['enabled' => false])
|
||||
->assertOk();
|
||||
$this->withHeaders($headers)
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$task->uuid}", ['command' => 'id'])
|
||||
->assertOk();
|
||||
|
||||
expect($task->fresh())->enabled->toBeFalse()->command->toBe('id');
|
||||
});
|
||||
|
||||
test('write and deploy token can change an enabled task', function () {
|
||||
$task = ScheduledTask::factory()->create([
|
||||
'application_id' => $this->application->id,
|
||||
'team_id' => $this->team->id,
|
||||
'enabled' => true,
|
||||
]);
|
||||
|
||||
$this->withHeaders(scheduledTaskAbilityHeaders($this->user, $this->team->id, ['write', 'deploy']))
|
||||
->patchJson("/api/v1/applications/{$this->application->uuid}/scheduled-tasks/{$task->uuid}", ['command' => 'id'])
|
||||
->assertOk();
|
||||
|
||||
expect($task->fresh()->command)->toBe('id');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user