Harden release gate diagnostics fetches

This commit is contained in:
Jeppe B
2026-06-01 23:16:51 +02:00
parent 7bb67b0470
commit dfa0441266
2 changed files with 118 additions and 11 deletions
@@ -1446,3 +1446,34 @@ it('normalizes release assignment subject suggestions without leaking private fi
'title' => 'Invalid',
]))->toBeNull();
});
it('restricts release gate fetches to Truckwash release hosts and relative paths', function (): void {
$manager = new release_manager();
$joinUrl = new ReflectionMethod(release_manager::class, 'releaseGateJoinUrl');
$joinUrl->setAccessible(true);
$hostAllowed = new ReflectionMethod(release_manager::class, 'releaseGateFetchHostAllowed');
$hostAllowed->setAccessible(true);
$publicIpAllowed = new ReflectionMethod(release_manager::class, 'releaseGatePublicIpAllowed');
$publicIpAllowed->setAccessible(true);
$stringArray = new ReflectionMethod(release_manager::class, 'releaseGateStringArray');
$stringArray->setAccessible(true);
expect($joinUrl->invoke($manager, 'https://api-v2.truckwash.io', '/master/api/ping'))
->toBe('https://api-v2.truckwash.io/master/api/ping')
->and($hostAllowed->invoke($manager, 'api-v2.truckwash.io'))->toBeTrue()
->and($hostAllowed->invoke($manager, 'assets.canary.truckwash.io'))->toBeTrue()
->and($hostAllowed->invoke($manager, 'truckwash.io.evil.test'))->toBeFalse()
->and($hostAllowed->invoke($manager, '127.0.0.1'))->toBeFalse()
->and($publicIpAllowed->invoke($manager, '8.8.8.8'))->toBeTrue()
->and($publicIpAllowed->invoke($manager, '127.0.0.1'))->toBeFalse()
->and($publicIpAllowed->invoke($manager, '10.0.0.5'))->toBeFalse()
->and($publicIpAllowed->invoke($manager, '169.254.169.254'))->toBeFalse()
->and($publicIpAllowed->invoke($manager, '::1'))->toBeFalse()
->and($stringArray->invoke($manager, ['/a', '/b', '/c'], 2))->toBe(['/a', '/b']);
expect(fn() => $joinUrl->invoke($manager, 'https://api-v2.truckwash.io', 'http://127.0.0.1/ping'))
->toThrow(RuntimeException::class, 'relative');
expect(fn() => $joinUrl->invoke($manager, 'https://api-v2.truckwash.io', '//127.0.0.1/ping'))
->toThrow(RuntimeException::class, 'relative');
});