fix(validation): add input validation for database public port and proxy timeout (#9272)

This commit is contained in:
Andras Bacsai 2026-03-30 15:10:26 +02:00 committed by GitHub
commit 9a0087ff69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 78 additions and 62 deletions

View file

@ -34,9 +34,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public ?string $customDockerRunOptions = null;
@ -81,7 +81,7 @@ protected function rules(): array
'image' => 'required|string',
'portsMappings' => 'nullable|string',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'customDockerRunOptions' => 'nullable|string',
'dbUrl' => 'nullable|string',
@ -102,6 +102,8 @@ protected function messages(): array
'image.required' => 'The Docker Image field is required.',
'image.string' => 'The Docker Image must be a string.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
]
@ -119,8 +121,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->save();

View file

@ -34,9 +34,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public ?string $customDockerRunOptions = null;
@ -92,7 +92,7 @@ protected function rules(): array
'image' => 'required|string',
'portsMappings' => 'nullable|string',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'customDockerRunOptions' => 'nullable|string',
'dbUrl' => 'nullable|string',
@ -112,6 +112,8 @@ protected function messages(): array
'image.required' => 'The Docker Image field is required.',
'image.string' => 'The Docker Image must be a string.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
]
@ -128,8 +130,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->enable_ssl = $this->enable_ssl;

View file

@ -36,9 +36,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public ?string $customDockerRunOptions = null;
@ -95,7 +95,7 @@ protected function rules(): array
'image' => 'required|string',
'portsMappings' => 'nullable|string',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'customDockerRunOptions' => 'nullable|string',
'dbUrl' => 'nullable|string',
@ -117,6 +117,8 @@ protected function messages(): array
'image.required' => 'The Docker Image field is required.',
'image.string' => 'The Docker Image must be a string.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
]
@ -134,8 +136,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->enable_ssl = $this->enable_ssl;

View file

@ -42,9 +42,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isLogDrainEnabled = false;
@ -80,7 +80,7 @@ protected function rules(): array
'image' => 'required',
'portsMappings' => 'nullable',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isLogDrainEnabled' => 'nullable|boolean',
'customDockerRunOptions' => 'nullable',
@ -100,6 +100,8 @@ protected function messages(): array
'mariadbDatabase.required' => 'The MariaDB Database field is required.',
'image.required' => 'The Docker Image field is required.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
]
@ -159,8 +161,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->enable_ssl = $this->enableSsl;

View file

@ -40,9 +40,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isLogDrainEnabled = false;
@ -79,7 +79,7 @@ protected function rules(): array
'image' => 'required',
'portsMappings' => 'nullable',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isLogDrainEnabled' => 'nullable|boolean',
'customDockerRunOptions' => 'nullable',
@ -99,6 +99,8 @@ protected function messages(): array
'mongoInitdbDatabase.required' => 'The MongoDB Database field is required.',
'image.required' => 'The Docker Image field is required.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
'sslMode.in' => 'The SSL Mode must be one of: allow, prefer, require, verify-full.',
@ -158,8 +160,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->enable_ssl = $this->enableSsl;

View file

@ -42,9 +42,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isLogDrainEnabled = false;
@ -82,7 +82,7 @@ protected function rules(): array
'image' => 'required',
'portsMappings' => 'nullable',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isLogDrainEnabled' => 'nullable|boolean',
'customDockerRunOptions' => 'nullable',
@ -103,6 +103,8 @@ protected function messages(): array
'mysqlDatabase.required' => 'The MySQL Database field is required.',
'image.required' => 'The Docker Image field is required.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
'sslMode.in' => 'The SSL Mode must be one of: PREFERRED, REQUIRED, VERIFY_CA, VERIFY_IDENTITY.',
@ -164,8 +166,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->enable_ssl = $this->enableSsl;

View file

@ -46,9 +46,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isLogDrainEnabled = false;
@ -94,7 +94,7 @@ protected function rules(): array
'image' => 'required',
'portsMappings' => 'nullable',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isLogDrainEnabled' => 'nullable|boolean',
'customDockerRunOptions' => 'nullable',
@ -114,6 +114,8 @@ protected function messages(): array
'postgresDb.required' => 'The Postgres Database field is required.',
'image.required' => 'The Docker Image field is required.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
'sslMode.in' => 'The SSL Mode must be one of: allow, prefer, require, verify-ca, verify-full.',
@ -179,8 +181,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->enable_ssl = $this->enableSsl;

View file

