Files
coolify/tests/Feature/ApiRateLimitClientIpTest.php
T
Andras Bacsai e7465000b3 fix(api): key unauthenticated rate limits by Cloudflare client IP
Use auth_rate_limit_ip() rather than $request->ip() for the api, 5 and
feedback rate limiters. On cloud, each client behind Cloudflare now gets
its own bucket instead of sharing the proxy's bucket. Self-hosted
instances ignore the CF-Connecting-IP header.

Add feature tests for per-client sentinel push buckets on cloud and for
ignoring the header on self-hosted.

Add scripts/restore-backup-vm.sh, which restores an instance backup into
an offline KVM VM to test database migrations. Bump the v4 version in
other/nightly/versions.json to sha-1e9add3.
2026-09-29 13:06:44 +02:00

57 lines
1.8 KiB
PHP

<?php
use App\Models\InstanceSettings;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Testing\TestResponse;
uses(RefreshDatabase::class);
beforeEach(function () {
config()->set('app.maintenance.store', 'array');
config()->set('api.rate_limit', 2);
InstanceSettings::forceCreate(['id' => 0]);
});
function pushSentinelFrom(string $clientIp): TestResponse
{
return test()
->withHeader('CF-Connecting-IP', $clientIp)
->withServerVariables(['REMOTE_ADDR' => '172.70.0.1'])
->postJson('/api/v1/sentinel/push');
}
it('gives each Cloudflare client ip its own sentinel push bucket on cloud', function () {
config()->set('constants.coolify.self_hosted', false);
pushSentinelFrom('203.0.113.10')->assertUnauthorized();
pushSentinelFrom('203.0.113.10')->assertUnauthorized();
pushSentinelFrom('203.0.113.10')->assertStatus(429);
pushSentinelFrom('203.0.113.20')->assertUnauthorized();
});
it('ignores the Cloudflare client ip for sentinel pushes on self-hosted instances', function () {
config()->set('constants.coolify.self_hosted', true);
pushSentinelFrom('203.0.113.10')->assertUnauthorized();
pushSentinelFrom('203.0.113.10')->assertUnauthorized();
pushSentinelFrom('203.0.113.20')->assertStatus(429);
});
it('keys unauthenticated limiters by the Cloudflare client ip on cloud', function (string $limiter) {
config()->set('constants.coolify.self_hosted', false);
$request = Request::create('/', server: [
'REMOTE_ADDR' => '172.70.0.1',
'HTTP_CF_CONNECTING_IP' => '203.0.113.10',
]);
$limit = RateLimiter::limiter($limiter)($request);
expect($limit->key)->toBe('203.0.113.10');
})->with(['api', '5', 'feedback']);