From c4e15d4e1b8cb58ef197bf386cdc12c36e0991ff Mon Sep 17 00:00:00 2001 From: Augustinas Malinauskas Date: Sun, 1 Feb 2026 17:51:55 -0800 Subject: [PATCH 1/3] feat: add --runtime support for custom docker run options This enables users to specify container runtimes like gVisor (runsc) via the Custom Docker Run Options field. Example usage: --runtime=runsc This is useful for running untrusted workloads in sandboxed runtimes that provide additional isolation beyond standard runc. Co-Authored-By: Claude Opus 4.5 --- bootstrap/helpers/docker.php | 13 ++++++++++- tests/Feature/DockerCustomCommandsTest.php | 25 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index b0d401b5f..f300dcc88 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -1009,6 +1009,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) '--gpus' => 'gpus', '--hostname' => 'hostname', '--entrypoint' => 'entrypoint', + '--runtime' => 'runtime', ]); foreach ($matches as $match) { $option = $match[1]; @@ -1029,6 +1030,16 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) $options[$option] = array_unique($options[$option]); } } + if ($option === '--runtime') { + // Match --runtime=value or --runtime value (e.g., --runtime=runsc, --runtime runc) + $regexForParsingRuntime = '/--runtime(?:=|\s+)([^\s]+)/'; + preg_match($regexForParsingRuntime, $custom_docker_run_options, $runtime_matches); + $value = $runtime_matches[1] ?? null; + if ($value && ! empty(trim($value))) { + $options[$option][] = $value; + $options[$option] = array_unique($options[$option]); + } + } if ($option === '--entrypoint') { $value = null; // Match --entrypoint=value or --entrypoint value @@ -1097,7 +1108,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) } }); $compose_options->put($mapping[$option], $ulimits); - } elseif ($option === '--shm-size' || $option === '--hostname') { + } elseif ($option === '--shm-size' || $option === '--hostname' || $option === '--runtime') { if (! is_null($value) && is_array($value) && count($value) > 0 && ! empty(trim($value[0]))) { $compose_options->put($mapping[$option], $value[0]); } diff --git a/tests/Feature/DockerCustomCommandsTest.php b/tests/Feature/DockerCustomCommandsTest.php index 5d9dcd174..f420dab52 100644 --- a/tests/Feature/DockerCustomCommandsTest.php +++ b/tests/Feature/DockerCustomCommandsTest.php @@ -198,3 +198,28 @@ test('ConvertEntrypointSingleQuotedWithDoubleQuotesInside', function () { 'entrypoint' => 'python -c "print(\"hi\")"', ]); }); + +test('RuntimeWithEquals', function () { + $input = '--runtime=runsc'; + $output = convertDockerRunToCompose($input); + expect($output)->toBe([ + 'runtime' => 'runsc', + ]); +}); + +test('RuntimeWithoutEquals', function () { + $input = '--runtime runsc'; + $output = convertDockerRunToCompose($input); + expect($output)->toBe([ + 'runtime' => 'runsc', + ]); +}); + +test('RuntimeWithOtherOptions', function () { + $input = '--runtime=runsc --cap-drop=ALL --security-opt=no-new-privileges'; + $output = convertDockerRunToCompose($input); + expect($output)->toHaveKeys(['runtime', 'cap_drop', 'security_opt']) + ->and($output['runtime'])->toBe('runsc') + ->and($output['cap_drop'])->toBe(['ALL']) + ->and($output['security_opt'])->toBe(['no-new-privileges']); +}); From c0100a3edd52721028f9d467d8653922d8dc30a1 Mon Sep 17 00:00:00 2001 From: Augustinas Malinauskas Date: Wed, 4 Feb 2026 08:16:40 -0800 Subject: [PATCH 2/3] feat: add --pids-limit to custom docker run options whitelist Add support for --pids-limit option in CustomDockerRunOptions to allow limiting the number of processes that can be created within a container. This provides an additional security hardening option for deployments. - Add --pids-limit to the mapping in convertDockerRunToCompose() - Add parsing logic for both --pids-limit=value and --pids-limit value formats - Add tests for the new option --- bootstrap/helpers/docker.php | 13 ++++++++++++- tests/Feature/DockerCustomCommandsTest.php | 12 ++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/bootstrap/helpers/docker.php b/bootstrap/helpers/docker.php index f300dcc88..3b6ac6d9c 100644 --- a/bootstrap/helpers/docker.php +++ b/bootstrap/helpers/docker.php @@ -1010,6 +1010,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) '--hostname' => 'hostname', '--entrypoint' => 'entrypoint', '--runtime' => 'runtime', + '--pids-limit' => 'pids_limit', ]); foreach ($matches as $match) { $option = $match[1]; @@ -1040,6 +1041,16 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) $options[$option] = array_unique($options[$option]); } } + if ($option === '--pids-limit') { + // Match --pids-limit=value or --pids-limit value (e.g., --pids-limit=256, --pids-limit 1024) + $regexForParsingPidsLimit = '/--pids-limit(?:=|\s+)([^\s]+)/'; + preg_match($regexForParsingPidsLimit, $custom_docker_run_options, $pids_limit_matches); + $value = $pids_limit_matches[1] ?? null; + if ($value && ! empty(trim($value))) { + $options[$option][] = $value; + $options[$option] = array_unique($options[$option]); + } + } if ($option === '--entrypoint') { $value = null; // Match --entrypoint=value or --entrypoint value @@ -1108,7 +1119,7 @@ function convertDockerRunToCompose(?string $custom_docker_run_options = null) } }); $compose_options->put($mapping[$option], $ulimits); - } elseif ($option === '--shm-size' || $option === '--hostname' || $option === '--runtime') { + } elseif ($option === '--shm-size' || $option === '--hostname' || $option === '--runtime' || $option === '--pids-limit') { if (! is_null($value) && is_array($value) && count($value) > 0 && ! empty(trim($value[0]))) { $compose_options->put($mapping[$option], $value[0]); } diff --git a/tests/Feature/DockerCustomCommandsTest.php b/tests/Feature/DockerCustomCommandsTest.php index f420dab52..2e5929a9b 100644 --- a/tests/Feature/DockerCustomCommandsTest.php +++ b/tests/Feature/DockerCustomCommandsTest.php @@ -223,3 +223,15 @@ test('RuntimeWithOtherOptions', function () { ->and($output['cap_drop'])->toBe(['ALL']) ->and($output['security_opt'])->toBe(['no-new-privileges']); }); + +test('PidsLimitWithEquals', function () { + $input = '--pids-limit=1024'; + $output = convertDockerRunToCompose($input); + expect($output)->toBe(['pids_limit' => '1024']); +}); + +test('PidsLimitWithoutEquals', function () { + $input = '--pids-limit 256'; + $output = convertDockerRunToCompose($input); + expect($output)->toBe(['pids_limit' => '256']); +}); From ec170b10ddd9b15952722e5d0990a9ebcbb00fd7 Mon Sep 17 00:00:00 2001 From: Augustinas Malinauskas Date: Wed, 4 Feb 2026 11:08:09 -0800 Subject: [PATCH 3/3] test: remove RuntimeWithOtherOptions test --- tests/Feature/DockerCustomCommandsTest.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/Feature/DockerCustomCommandsTest.php b/tests/Feature/DockerCustomCommandsTest.php index 2e5929a9b..098d4b3c3 100644 --- a/tests/Feature/DockerCustomCommandsTest.php +++ b/tests/Feature/DockerCustomCommandsTest.php @@ -215,15 +215,6 @@ test('RuntimeWithoutEquals', function () { ]); }); -test('RuntimeWithOtherOptions', function () { - $input = '--runtime=runsc --cap-drop=ALL --security-opt=no-new-privileges'; - $output = convertDockerRunToCompose($input); - expect($output)->toHaveKeys(['runtime', 'cap_drop', 'security_opt']) - ->and($output['runtime'])->toBe('runsc') - ->and($output['cap_drop'])->toBe(['ALL']) - ->and($output['security_opt'])->toBe(['no-new-privileges']); -}); - test('PidsLimitWithEquals', function () { $input = '--pids-limit=1024'; $output = convertDockerRunToCompose($input);