refactor(settings): harden dev_helper_version validation and escape build args (#9670)
This commit is contained in:
commit
fe8b3412d3
2 changed files with 102 additions and 2 deletions
|
|
@ -35,7 +35,7 @@ class Index extends Component
|
|||
#[Validate('required|string|timezone')]
|
||||
public string $instance_timezone;
|
||||
|
||||
#[Validate('nullable|string|max:50')]
|
||||
#[Validate(['nullable', 'string', 'max:128', 'regex:/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/'])]
|
||||
public ?string $dev_helper_version = null;
|
||||
|
||||
public array $domainConflicts = [];
|
||||
|
|
@ -49,6 +49,7 @@ class Index extends Component
|
|||
protected array $messages = [
|
||||
'fqdn.url' => 'Invalid instance URL.',
|
||||
'fqdn.max' => 'URL must not exceed 255 characters.',
|
||||
'dev_helper_version.regex' => 'Dev helper version must match Docker tag format (alphanumeric, _, ., -; first char cannot be . or -).',
|
||||
];
|
||||
|
||||
public function render()
|
||||
|
|
@ -184,6 +185,8 @@ public function buildHelperImage()
|
|||
return;
|
||||
}
|
||||
|
||||
$this->validateOnly('dev_helper_version');
|
||||
|
||||
$version = $this->dev_helper_version ?: config('constants.coolify.helper_version');
|
||||
if (empty($version)) {
|
||||
$this->dispatch('error', 'Please specify a version to build.');
|
||||
|
|
@ -191,7 +194,14 @@ public function buildHelperImage()
|
|||
return;
|
||||
}
|
||||
|
||||
$buildCommand = "docker build -t ghcr.io/coollabsio/coolify-helper:{$version} -f docker/coolify-helper/Dockerfile .";
|
||||
if (! preg_match('/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/', (string) $version)) {
|
||||
$this->dispatch('error', 'Invalid helper version format.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$imageRef = escapeshellarg("ghcr.io/coollabsio/coolify-helper:{$version}");
|
||||
$buildCommand = "docker build -t {$imageRef} -f docker/coolify-helper/Dockerfile .";
|
||||
|
||||
$activity = remote_process(
|
||||
command: [$buildCommand],
|
||||
|
|
|
|||
90
tests/Feature/DevHelperVersionValidationTest.php
Normal file
90
tests/Feature/DevHelperVersionValidationTest.php
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
use App\Livewire\Settings\Index;
|
||||
use App\Models\InstanceSettings;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Once;
|
||||
use Livewire\Livewire;
|
||||
|
||||
uses(RefreshDatabase::class);
|
||||
|
||||
beforeEach(function () {
|
||||
Model::unguarded(function () {
|
||||
$this->rootTeam = Team::find(0) ?? Team::create(['id' => 0, 'name' => 'Root Team', 'personal_team' => false]);
|
||||
if (! Server::find(0)) {
|
||||
Server::factory()->create(['id' => 0, 'team_id' => $this->rootTeam->id]);
|
||||
}
|
||||
if (! InstanceSettings::find(0)) {
|
||||
InstanceSettings::create(['id' => 0]);
|
||||
}
|
||||
});
|
||||
Once::flush();
|
||||
|
||||
$this->user = User::factory()->create();
|
||||
$this->rootTeam->members()->attach($this->user->id, ['role' => 'admin']);
|
||||
|
||||
$this->actingAs($this->user);
|
||||
session(['currentTeam' => ['id' => $this->rootTeam->id]]);
|
||||
});
|
||||
|
||||
test('dev_helper_version rejects values outside Docker tag grammar on save', function () {
|
||||
$invalid = [
|
||||
'latest with spaces',
|
||||
'a$b',
|
||||
'a`b',
|
||||
'a|b',
|
||||
'a;b',
|
||||
'a&b',
|
||||
'a>b',
|
||||
'a<b',
|
||||
"a\nb",
|
||||
'.bad',
|
||||
'-rm',
|
||||
];
|
||||
|
||||
foreach ($invalid as $payload) {
|
||||
Livewire::test(Index::class)
|
||||
->set('dev_helper_version', $payload)
|
||||
->call('instantSave')
|
||||
->assertHasErrors(['dev_helper_version']);
|
||||
}
|
||||
|
||||
expect(InstanceSettings::find(0)->dev_helper_version)->toBeNull();
|
||||
});
|
||||
|
||||
test('dev_helper_version accepts valid docker tag formats', function () {
|
||||
$valid = ['1.0.12', 'latest', 'dev', 'dev-branch_2', 'v1.2.3-rc1', '1_0_0'];
|
||||
|
||||
foreach ($valid as $tag) {
|
||||
Livewire::test(Index::class)
|
||||
->set('dev_helper_version', $tag)
|
||||
->call('instantSave')
|
||||
->assertHasNoErrors(['dev_helper_version']);
|
||||
|
||||
expect(InstanceSettings::find(0)->fresh()->dev_helper_version)->toBe($tag);
|
||||
}
|
||||
});
|
||||
|
||||
test('buildHelperImage refuses when non-dev environment', function () {
|
||||
config(['app.env' => 'production']);
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->set('dev_helper_version', 'latest')
|
||||
->call('buildHelperImage')
|
||||
->assertDispatched('error');
|
||||
});
|
||||
|
||||
test('buildHelperImage refuses previously stored invalid version', function () {
|
||||
config(['app.env' => 'local']);
|
||||
|
||||
$settings = InstanceSettings::find(0);
|
||||
$settings->forceFill(['dev_helper_version' => 'bad value'])->saveQuietly();
|
||||
|
||||
Livewire::test(Index::class)
|
||||
->call('buildHelperImage')
|
||||
->assertDispatched('error');
|
||||
});
|
||||
Loading…
Reference in a new issue