@ -34,9 +34,9 @@ class General extends Component
public ?bool $isPublic = null;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isLogDrainEnabled = false;
@ -75,7 +75,7 @@ protected function rules(): array
'image' => 'required',
'portsMappings' => 'nullable',
'isPublic' => 'nullable|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isLogDrainEnabled' => 'nullable|boolean',
'customDockerRunOptions' => 'nullable',
@ -93,6 +93,8 @@ protected function messages(): array
'name.required' => 'The Name field is required.',
'image.required' => 'The Docker Image field is required.',
'publicPort.integer' => 'The Public Port must be an integer.',
'publicPort.min' => 'The Public Port must be at least 1.',
'publicPort.max' => 'The Public Port must not exceed 65535.',
'publicPortTimeout.integer' => 'The Public Port Timeout must be an integer.',
'publicPortTimeout.min' => 'The Public Port Timeout must be at least 1.',
'redisUsername.required' => 'The Redis Username field is required.',
@ -148,8 +150,8 @@ public function syncData(bool $toModel = false)
$this->database->image = $this->image;
$this->database->ports_mappings = $this->portsMappings;
$this->database->is_public = $this->isPublic;
$this->database->public_port = $this->publicPort;
$this->database->public_port_timeout = $this->publicPortTimeout;
$this->database->public_port = $this->publicPort ?: null;
$this->database->public_port_timeout = $this->publicPortTimeout ?: null;
$this->database->is_log_drain_enabled = $this->isLogDrainEnabled;
$this->database->custom_docker_run_options = $this->customDockerRunOptions;
$this->database->enable_ssl = $this->enableSsl;

View file

@ -51,9 +51,9 @@ class Index extends Component
public bool $excludeFromStatus = false;
public ?int $publicPort = null;
public mixed $publicPort = null;
public ?int $publicPortTimeout = 3600;
public mixed $publicPortTimeout = 3600;
public bool $isPublic = false;
@ -91,7 +91,7 @@ class Index extends Component
'description' => 'nullable',
'image' => 'required',
'excludeFromStatus' => 'required|boolean',
'publicPort' => 'nullable|integer',
'publicPort' => 'nullable|integer|min:1|max:65535',
'publicPortTimeout' => 'nullable|integer|min:1',
'isPublic' => 'required|boolean',
'isLogDrainEnabled' => 'required|boolean',
@ -160,8 +160,8 @@ private function syncDatabaseData(bool $toModel = false): void
$this->serviceDatabase->description = $this->description;
$this->serviceDatabase->image = $this->image;
$this->serviceDatabase->exclude_from_status = $this->excludeFromStatus;
$this->serviceDatabase->public_port = $this->publicPort;
$this->serviceDatabase->public_port_timeout = $this->publicPortTimeout;
$this->serviceDatabase->public_port = $this->publicPort ?: null;
$this->serviceDatabase->public_port_timeout = $this->publicPortTimeout ?: null;
$this->serviceDatabase->is_public = $this->isPublic;
$this->serviceDatabase->is_log_drain_enabled = $this->isLogDrainEnabled;
} else {

View file

@ -76,9 +76,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available" canGate="update"
:canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
</form>

View file

@ -113,9 +113,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available" canGate="update"
:canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
</form>

View file

@ -113,9 +113,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available" canGate="update"
:canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}" id="publicPort" label="Public Port"
canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
<x-forms.textarea

View file

@ -137,9 +137,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available"
canGate="update" :canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}"
id="publicPort" label="Public Port" canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
<x-forms.textarea label="Custom MariaDB Configuration" rows="10" id="mariadbConf"

View file

@ -151,9 +151,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available"
canGate="update" :canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}"
id="publicPort" label="Public Port" canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
<x-forms.textarea label="Custom MongoDB Configuration" rows="10" id="mongoConf"

View file

@ -153,9 +153,9 @@
</div>
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available" canGate="update" :canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}"
id="publicPort" label="Public Port" canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
<x-forms.textarea label="Custom Mysql Configuration" rows="10" id="mysqlConf" canGate="update" :canResource="$database" />

View file

@ -163,9 +163,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available"
canGate="update" :canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}" id="publicPort"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}" id="publicPort"
label="Public Port" canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>

View file

@ -132,9 +132,9 @@
<x-forms.checkbox instantSave id="isPublic" label="Make it publicly available"
canGate="update" :canResource="$database" />
</div>
<x-forms.input placeholder="5432" disabled="{{ $isPublic }}"
<x-forms.input type="number" placeholder="5432" disabled="{{ $isPublic }}"
id="publicPort" label="Public Port" canGate="update" :canResource="$database" />
<x-forms.input placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
<x-forms.input type="number" placeholder="3600" disabled="{{ $isPublic }}" id="publicPortTimeout"
label="Proxy Timeout (seconds)" helper="Timeout for the public TCP proxy connection in seconds. Default: 3600 (1 hour)." canGate="update" :canResource="$database" />
</div>
<x-forms.textarea placeholder="# maxmemory 256mb

View file

@ -233,7 +233,7 @@ class="w-auto dark:bg-coolgray-200 dark:hover:bg-coolgray-300">
<x-forms.checkbox canGate="update" :canResource="$serviceDatabase" instantSave id="isPublic"
label="Make it publicly available" />
</div>
<x-forms.input canGate="update" :canResource="$serviceDatabase" placeholder="5432"
<x-forms.input type="number" canGate="update" :canResource="$serviceDatabase" placeholder="5432"
disabled="{{ $serviceDatabase->is_public }}" id="publicPort" label="Public Port" />
@if ($db_url_public)
<x-forms.input label="Database IP:PORT (public)"