Fix api-v2 CORS at the edge without changing rollout flows (#330)
Add API-only Traefik CORS middleware labels while preserving configured origins and the existing rollout/load-balancer behavior.
This commit is contained in:
@@ -5,6 +5,7 @@ app_require('classes/coolify_manager.php');
|
||||
|
||||
use classes\coolify_api_client;
|
||||
use classes\coolify_manager;
|
||||
use classes\cors_policy;
|
||||
|
||||
class CoolifyManagerHetznerTargetSetFake
|
||||
{
|
||||
@@ -418,9 +419,10 @@ it('adds explicit Coolify application route labels for gateway API domains', fun
|
||||
$payload = $payloadMethod->invoke(null, 'https://api-v2.truckwash.io', 'api-app-uuid', 8080, base64_encode(implode("\n", [
|
||||
'custom.keep=true',
|
||||
'traefik.http.routers.https-0-api-app-uuid.entryPoints=old',
|
||||
'traefik.http.routers.https-0-api-app-uuid.middlewares=legacy',
|
||||
'traefik.http.routers.https-0-api-app-uuid.tls.certresolver=dns-cloudflare',
|
||||
'traefik.http.services.https-0-api-app-uuid.loadbalancer.server.port=9090',
|
||||
])));
|
||||
])), 'api', 'https://partner.example.test/app');
|
||||
$labels = explode("\n", base64_decode($payload['custom_labels'], true));
|
||||
|
||||
expect($payload['domains'])->toBe('https://api-v2.truckwash.io:8080')
|
||||
@@ -429,6 +431,12 @@ it('adds explicit Coolify application route labels for gateway API domains', fun
|
||||
->and($labels)->toContain('custom.keep=true')
|
||||
->and($labels)->toContain('traefik.http.routers.https-0-api-app-uuid.rule=Host(`api-v2.truckwash.io`) && PathPrefix(`/`)')
|
||||
->and($labels)->toContain('traefik.http.routers.https-0-api-app-uuid.entryPoints=https')
|
||||
->and($labels)->toContain('traefik.http.routers.https-0-api-app-uuid.middlewares=https-0-api-app-uuid-cors,gzip')
|
||||
->and($labels)->toContain('traefik.http.middlewares.https-0-api-app-uuid-cors.headers.accesscontrolallowcredentials=true')
|
||||
->and($labels)->toContain(
|
||||
'traefik.http.middlewares.https-0-api-app-uuid-cors.headers.accesscontrolalloworiginlist='
|
||||
. implode(',', cors_policy::allowedOrigins('https://partner.example.test/app'))
|
||||
)
|
||||
->and($labels)->toContain('traefik.http.routers.https-0-api-app-uuid.tls.certresolver=letsencrypt')
|
||||
->and($labels)->toContain('traefik.http.routers.https-0-api-app-uuid.tls.domains[0].main=api-v2.truckwash.io')
|
||||
->and($labels)->toContain('traefik.http.services.https-0-api-app-uuid.loadbalancer.server.port=8080');
|
||||
@@ -449,21 +457,49 @@ it('adds explicit Coolify application route labels for gateway API domains', fun
|
||||
'app' => 'frontend',
|
||||
]))->toBe('https://api-v2.truckwash.io/internal/frontend');
|
||||
|
||||
$pathPayload = $payloadMethod->invoke(null, 'https://api-v2.truckwash.io/internal/api', 'api-app-uuid', 8080, '');
|
||||
$pathPayload = $payloadMethod->invoke(null, 'https://api-v2.truckwash.io/internal/api', 'api-app-uuid', 8080, '', 'api', '*');
|
||||
$pathLabels = explode("\n", base64_decode($pathPayload['custom_labels'], true));
|
||||
|
||||
expect($pathPayload['domains'])->toBe('https://api-v2.truckwash.io:8080/internal/api')
|
||||
->and($pathLabels)->toContain('traefik.http.routers.https-0-api-app-uuid.rule=Host(`api-v2.truckwash.io`) && PathPrefix(`/internal/api`)')
|
||||
->and($pathLabels)->toContain('traefik.http.middlewares.https-0-api-app-uuid-stripprefix.stripprefix.prefixes=/internal/api')
|
||||
->and($pathLabels)->toContain('traefik.http.routers.https-0-api-app-uuid.middlewares=https-0-api-app-uuid-stripprefix,gzip');
|
||||
->and($pathLabels)->toContain('traefik.http.middlewares.https-0-api-app-uuid-cors.headers.accesscontrolalloworiginlistregex=^(https?://[^/]+|capacitor://[^/]+)$')
|
||||
->and($pathLabels)->toContain('traefik.http.routers.https-0-api-app-uuid.middlewares=https-0-api-app-uuid-cors,https-0-api-app-uuid-stripprefix,gzip');
|
||||
|
||||
$frontendPayload = $payloadMethod->invoke(null, 'https://api-v2.truckwash.io/internal/frontend', 'frontend-app-uuid', 80, '');
|
||||
$frontendPayload = $payloadMethod->invoke(null, 'https://api-v2.truckwash.io/internal/frontend', 'frontend-app-uuid', 80, '', 'frontend');
|
||||
$frontendLabels = explode("\n", base64_decode($frontendPayload['custom_labels'], true));
|
||||
|
||||
expect($frontendPayload['domains'])->toBe('https://api-v2.truckwash.io:80/internal/frontend')
|
||||
->and($frontendLabels)->toContain('traefik.http.routers.https-0-frontend-app-uuid.rule=Host(`api-v2.truckwash.io`) && PathPrefix(`/internal/frontend`)')
|
||||
->and($frontendLabels)->toContain('traefik.http.middlewares.https-0-frontend-app-uuid-stripprefix.stripprefix.prefixes=/internal/frontend')
|
||||
->and($frontendLabels)->toContain('traefik.http.routers.https-0-frontend-app-uuid.middlewares=https-0-frontend-app-uuid-stripprefix,gzip');
|
||||
expect(implode("\n", $frontendLabels))->not->toContain('-cors');
|
||||
});
|
||||
|
||||
it('resolves gateway CORS from deployment context with the same precedence as runtime env', function (): void {
|
||||
$method = new ReflectionMethod(coolify_manager::class, 'gatewayRouteTargetCorsConfig');
|
||||
$config = $method->invoke(null, [
|
||||
'deploy_context_json' => json_encode([
|
||||
'coolify_env' => [
|
||||
'CORS' => 'https://array.example.test/app',
|
||||
],
|
||||
'coolify_env_file' => "CORS=https://file.example.test/path\nOTHER=value",
|
||||
'env' => "CORS=*\n",
|
||||
]),
|
||||
]);
|
||||
|
||||
expect($config)->toBe('*');
|
||||
|
||||
$requiredConfig = $method->invoke(null, [
|
||||
'deploy_context_json' => json_encode([
|
||||
'runtime_env' => [
|
||||
'CORS' => 'https://partner.example.test/app',
|
||||
],
|
||||
]),
|
||||
]);
|
||||
expect(explode(',', $requiredConfig))
|
||||
->toContain('https://partner.example.test')
|
||||
->toContain('https://truckwash.io');
|
||||
});
|
||||
|
||||
it('isolates and restores Hetzner load balancer IP targets for gateway certificate bootstrap', function (): void {
|
||||
|
||||
Reference in New Issue
Block a user