From baab00a10ae98c6db561c30df9c24353278b9f2b Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 10:43:45 +0200 Subject: [PATCH 1/7] Drop nullable from $provider test property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `$this->provider` is initialized in `setUp()` and never assigned null, so the nullable type was misleading. Dropping the `?` removes 25 of the 46 grandfathered errors in `phpstan-baseline.neon` — every `Cannot call method X() on …|null` was a downstream consequence of that one type. Co-Authored-By: Claude Opus 4.7 (1M context) --- phpstan-baseline.neon | 72 ------------------- .../OpenIdConfigurationProviderTest.php | 2 +- 2 files changed, 1 insertion(+), 73 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 9d14590..4a89a8d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -54,72 +54,6 @@ parameters: count: 1 path: tests/Security/OpenIdConfigurationProviderTest.php - - - message: '#^Cannot call method generateNonce\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method generateState\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getAuthorizationUrl\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 3 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getBaseAccessTokenUrl\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getBaseAuthorizationUrl\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getDefaultScopes\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getEndSessionUrl\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 6 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getGuarded\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getResourceOwnerDetailsUrl\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method getState\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Cannot call method validateIdToken\(\) on ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\.$#' - identifier: method.nonObject - count: 7 - path: tests/Security/OpenIdConfigurationProviderTest.php - - message: '#^Parameter \#1 \$json of function json_decode expects string, string\|false given\.$#' identifier: argument.type @@ -131,9 +65,3 @@ parameters: identifier: argument.type count: 1 path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Property Tests\\Security\\OpenIdConfigurationProviderTest\:\:\$provider \(ItkDev\\OpenIdConnect\\Security\\OpenIdConfigurationProvider\|null\) is never assigned null so it can be removed from the property type\.$#' - identifier: property.unusedType - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php diff --git a/tests/Security/OpenIdConfigurationProviderTest.php b/tests/Security/OpenIdConfigurationProviderTest.php index c3ef46b..808dac9 100644 --- a/tests/Security/OpenIdConfigurationProviderTest.php +++ b/tests/Security/OpenIdConfigurationProviderTest.php @@ -37,7 +37,7 @@ class OpenIdConfigurationProviderTest extends TestCase private const REDIRECT_URI = 'https://redirect.url'; private const NONCE = '12345678'; - private ?OpenIdConfigurationProvider $provider; + private OpenIdConfigurationProvider $provider; public function setUp(): void { From 02d877972754b29f029ff0f40066ff4dd2fb2f75 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 10:48:44 +0200 Subject: [PATCH 2/7] Install phpstan/phpstan-mockery for Mockery type stubs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `shouldReceive(...)->andReturn(...)` is the Mockery fluent API. The return type of `shouldReceive()` is declared as `Mockery\ExpectationInterface|Mockery\HigherOrderMessage`, and the chained methods only exist on `ExpectationInterface` — PHPStan can't tell the call sites are safe without type stubs. `phpstan/phpstan-mockery` is the official PHPStan extension shipping those stubs. Adding it removes 8 entries from `phpstan-baseline.neon`. Co-Authored-By: Claude Opus 4.7 (1M context) --- composer.json | 3 ++- phpstan-baseline.neon | 18 ------------------ phpstan.neon | 1 + 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/composer.json b/composer.json index 1bf1ecb..4c60f08 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "mockery/mockery": "^1.6.12", "phpstan/phpstan": "^2.1.41", "phpunit/php-code-coverage": "^12", - "phpunit/phpunit": "^12" + "phpunit/phpunit": "^12", + "phpstan/phpstan-mockery": "^2.0" }, "autoload": { "psr-4": { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4a89a8d..6c77134 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -30,24 +30,6 @@ parameters: count: 3 path: tests/Security/OpenIdConfigurationProviderTest.php - - - message: '#^Call to an undefined method Mockery\\ExpectationInterface\|Mockery\\HigherOrderMessage\:\:andReturn\(\)\.$#' - identifier: method.notFound - count: 6 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Call to an undefined method Mockery\\ExpectationInterface\|Mockery\\HigherOrderMessage\:\:andThrow\(\)\.$#' - identifier: method.notFound - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Call to an undefined method Mockery\\ExpectationInterface\|Mockery\\HigherOrderMessage\:\:with\(\)\.$#' - identifier: method.notFound - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php - - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' identifier: method.alreadyNarrowedType diff --git a/phpstan.neon b/phpstan.neon index b0a1a59..b1a3869 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,6 @@ includes: - phpstan-baseline.neon + - vendor/phpstan/phpstan-mockery/extension.neon parameters: level: 8 From f47f708007c8e7880f6ded3f97d3fb8a5eaa65a1 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 10:51:46 +0200 Subject: [PATCH 3/7] Narrow validateIdToken claim accesses via @var MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `validateIdToken()` is declared `: object` in the library — PHPStan can't see the dynamic `nonce` / `aud` properties of the decoded JWT payload. Annotate each call site's local `$claims` with an `object{nonce, aud}` shape so the subsequent property reads type- check. Removes 5 entries from `phpstan-baseline.neon`. Co-Authored-By: Claude Opus 4.7 (1M context) --- phpstan-baseline.neon | 12 ------------ tests/Security/OpenIdConfigurationProviderTest.php | 3 +++ 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 6c77134..32e1130 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -18,18 +18,6 @@ parameters: count: 1 path: tests/Security/MockJWT.php - - - message: '#^Access to an undefined property object\:\:\$aud\.$#' - identifier: property.notFound - count: 2 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Access to an undefined property object\:\:\$nonce\.$#' - identifier: property.notFound - count: 3 - path: tests/Security/OpenIdConfigurationProviderTest.php - - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' identifier: method.alreadyNarrowedType diff --git a/tests/Security/OpenIdConfigurationProviderTest.php b/tests/Security/OpenIdConfigurationProviderTest.php index 808dac9..026f72f 100644 --- a/tests/Security/OpenIdConfigurationProviderTest.php +++ b/tests/Security/OpenIdConfigurationProviderTest.php @@ -238,6 +238,7 @@ public function testValidateIdTokenSuccess(): void ) )->andReturn($mockClaims); + /** @var object{nonce: string, aud: string|list} $claims */ $claims = $this->provider->validateIdToken('token', self::NONCE); $this->assertEquals(self::NONCE, $claims->nonce); @@ -436,6 +437,7 @@ public function testValidateIdTokenArrayAudience(): void $mockJWT->shouldReceive('decode')->andReturn($mockClaims); + /** @var object{nonce: string, aud: string|list} $claims */ $claims = $this->provider->validateIdToken('token', self::NONCE); $this->assertEquals(self::NONCE, $claims->nonce); @@ -770,6 +772,7 @@ public function testGetJwtVerificationKeysCacheHit(): void $mockClaims = $this->getMockClaims(); $mockJWT->shouldReceive('decode')->andReturn($mockClaims); + /** @var object{nonce: string} $claims */ $claims = $provider->validateIdToken('token', self::NONCE); $this->assertEquals(self::NONCE, $claims->nonce); } From eda1395ec2074f9e48880e0df6fc18fe678dfdda Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 10:57:59 +0200 Subject: [PATCH 4/7] Fail loudly on missing fixtures and malformed authorization URLs `(string) file_get_contents(...)` silently coerces the `false` returned when a fixture is missing into an empty string, which then flows into `json_decode` and produces `null`. Tests downstream of that report confusing assertion failures instead of "the fixture isn't there". Similarly, `(string) parse_url(...)` masks malformed-URL failures. Replaces the three duplicate fixture loads with a single `loadMockFixture()` helper that uses `assertNotFalse` and `assertIsArray` to fail the test at the actual error boundary. The `parse_url` call adds an `assertIsString` guard for the same reason. Removes 4 entries from `phpstan-baseline.neon`. Co-Authored-By: Claude Opus 4.7 (1M context) --- phpstan-baseline.neon | 12 ------ .../OpenIdConfigurationProviderTest.php | 38 ++++++++++++------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 32e1130..040ec00 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -23,15 +23,3 @@ parameters: identifier: method.alreadyNarrowedType count: 1 path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Parameter \#1 \$json of function json_decode expects string, string\|false given\.$#' - identifier: argument.type - count: 3 - path: tests/Security/OpenIdConfigurationProviderTest.php - - - - message: '#^Parameter \#1 \$string of function parse_str expects string, string\|false\|null given\.$#' - identifier: argument.type - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php diff --git a/tests/Security/OpenIdConfigurationProviderTest.php b/tests/Security/OpenIdConfigurationProviderTest.php index 026f72f..fed9b23 100644 --- a/tests/Security/OpenIdConfigurationProviderTest.php +++ b/tests/Security/OpenIdConfigurationProviderTest.php @@ -168,7 +168,9 @@ public function testGetAuthorizationUrl(): void $authUrl = $this->provider->getAuthorizationUrl(['state' => $state, 'nonce' => $nonce]); $query = []; - parse_str(parse_url($authUrl, PHP_URL_QUERY), $query); + $queryString = parse_url($authUrl, PHP_URL_QUERY); + $this->assertIsString($queryString, 'Generated authorization URL must have a query string'); + parse_str($queryString, $query); $this->assertSame('openid', $query['scope']); $this->assertSame('id_token', $query['response_type']); @@ -544,10 +546,7 @@ public function testGetIdTokenFailure(): void public function testGetConfigurationCacheHit(): void { - $configuration = json_decode( - file_get_contents(__DIR__.'/../MockData/mockOpenIDConfiguration.json'), - true - ); + $configuration = $this->loadMockFixture('mockOpenIDConfiguration.json'); $mockCacheItem = $this->createStub(CacheItemInterface::class); $mockCacheItem->method('isHit')->willReturn(true); @@ -732,10 +731,7 @@ public function testGetJwtVerificationKeysCacheHit(): void { $openIDConnectMetadataUrl = 'https://some.url/openid-configuration'; - $configuration = json_decode( - file_get_contents(__DIR__.'/../MockData/mockOpenIDConfiguration.json'), - true - ); + $configuration = $this->loadMockFixture('mockOpenIDConfiguration.json'); $cachedKeys = ['key1' => new Key('public-key-data', 'RS256')]; @@ -807,10 +803,7 @@ public function testGetConfigurationCacheInvalidArgument(): void public function testGetJwtVerificationKeysCacheInvalidArgument(): void { $openIDConnectMetadataUrl = 'https://some.url/openid-configuration'; - $configuration = json_decode( - file_get_contents(__DIR__.'/../MockData/mockOpenIDConfiguration.json'), - true - ); + $configuration = $this->loadMockFixture('mockOpenIDConfiguration.json'); $configCacheItem = $this->createStub(CacheItemInterface::class); $configCacheItem->method('isHit')->willReturn(true); @@ -901,6 +894,25 @@ public function testBase64urlDecodeFailure(): void * @return ResponseInterface * A success ("200") response with mock body data */ + /** + * Load a JSON fixture from tests/MockData and decode it as an associative + * array. Fails the test with an explicit message if the file is missing / + * unreadable / not valid JSON, rather than letting `false` or `null` flow + * silently into the assertion under test. + * + * @return array + */ + private function loadMockFixture(string $filename): array + { + $path = __DIR__.'/../MockData/'.$filename; + $contents = file_get_contents($path); + $this->assertNotFalse($contents, sprintf('Mock fixture not readable: %s', $path)); + $decoded = json_decode($contents, true); + $this->assertIsArray($decoded, sprintf('Mock fixture is not valid JSON: %s', $path)); + + return $decoded; + } + private function getMockHttpSuccessResponse(string $mockResponseDataPath): ResponseInterface { $mockResponseData = file_get_contents(__DIR__.$mockResponseDataPath); From 32aa3e6d53ad195ba50acb41a7b6dd5dc9f6ec70 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 11:00:05 +0200 Subject: [PATCH 5/7] Clear remaining level-8 test issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three small cleanups, each removing one entry from the baseline: - `testCheckResponseSuccess` swaps `assertTrue(true)` (which PHPStan correctly flags as a tautology) for `expectNotToPerformAssertions()`, the PHPUnit idiom for "this test verifies the call doesn't throw". - `testAbstractBaseImplementsMarker` was using a constant-folded `is_subclass_of(...)` call wrapped in `assertTrue`. Replaced with a runtime `ReflectionClass::getInterfaceNames()` check + `assertContains` — PHPStan can't fold the reflection result, and the assertion stays semantically meaningful (catches a future regression that removes the marker from the deprecated abstract). - `MockJWT::$leeway` declares a type (`?int`) so the property satisfies PHPStan's missingType.property rule. Baseline now empty — see follow-up commit. Co-Authored-By: Claude Opus 4.7 (1M context) --- phpstan-baseline.neon | 25 +------------------ tests/Exception/ExceptionHierarchyTest.php | 14 +++++++---- tests/Security/MockJWT.php | 2 +- .../OpenIdConfigurationProviderTest.php | 3 ++- 4 files changed, 13 insertions(+), 31 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 040ec00..aab4991 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,25 +1,2 @@ parameters: - ignoreErrors: - - - message: '#^Call to function is_subclass_of\(\) with ''ItkDev\\\\OpenIdConnect\\\\Exception\\\\ItkOpenIdConnectException'' and ''ItkDev\\\\OpenIdConnect\\\\Exception\\\\OpenIdConnectExceptionInterface'' will always evaluate to true\.$#' - identifier: function.alreadyNarrowedType - count: 1 - path: tests/Exception/ExceptionHierarchyTest.php - - - - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' - identifier: method.alreadyNarrowedType - count: 1 - path: tests/Exception/ExceptionHierarchyTest.php - - - - message: '#^Property Tests\\Security\\MockJWT\:\:\$leeway has no type specified\.$#' - identifier: missingType.property - count: 1 - path: tests/Security/MockJWT.php - - - - message: '#^Call to method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true will always evaluate to true\.$#' - identifier: method.alreadyNarrowedType - count: 1 - path: tests/Security/OpenIdConfigurationProviderTest.php + ignoreErrors: [] diff --git a/tests/Exception/ExceptionHierarchyTest.php b/tests/Exception/ExceptionHierarchyTest.php index 06fdd92..658cd65 100644 --- a/tests/Exception/ExceptionHierarchyTest.php +++ b/tests/Exception/ExceptionHierarchyTest.php @@ -121,11 +121,15 @@ public function testAbstractBaseImplementsMarker(): void // Catch sites that wrote `catch (ItkOpenIdConnectException $e)` should // migrate to the marker interface; this assertion guards the marker // implementation while the deprecation window is open. - $this->assertTrue( - is_subclass_of( - \ItkDev\OpenIdConnect\Exception\ItkOpenIdConnectException::class, - OpenIdConnectExceptionInterface::class, - ), + // + // ReflectionClass keeps the check at runtime so PHPStan can't fold it + // into a constant tautology — the value of the test is catching a + // *future* regression that removes the marker from the abstract. + $reflection = new \ReflectionClass(\ItkDev\OpenIdConnect\Exception\ItkOpenIdConnectException::class); + $this->assertContains( + OpenIdConnectExceptionInterface::class, + $reflection->getInterfaceNames(), + 'Deprecated abstract must still implement the marker for 5.x BC.', ); } } diff --git a/tests/Security/MockJWT.php b/tests/Security/MockJWT.php index 95a8cde..cdd40e7 100644 --- a/tests/Security/MockJWT.php +++ b/tests/Security/MockJWT.php @@ -4,5 +4,5 @@ class MockJWT { - public static $leeway; + public static ?int $leeway = null; } diff --git a/tests/Security/OpenIdConfigurationProviderTest.php b/tests/Security/OpenIdConfigurationProviderTest.php index fed9b23..8bd4338 100644 --- a/tests/Security/OpenIdConfigurationProviderTest.php +++ b/tests/Security/OpenIdConfigurationProviderTest.php @@ -373,6 +373,8 @@ public function testGetResourceOwnerDetailsUrl(): void public function testCheckResponseSuccess(): void { + $this->expectNotToPerformAssertions(); + $response = $this->createStub(ResponseInterface::class); $response->method('getStatusCode')->willReturn(200); @@ -380,7 +382,6 @@ public function testCheckResponseSuccess(): void // Should not throw $method->invoke($this->provider, $response, ['data' => 'value']); - $this->assertTrue(true); } public function testCheckResponseWithErrorString(): void From c865421803f9b6d8c7999c13bcd753bd1710a46e Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 11:01:03 +0200 Subject: [PATCH 6/7] Delete now-empty phpstan-baseline.neon The four predecessor commits cleared the 46 grandfathered errors that `phpstan-baseline.neon` was absorbing. With the baseline at zero entries the file serves no purpose, so drop it (and its include line from `phpstan.neon`) rather than keep an empty alias around. PHPStan still runs at level 8 across `src` and `tests` and remains clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- phpstan-baseline.neon | 2 -- phpstan.neon | 1 - 2 files changed, 3 deletions(-) delete mode 100644 phpstan-baseline.neon diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon deleted file mode 100644 index aab4991..0000000 --- a/phpstan-baseline.neon +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - ignoreErrors: [] diff --git a/phpstan.neon b/phpstan.neon index b1a3869..6e3ce04 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,5 +1,4 @@ includes: - - phpstan-baseline.neon - vendor/phpstan/phpstan-mockery/extension.neon parameters: From 54be58b319d0e4d9721c7329340f41196abf6546 Mon Sep 17 00:00:00 2001 From: turegjorup Date: Tue, 12 May 2026 11:25:55 +0200 Subject: [PATCH 7/7] Fix CI failures: redundant PHPDoc, composer order, CHANGELOG - `php-cs-fixer` (@Symfony ruleset) flagged a redundant `@param` PHPDoc on a typed parameter in `getMockHttpSuccessResponse`. Auto-fixed. - `composer normalize` reorders `phpstan-mockery` alphabetically within `require-dev` (it landed at the bottom after the manual `composer require`, between `phpunit/phpunit` and nothing). - The `changelog` CI step requires every PR to touch `CHANGELOG.md`. Added a "Tooling" subsection to `[Unreleased]` summarising what this PR's six commits did (PHPStan scope extension, mockery extension install, baseline cleanup). Co-Authored-By: Claude Opus 4.7 (1M context) --- CHANGELOG.md | 18 ++++++++++++++++++ composer.json | 4 ++-- .../OpenIdConfigurationProviderTest.php | 3 --- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 470efa0..13d2d49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 migration. Also fixed the `validateIdToken` example to catch the marker interface instead of the now-deprecated abstract. +### Tooling + +- PHPStan now scans `tests/` in addition to `src/` at level 8, with + `reportIgnoresWithoutComments: true` so unexplained + `@phpstan-ignore` directives fail CI. +- Added `phpstan/phpstan-mockery` to `require-dev` for stubs covering + Mockery's fluent `shouldReceive(...)->andReturn(...)` API. +- Cleaned the 46 pre-existing level-8 issues in `tests/`: dropped the + unused nullable from `$this->provider`, narrowed `validateIdToken` + claim accesses with `object{nonce, aud}` `@var` shapes, replaced + silent `(string)` coercion of `file_get_contents` / `parse_url` + failures with `assertNotFalse` / `assertIsString` boundary guards, + swapped `assertTrue(true)` tautologies for + `expectNotToPerformAssertions`, and replaced the constant-folded + `is_subclass_of` marker check with a `ReflectionClass` lookup so + PHPStan can't fold it into a tautology. `phpstan-baseline.neon` + consequently shrinks to zero and is deleted. + ## [4.1.2] - 2026-05-11 - Chained `previous` consistently in `OpenIdConfigurationProvider` catch diff --git a/composer.json b/composer.json index 4c60f08..bb3321b 100644 --- a/composer.json +++ b/composer.json @@ -32,9 +32,9 @@ "friendsofphp/php-cs-fixer": "^3.75", "mockery/mockery": "^1.6.12", "phpstan/phpstan": "^2.1.41", + "phpstan/phpstan-mockery": "^2.0", "phpunit/php-code-coverage": "^12", - "phpunit/phpunit": "^12", - "phpstan/phpstan-mockery": "^2.0" + "phpunit/phpunit": "^12" }, "autoload": { "psr-4": { diff --git a/tests/Security/OpenIdConfigurationProviderTest.php b/tests/Security/OpenIdConfigurationProviderTest.php index 8bd4338..7c91d1e 100644 --- a/tests/Security/OpenIdConfigurationProviderTest.php +++ b/tests/Security/OpenIdConfigurationProviderTest.php @@ -889,9 +889,6 @@ public function testBase64urlDecodeFailure(): void /** * Get a mock success response with mock date. * - * @param string $mockResponseDataPath - * Path to the file containing the mock response data - * * @return ResponseInterface * A success ("200") response with mock body data */