From 6562c0400054a40b839923bd37e1d3f9bcf9869a Mon Sep 17 00:00:00 2001 From: Mathias Grimm Date: Thu, 16 Jul 2026 21:19:56 -0300 Subject: [PATCH 1/2] Fix PR 22 review findings: config edge cases and token type guard - README: google-dns warn default is 35 ms, matching the config - TCP probe config entries use ?: so a false return from parse_url still falls back to the raw env value, and empty port env values fall back to the default instead of port 0 - TcpPingProbe accepts a null/empty host and returns a failing ProbeResult instead of throwing a TypeError - Authorize middleware ignores non-string token query params instead of letting hash_equals throw a TypeError (500) Co-Authored-By: Claude Fable 5 --- README.md | 10 +++++----- src/Laravel/Http/Middleware/Authorize.php | 3 ++- src/Laravel/config/netwatch.php | 8 ++++---- src/Probe/TcpPingProbe.php | 12 +++++++++++- tests/Laravel/AuthorizeTokenTest.php | 7 +++++++ tests/Probe/TcpPingProbeTest.php | 16 ++++++++++++++++ 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 80ac90a..d85e626 100644 --- a/README.md +++ b/README.md @@ -112,8 +112,8 @@ return [ 'enabled' => env('NETWATCH_PROBE_DATABASE_TCP_ENABLED', false), 'probe' => [ TcpPingProbe::class => [ - parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?? env('DB_HOST'), - (int) env('DB_PORT', 3306), + parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?: env('DB_HOST'), + (int) (env('DB_PORT') ?: 3306), ], ], ], @@ -133,8 +133,8 @@ return [ 'enabled' => env('NETWATCH_PROBE_REDIS_TCP_ENABLED', false), 'probe' => [ TcpPingProbe::class => [ - parse_url((string) env('REDIS_HOST'), PHP_URL_HOST) ?? env('REDIS_HOST'), - (int) env('REDIS_PORT', 6379), + parse_url((string) env('REDIS_HOST'), PHP_URL_HOST) ?: env('REDIS_HOST'), + (int) (env('REDIS_PORT') ?: 6379), ], ], ], @@ -331,7 +331,7 @@ NETWATCH_PROBE_APP_WARN_MS=500 NETWATCH_PROBE_APP_CRIT_MS=1000 NETWATCH_PROBE_CLOUDFLARE_DNS_WARN_MS=35 NETWATCH_PROBE_CLOUDFLARE_DNS_CRIT_MS=50 -NETWATCH_PROBE_GOOGLE_DNS_WARN_MS=25 +NETWATCH_PROBE_GOOGLE_DNS_WARN_MS=35 NETWATCH_PROBE_GOOGLE_DNS_CRIT_MS=50 ``` diff --git a/src/Laravel/Http/Middleware/Authorize.php b/src/Laravel/Http/Middleware/Authorize.php index ce997ea..bc0c465 100644 --- a/src/Laravel/Http/Middleware/Authorize.php +++ b/src/Laravel/Http/Middleware/Authorize.php @@ -13,8 +13,9 @@ class Authorize public function handle(Request $request, Closure $next) { $token = config('netwatch.health_route.token'); + $requestToken = $request->query('token'); - if ($token && $request->query('token') && hash_equals($token, $request->query('token'))) { + if ($token && is_string($requestToken) && $requestToken !== '' && hash_equals($token, $requestToken)) { return $next($request); } diff --git a/src/Laravel/config/netwatch.php b/src/Laravel/config/netwatch.php index fc65277..cfe25e1 100644 --- a/src/Laravel/config/netwatch.php +++ b/src/Laravel/config/netwatch.php @@ -76,8 +76,8 @@ ], 'probe' => [ TcpPingProbe::class => [ - parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?? env('DB_HOST'), - (int) env('DB_PORT', 3306), + parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?: env('DB_HOST'), + (int) (env('DB_PORT') ?: 3306), ], ], ], @@ -105,8 +105,8 @@ ], 'probe' => [ TcpPingProbe::class => [ - parse_url((string) env('REDIS_HOST'), PHP_URL_HOST) ?? env('REDIS_HOST'), - (int) env('REDIS_PORT', 6379), + parse_url((string) env('REDIS_HOST'), PHP_URL_HOST) ?: env('REDIS_HOST'), + (int) (env('REDIS_PORT') ?: 6379), ], ], ], diff --git a/src/Probe/TcpPingProbe.php b/src/Probe/TcpPingProbe.php index 7b512bb..c979458 100644 --- a/src/Probe/TcpPingProbe.php +++ b/src/Probe/TcpPingProbe.php @@ -10,13 +10,23 @@ class TcpPingProbe implements ProbeInterface { public function __construct( - private readonly string $host, + private readonly ?string $host, private readonly int $port, private readonly float $timeout = 3.0, ) {} public function probe(): ProbeResult { + if ($this->host === null || $this->host === '') { + return new ProbeResult( + connectMs: 0, + requestMs: 0, + totalMs: 0, + success: false, + error: 'TCP connect failed: no host configured', + ); + } + $start = hrtime(true); $errno = 0; diff --git a/tests/Laravel/AuthorizeTokenTest.php b/tests/Laravel/AuthorizeTokenTest.php index 0e4c7dc..7910a37 100644 --- a/tests/Laravel/AuthorizeTokenTest.php +++ b/tests/Laravel/AuthorizeTokenTest.php @@ -105,6 +105,13 @@ ->assertForbidden(); }); +test('array token query param is rejected instead of erroring', function () { + config(['netwatch.health_route.token' => 'secret-token']); + + $this->get('/netwatch/health?token[]=secret-token', ['Accept' => 'application/json']) + ->assertForbidden(); +}); + test('token not configured ignores query param and uses regular auth', function () { config(['netwatch.health_route.token' => null]); diff --git a/tests/Probe/TcpPingProbeTest.php b/tests/Probe/TcpPingProbeTest.php index 07d3bff..b54381a 100644 --- a/tests/Probe/TcpPingProbeTest.php +++ b/tests/Probe/TcpPingProbeTest.php @@ -9,6 +9,22 @@ expect($probe->name())->toBe('tcp://example.com:443'); }); +test('probe fails gracefully when host is null', function () { + $probe = new TcpPingProbe(null, 3306); + $result = $probe->probe(); + + expect($result->success)->toBeFalse() + ->and($result->error)->toBe('TCP connect failed: no host configured'); +}); + +test('probe fails gracefully when host is empty', function () { + $probe = new TcpPingProbe('', 6379); + $result = $probe->probe(); + + expect($result->success)->toBeFalse() + ->and($result->error)->toBe('TCP connect failed: no host configured'); +}); + test('probe fails on unreachable host', function () { $probe = new TcpPingProbe('192.0.2.1', 9999, timeout: 0.5); $result = $probe->probe(); From a906cb1608e43d6ed630a31a5230da20634b62eb Mon Sep 17 00:00:00 2001 From: Mathias Grimm Date: Thu, 16 Jul 2026 21:25:04 -0300 Subject: [PATCH 2/2] Derive database-tcp default port from DB_CONNECTION 3306 only applies to MySQL/MariaDB; pgsql defaults to 5432 and sqlsrv to 1433 when DB_PORT is not set. Co-Authored-By: Claude Fable 5 --- README.md | 6 +++++- src/Laravel/config/netwatch.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d85e626..06f627d 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,11 @@ return [ 'probe' => [ TcpPingProbe::class => [ parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?: env('DB_HOST'), - (int) (env('DB_PORT') ?: 3306), + (int) (env('DB_PORT') ?: match (env('DB_CONNECTION')) { + 'pgsql' => 5432, + 'sqlsrv' => 1433, + default => 3306, + }), ], ], ], diff --git a/src/Laravel/config/netwatch.php b/src/Laravel/config/netwatch.php index cfe25e1..979c3ab 100644 --- a/src/Laravel/config/netwatch.php +++ b/src/Laravel/config/netwatch.php @@ -77,7 +77,11 @@ 'probe' => [ TcpPingProbe::class => [ parse_url((string) env('DB_HOST'), PHP_URL_HOST) ?: env('DB_HOST'), - (int) (env('DB_PORT') ?: 3306), + (int) (env('DB_PORT') ?: match (env('DB_CONNECTION')) { + 'pgsql' => 5432, + 'sqlsrv' => 1433, + default => 3306, + }), ], ], ],