From fa8393184fdce57dd8dfc7de7227f8821c9b3fb7 Mon Sep 17 00:00:00 2001 From: Andras Bacsai <5845193+andrasbacsai@users.noreply.github.com> Date: Wed, 15 Oct 2025 22:07:39 +0200 Subject: [PATCH] refactor: improve validation error handling and coding standards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes: 1. Add explicit try-catch blocks around validateDockerComposeForInjection() in API endpoints to return proper 422 JSON responses with validation errors 2. Rename $service_payload to $servicePayload for PSR-12 compliance (camelCase) API endpoints now properly handle validation failures: - One-click service creation (line 334) - Custom compose service creation (line 480) - Service update endpoint (line 808) All return consistent error format: { "message": "Validation failed.", "errors": { "docker_compose_raw": "Invalid Docker Compose service name: ..." } } Livewire components already have proper exception handling via handleError(). All 60 security tests pass (176 assertions). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Controllers/Api/ServicesController.php | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/Api/ServicesController.php b/app/Http/Controllers/Api/ServicesController.php index 0a571802b..b3565a933 100644 --- a/app/Http/Controllers/Api/ServicesController.php +++ b/app/Http/Controllers/Api/ServicesController.php @@ -331,9 +331,18 @@ public function create_service(Request $request) $dockerComposeRaw = base64_decode($oneClickService); // Validate for command injection BEFORE creating service - validateDockerComposeForInjection($dockerComposeRaw); + try { + validateDockerComposeForInjection($dockerComposeRaw); + } catch (\Exception $e) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => [ + 'docker_compose_raw' => $e->getMessage(), + ], + ], 422); + } - $service_payload = [ + $servicePayload = [ 'name' => "$oneClickServiceName-".str()->random(10), 'docker_compose_raw' => $dockerComposeRaw, 'environment_id' => $environment->id, @@ -343,9 +352,9 @@ public function create_service(Request $request) 'destination_type' => $destination->getMorphClass(), ]; if ($oneClickServiceName === 'cloudflared') { - data_set($service_payload, 'connect_to_docker_network', true); + data_set($servicePayload, 'connect_to_docker_network', true); } - $service = Service::create($service_payload); + $service = Service::create($servicePayload); $service->name = "$oneClickServiceName-".$service->uuid; $service->save(); if ($oneClickDotEnvs?->count() > 0) { @@ -468,7 +477,16 @@ public function create_service(Request $request) $dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); // Validate for command injection BEFORE saving to database - validateDockerComposeForInjection($dockerComposeRaw); + try { + validateDockerComposeForInjection($dockerComposeRaw); + } catch (\Exception $e) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => [ + 'docker_compose_raw' => $e->getMessage(), + ], + ], 422); + } $connectToDockerNetwork = $request->connect_to_docker_network ?? false; $instantDeploy = $request->instant_deploy ?? false; @@ -787,7 +805,16 @@ public function update_by_uuid(Request $request) $dockerComposeRaw = Yaml::dump(Yaml::parse($dockerCompose), 10, 2, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK); // Validate for command injection BEFORE saving to database - validateDockerComposeForInjection($dockerComposeRaw); + try { + validateDockerComposeForInjection($dockerComposeRaw); + } catch (\Exception $e) { + return response()->json([ + 'message' => 'Validation failed.', + 'errors' => [ + 'docker_compose_raw' => $e->getMessage(), + ], + ], 422); + } $service->docker_compose_raw = $dockerComposeRaw; }