From d437bfa33f9bc22bbd347dc81778f382b5082073 Mon Sep 17 00:00:00 2001 From: smarcet Date: Wed, 25 Mar 2026 11:36:59 -0300 Subject: [PATCH] fix(external-services): argument error implode(): Argument #2 ($array) must be of type ?array, string given --- .github/workflows/push.yml | 1 + app/Services/Apis/AbstractOAuth2Api.php | 6 +- .../Services/AbstractOAuth2ApiScopesTest.php | 85 +++++++++++++++++++ 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 tests/Unit/Services/AbstractOAuth2ApiScopesTest.php diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml index f2d4b7cda..a16d44373 100644 --- a/.github/workflows/push.yml +++ b/.github/workflows/push.yml @@ -63,6 +63,7 @@ jobs: - { name: "AuditEventTypesTest", filter: "--filter AuditEventTypesTest" } - { name: "GuzzleTracingTest", filter: "--filter GuzzleTracingTest" } - { name: "Repositories", filter: "--filter tests/Repositories/" } + - { name: "Services", filter: "--filter tests/Unit/Services/" } env: OTEL_SERVICE_ENABLED: false APP_ENV: testing diff --git a/app/Services/Apis/AbstractOAuth2Api.php b/app/Services/Apis/AbstractOAuth2Api.php index 2961ec9d9..8016c3cd9 100644 --- a/app/Services/Apis/AbstractOAuth2Api.php +++ b/app/Services/Apis/AbstractOAuth2Api.php @@ -132,8 +132,8 @@ protected function getAccessToken():?string{ Log::debug("AbstractOAuth2Api::getAccessToken - access token is empty, getting new one"); $client = $this->getIDPClient(); $appConfig = $this->getAppConfig(); - $scopes = $appConfig['scopes'] ?? []; - Log::debug(sprintf( "AbstractOAuth2Api::getAccessToken - got scopes %s", implode(' ', $scopes))); + $scopes = $appConfig['scopes'] ?? ''; + Log::debug(sprintf( "AbstractOAuth2Api::getAccessToken - got scopes %s", $scopes)); // Try to get an access token using the client credentials grant. $accessToken = $client->getAccessToken('client_credentials', ['scope' => $scopes]); $token = $accessToken->getToken(); @@ -163,4 +163,4 @@ protected function getAccessToken():?string{ protected function cleanAccessToken():void{ $this->cacheService->delete($this->getAccessTokenCacheKey()); } -} \ No newline at end of file +} diff --git a/tests/Unit/Services/AbstractOAuth2ApiScopesTest.php b/tests/Unit/Services/AbstractOAuth2ApiScopesTest.php new file mode 100644 index 000000000..e29516350 --- /dev/null +++ b/tests/Unit/Services/AbstractOAuth2ApiScopesTest.php @@ -0,0 +1,85 @@ +shouldReceive('getSingleValue')->andReturn(null); + + $api = new MailApi($cacheService); + + $reflection = new \ReflectionMethod($api, 'getAccessToken'); + $reflection->setAccessible(true); + + try { + $reflection->invoke($api); + } catch (\TypeError $e) { + $this->fail("TypeError thrown with {$description}: " . $e->getMessage()); + } catch (\Exception $e) { + // Connection/HTTP errors are expected since IDP is not reachable. + // The critical assertion is that no TypeError was thrown from implode(). + $this->assertNotInstanceOf( + \TypeError::class, + $e, + "No TypeError should occur with {$description}" + ); + } + } + + public static function scopesProvider(): array + { + return [ + 'string scopes (space-separated)' => ['scope1 scope2', 'space-separated string scopes'], + 'single string scope' => ['payment-profile/read', 'single string scope'], + 'null scopes' => [null, 'null scopes'], + 'empty string scopes' => ['', 'empty string scopes'], + ]; + } +}