feat(scheduled-tasks): add an option to run a task without a shell

Containers without sh (distroless or scratch images) could not run
scheduled tasks, because Coolify always ran the command with sh -c.
Turn off "Run in a shell" to split the command into arguments and run
it directly. The option is also in the API, the MCP tools, and the
server transfer.

Closes #8244

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andras Bacsai
2026-11-03 22:19:37 +01:00
co-authored by Claude Opus 5.5
parent e0b94662e9
commit 31c3fcf50d
20 changed files with 301 additions and 10 deletions
@@ -149,6 +149,25 @@ test('a scheduled task in a service quotes the container name', function (bool $
expect($task->executions()->sole()->status)->toBe('success');
})->with(['root' => [false, ''], 'non-root' => [true, 'sudo ']]);
test('a scheduled task without a shell runs the command arguments directly', function (bool $nonRoot, string $sudo) {
if ($nonRoot) {
quotingUseNonRootUser();
}
$task = ScheduledTask::factory()->create([
'team_id' => $this->team->id,
'service_id' => $this->service->id,
'container' => QUOTING_HOSTILE_NAME,
'command' => '/surreal export --conn "http://localhost:8000" $HOME;id',
'use_shell' => false,
]);
(new ScheduledTaskJob($task))->handle();
quotingAssertCommandRan("{$sudo}docker exec {$this->containerName} '/surreal' 'export' '--conn' 'http://localhost:8000' '\$HOME;id' 2>&1 |");
quotingAssertNoUnquotedName();
expect($task->executions()->sole()->status)->toBe('success');
})->with(['root' => [false, ''], 'non-root' => [true, 'sudo ']]);
/**
* `docker ps` returns one container for the application.
*/