From e6d18931efa5b81ae9ff3a3a20b13d91fb85a378 Mon Sep 17 00:00:00 2001 From: Patrick Dawkins Date: Tue, 26 May 2026 18:11:28 +0100 Subject: [PATCH] fix(tunnel): cast remote port to int in TunnelManager::create The relationship metadata returned by the API delivers `port` as a string. Tunnel::__construct types $remotePort as int, so tunnel:open crashed with a TypeError when constructing the Tunnel object. Cast $service['port'] to int at the call site. Co-Authored-By: Claude Opus 4.7 (1M context) --- legacy/src/Service/TunnelManager.php | 4 +++- legacy/tests/Service/TunnelManagerTest.php | 26 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/legacy/src/Service/TunnelManager.php b/legacy/src/Service/TunnelManager.php index 9ceb8f7f..c5054cd8 100644 --- a/legacy/src/Service/TunnelManager.php +++ b/legacy/src/Service/TunnelManager.php @@ -51,7 +51,9 @@ public function create(Selection $selection, array $service, ?int $localPort = n 'service' => $service, ]; - return new Tunnel($this->getId($metadata), $localPort ?: $this->getPort(), $service['host'], $service['port'], $metadata); + // The 'port' value from the API relationship metadata is a string, but + // Tunnel expects an int, so cast it here. + return new Tunnel($this->getId($metadata), $localPort ?: $this->getPort(), $service['host'], (int) $service['port'], $metadata); } /** diff --git a/legacy/tests/Service/TunnelManagerTest.php b/legacy/tests/Service/TunnelManagerTest.php index 2112e5b9..abd95d50 100644 --- a/legacy/tests/Service/TunnelManagerTest.php +++ b/legacy/tests/Service/TunnelManagerTest.php @@ -5,11 +5,14 @@ namespace Platformsh\Cli\Tests\Service; use PHPUnit\Framework\TestCase; +use Platformsh\Cli\Selector\Selection; use Platformsh\Cli\Service\Config; use Platformsh\Cli\Service\Io; use Platformsh\Cli\Service\Relationships; use Platformsh\Cli\Service\TunnelManager; use Platformsh\Cli\Tunnel\Tunnel; +use Platformsh\Client\Model\Environment; +use Platformsh\Client\Model\Project; class TunnelManagerTest extends TestCase { @@ -95,6 +98,29 @@ public function testUnserializeOldFormatWithoutId(): void $this->assertSame(1, $tunnel->metadata['serviceKey']); } + public function testCreateCastsRemotePortToInt(): void + { + // Relationship data from the API delivers 'port' as a string, but + // Tunnel::$remotePort is typed int. Regression test for #72. + $selection = new Selection( + null, + new Project(['id' => 'proj1']), + new Environment(['id' => 'main']), + 'app', + ); + $service = [ + 'host' => 'database.internal', + 'port' => '3306', + '_relationship_name' => 'database', + '_relationship_key' => 0, + ]; + + $tunnel = $this->createManager()->create($selection, $service, 30000); + + $this->assertSame(3306, $tunnel->remotePort); + $this->assertSame(30000, $tunnel->localPort); + } + public function testUnserializeOldFormatDerivedIdIsStable(): void { $json = (string) json_encode([