fix(api): accept connect_to_docker_network when creating services

Closes #12014
This commit is contained in:
Andras Bacsai
2026-10-15 22:52:05 +02:00
parent b74906d15b
commit f9df974069
4 changed files with 91 additions and 2 deletions
@@ -308,6 +308,7 @@ class ServicesController extends Controller
'destination_uuid' => ['type' => 'string', 'description' => 'Destination UUID. Required if server has multiple destinations.'],
'instant_deploy' => ['type' => 'boolean', 'default' => false, 'description' => 'Start the service immediately after creation.'],
'docker_compose_raw' => ['type' => 'string', 'description' => 'The base64 encoded Docker Compose content.'],
'connect_to_docker_network' => ['type' => 'boolean', 'default' => false, 'description' => 'Connect the service to the predefined docker network.'],
'urls' => [
'type' => 'array',
'description' => 'Array of URLs to be applied to containers of a service.',
@@ -388,7 +389,7 @@ class ServicesController extends Controller
)]
public function create_service(Request $request)
{
$allowedFields = ['type', 'name', 'description', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'docker_compose_raw', 'urls', 'force_domain_override', 'is_container_label_escape_enabled', 'tags'];
$allowedFields = ['type', 'name', 'description', 'project_uuid', 'environment_name', 'environment_uuid', 'server_uuid', 'destination_uuid', 'instant_deploy', 'docker_compose_raw', 'connect_to_docker_network', 'urls', 'force_domain_override', 'is_container_label_escape_enabled', 'tags'];
$teamId = getTeamIdFromToken();
if (is_null($teamId)) {
@@ -416,6 +417,7 @@ class ServicesController extends Controller
'name' => 'string|max:255',
'description' => 'string|nullable',
'instant_deploy' => 'boolean',
'connect_to_docker_network' => 'boolean',
'urls' => 'array|nullable',
'urls.*' => 'array:name,url',
'urls.*.name' => 'string|required',
@@ -544,7 +546,7 @@ class ServicesController extends Controller
'destination_id' => $destination->id,
'destination_type' => $destination->getMorphClass(),
];
if (in_array($oneClickServiceName, NEEDS_TO_CONNECT_TO_PREDEFINED_NETWORK)) {
if (in_array($oneClickServiceName, NEEDS_TO_CONNECT_TO_PREDEFINED_NETWORK) || $request->boolean('connect_to_docker_network')) {
data_set($servicePayload, 'connect_to_docker_network', true);
}
$service = new Service($servicePayload);
+5
View File
@@ -19239,6 +19239,11 @@
"type": "string",
"description": "The base64 encoded Docker Compose content."
},
"connect_to_docker_network": {
"type": "boolean",
"default": false,
"description": "Connect the service to the predefined docker network."
},
"urls": {
"type": "array",
"description": "Array of URLs to be applied to containers of a service.",
+4
View File
@@ -12154,6 +12154,10 @@ paths:
docker_compose_raw:
type: string
description: 'The base64 encoded Docker Compose content.'
connect_to_docker_network:
type: boolean
default: false
description: 'Connect the service to the predefined docker network.'
urls:
type: array
description: 'Array of URLs to be applied to containers of a service.'
@@ -0,0 +1,78 @@
<?php
use App\Models\InstanceSettings;
use App\Models\Project;
use App\Models\Server;
use App\Models\Service;
use App\Models\Team;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Queue;
use Illuminate\Testing\TestResponse;
uses(RefreshDatabase::class);
beforeEach(function () {
InstanceSettings::unguarded(fn () => InstanceSettings::create(['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]);
$this->bearerToken = $this->user->createToken('test-token', ['*'])->plainTextToken;
$this->server = Server::factory()->create(['team_id' => $this->team->id]);
$this->project = Project::factory()->create(['team_id' => $this->team->id]);
$this->environment = $this->project->environments()->first();
});
function createServiceWithDockerNetworkFlag(mixed $connectToDockerNetwork, string $bearerToken, array $payload): TestResponse
{
return test()->withHeaders(['Authorization' => 'Bearer '.$bearerToken])
->postJson('/api/v1/services', [
...$payload,
'connect_to_docker_network' => $connectToDockerNetwork,
]);
}
describe('POST /api/v1/services connect_to_docker_network', function () {
test('saves the flag for a docker_compose_raw service', function () {
$response = createServiceWithDockerNetworkFlag(true, $this->bearerToken, [
'project_uuid' => $this->project->uuid,
'environment_uuid' => $this->environment->uuid,
'server_uuid' => $this->server->uuid,
'docker_compose_raw' => base64_encode("services:\n app:\n image: nginx:alpine\n"),
]);
$response->assertCreated();
expect(Service::whereUuid($response->json('uuid'))->firstOrFail()->connect_to_docker_network)->toBeTruthy();
});
test('saves the flag for a one-click service', function () {
Queue::fake();
$response = createServiceWithDockerNetworkFlag(true, $this->bearerToken, [
'type' => 'cyberchef',
'project_uuid' => $this->project->uuid,
'environment_uuid' => $this->environment->uuid,
'server_uuid' => $this->server->uuid,
]);
$response->assertCreated();
expect(Service::whereUuid($response->json('uuid'))->firstOrFail()->connect_to_docker_network)->toBeTruthy();
});
test('rejects a non-boolean value', function () {
$response = createServiceWithDockerNetworkFlag('not-a-boolean', $this->bearerToken, [
'project_uuid' => $this->project->uuid,
'environment_uuid' => $this->environment->uuid,
'server_uuid' => $this->server->uuid,
'docker_compose_raw' => base64_encode("services:\n app:\n image: nginx:alpine\n"),
]);
$response->assertUnprocessable()->assertJsonValidationErrors(['connect_to_docker_network']);
expect($response->json('errors.connect_to_docker_network'))->not->toContain('This field is not allowed.');
});
});