feat(dev): add coold VM dev workflow

Add scripts and Lima config for managing local coold endpoint VMs,
mint Flux dev host JWTs, expose coold host details on the V5 home
page, and document the local development workflow.
This commit is contained in:
Andras Bacsai committed 2026-06-16 11:39:36 +02:00
1 parent ed89d83d68
commit 1b1b0726a2
15 files changed
+1661 -5

No files matched your search

@@ -0,0 +1,31 @@
<?php
it('does not include coold dev tooling defaults in the development env example', function (string $variable) {
$developmentExample = file_get_contents(base_path('.env.development.example'));
expect($developmentExample)->not->toContain($variable.'=');
})->with([
'coold package version default' => 'COOLIFY_COOLD_VERSION',
'flux package version default' => 'COOLIFY_FLUX_VERSION',
'corrosion package version default' => 'COOLIFY_CORROSION_VERSION',
'coold VM count default' => 'COOLIFY_COOLD_VM_COUNT',
'coold VM flux URL default' => 'COOLIFY_COOLD_VM_FLUX_URL',
'coold VM WireGuard IP 1 default' => 'COOLIFY_COOLD_VM_WG_IP_1',
'coold VM WireGuard IP 2 default' => 'COOLIFY_COOLD_VM_WG_IP_2',
'coold VM WireGuard port 1 default' => 'COOLIFY_COOLD_VM_WG_PORT_1',
'coold VM WireGuard port 2 default' => 'COOLIFY_COOLD_VM_WG_PORT_2',
'coold VM builder capacity default' => 'COOLIFY_COOLD_VM_BUILDER_CAPACITY',
'coold VM enabled default' => 'COOLIFY_COOLD_VM_ENABLED',
'coold VM stop on down default' => 'COOLIFY_COOLD_VM_STOP_ON_DOWN',
'dev follow logs default' => 'COOLIFY_DEV_FOLLOW_LOGS',
]);
it('defaults coold dev VM settings in Laravel config', function () {
expect(config('coold.dev_host_count'))->toBe(2)
->and(config('coold.dev_host_id'))->toBe('coolify-coold-dev')
->and(config('coold.dev_host_id_2'))->toBe('coolify-coold-dev-2')
->and(config('coold.dev_wireguard_ip_1'))->toBe('100.64.0.10')
->and(config('coold.dev_wireguard_ip_2'))->toBe('100.64.0.11')
->and(config('coold.dev_builder_capacity'))->toBe(2)
->and(config('coold.dev_builder_enabled'))->toBeTrue();
});
+65
View File
@@ -0,0 +1,65 @@
<?php
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Config;
it('mints a host jwt signed by the configured flux private key', function () {
[$privateKeyPath, $publicKeyPath] = createFluxJwtKeypair();
Config::set('flux.jwt_private_key_path', $privateKeyPath);
$exitCode = Artisan::call('flux:dev', [
'host_id' => 'coold-dev',
'--caps' => 'coold,builder',
'--ttl' => '600',
]);
expect($exitCode)->toBe(0);
$token = trim(Artisan::output());
$claims = JWT::decode($token, new Key(file_get_contents($publicKeyPath), 'ES256'));
expect($claims->sub)->toBe('coold-dev')
->and($claims->aud)->toBe('coold')
->and($claims->caps)->toBe(['coold', 'builder'])
->and($claims->exp)->toBeGreaterThan(time());
});
it('writes the host jwt to an output path with owner-only permissions', function () {
[$privateKeyPath] = createFluxJwtKeypair();
$outputPath = storage_path('framework/testing/host-jwt');
Config::set('flux.jwt_private_key_path', $privateKeyPath);
$exitCode = Artisan::call('flux:dev', [
'host_id' => 'coold-dev',
'--output' => $outputPath,
]);
expect($exitCode)->toBe(0);
expect($outputPath)->toBeFile()
->and(substr(sprintf('%o', fileperms($outputPath)), -4))->toBe('0600');
});
/**
* @return array{0: string, 1: string}
*/
function createFluxJwtKeypair(): array
{
$directory = storage_path('framework/testing/flux-keys-'.bin2hex(random_bytes(4)));
mkdir($directory, 0777, true);
$privateKeyPath = $directory.'/jwt.priv';
$publicKeyPath = $directory.'/jwt.pub';
exec('openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out '.escapeshellarg($privateKeyPath), $output, $exitCode);
expect($exitCode)->toBe(0);
exec('openssl pkey -in '.escapeshellarg($privateKeyPath).' -pubout -out '.escapeshellarg($publicKeyPath), $output, $exitCode);
expect($exitCode)->toBe(0);
return [$privateKeyPath, $publicKeyPath];
}
+6
View File
@@ -105,6 +105,12 @@ it('serves the v5 inertia shell', function () {
->assertSee('v5-ready', false)
->assertSee('Running')
->assertSee('Flux is running.')
->assertSee('coolify-coold-dev')
->assertSee('coolify-coold-dev-2')
->assertSee('100.64.0.10')
->assertSee('100.64.0.11')
->assertSee('builder')
->assertSee('builderCapacity')
->assertSee('V5 Shared Team')
->assertSee('Shared team details')
->assertSee('owner')