From f7a9b59b64cbffb3c90214cf1a10e22c6e75a90a Mon Sep 17 00:00:00 2001 From: horea Date: Thu, 6 Mar 2025 17:01:22 +0200 Subject: [PATCH 1/5] Issue #30: Replace Psalm with PHPStan --- .github/workflows/static-analysis.yml | 49 +++++++++++++++++++ README.md | 11 +++-- composer.json | 13 ++--- docs/book/v3/overview.md | 17 +++++++ phpstan.neon | 8 +++ psalm.xml | 17 ------- src/Assertion/AssertionPluginManager.php | 2 +- test/Assertion/FactoryTest.php | 4 +- .../AssertionPluginManagerFactoryTest.php | 2 +- ...henticationIdentityProviderFactoryTest.php | 2 +- .../AuthorizationOptionFactoryTest.php | 2 +- .../AuthorizationServiceFactoryTest.php | 2 +- .../RoleProviderPluginManagerFactoryTest.php | 2 +- test/Factory/RoleServiceFactoryTest.php | 2 +- 14 files changed, 98 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/static-analysis.yml create mode 100644 docs/book/v3/overview.md create mode 100644 phpstan.neon delete mode 100644 psalm.xml diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 0000000..2423564 --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,49 @@ +on: + - push + +name: Run PHPStan checks + +jobs: + mutation: + name: PHPStan ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "8.1" + - "8.2" + - "8.3" + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + coverage: pcov + ini-values: assert.exception=1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + tools: composer:v2, cs2pr + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v4 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + + - name: Install dependencies with composer + run: composer install --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Run static analysis with PHPStan + run: vendor/bin/phpstan analyse diff --git a/README.md b/README.md index fb782ad..3941b64 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,14 @@ Rbac authorization model implements [dot-authorization](https://github.com/dotke The RBAC model defines roles that can be assigned to users. The authorization is done on a role basis, not user basis as in ACL. Each role can have one or multiple permissions/privileges assigned. When deciding if a user is authorized, the requested permission is checked in all user roles and if at least one role has that permission, access is granted. +## Documentation + +Documentation is available at: https://docs.dotkernel.org/dot-rbac/. + +## Badges + ![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-rbac) -![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.5.2) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.6.0) [![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/issues) [![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/network) @@ -14,8 +20,7 @@ The RBAC model defines roles that can be assigned to users. The authorization is [![Build Static](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml) [![codecov](https://codecov.io/gh/dotkernel/dot-rbac/graph/badge.svg?token=GCK6C92N83)](https://codecov.io/gh/dotkernel/dot-rbac) - -[![SymfonyInsight](https://insight.symfony.com/projects/ce0cfbb2-7e97-427b-b394-531ff5be13d6/big.svg)](https://insight.symfony.com/projects/ce0cfbb2-7e97-427b-b394-531ff5be13d6) +[![PHPStan](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml) ## Installation diff --git a/composer.json b/composer.json index bb3a146..0ee3a65 100644 --- a/composer.json +++ b/composer.json @@ -29,9 +29,10 @@ "laminas/laminas-authentication": "2.16.0" }, "require-dev": { - "phpunit/phpunit": "^10.2", - "vimeo/psalm": "^5.13", - "laminas/laminas-coding-standard": "^2.5" + "laminas/laminas-coding-standard": "^2.5", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.2" }, "autoload": { "psr-4": { @@ -46,12 +47,12 @@ "scripts": { "check": [ "@cs-check", - "@test" + "@test", + "@static-analysis" ], "cs-check": "phpcs", "cs-fix": "phpcbf", "test": "phpunit --colors=always", - "test-coverage": "phpunit --colors=always --coverage-clover clover.xml", - "static-analysis": "psalm --shepherd --stats" + "static-analysis": "phpstan analyse --memory-limit 1G" } } diff --git a/docs/book/v3/overview.md b/docs/book/v3/overview.md new file mode 100644 index 0000000..4a61421 --- /dev/null +++ b/docs/book/v3/overview.md @@ -0,0 +1,17 @@ +# dot-rbac + +The rbac authorization service decides if the authenticated identity or guest has access to certain parts of the application + +## Badges + +![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-rbac) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.6.0) + +[![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/issues) +[![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/network) +[![GitHub stars](https://img.shields.io/github/stars/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/stargazers) +[![GitHub license](https://img.shields.io/github/license/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/blob/3.0/LICENSE.md) + +[![Build Static](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/continuous-integration.yml) +[![codecov](https://codecov.io/gh/dotkernel/dot-rbac/graph/badge.svg?token=GCK6C92N83)](https://codecov.io/gh/dotkernel/dot-rbac) +[![PHPStan](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml/badge.svg?branch=3.0)](https://github.com/dotkernel/dot-rbac/actions/workflows/static-analysis.yml) diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..349be25 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +includes: + - vendor/phpstan/phpstan-phpunit/extension.neon +parameters: + level: 5 + paths: + - src + - test + treatPhpDocTypesAsCertain: false diff --git a/psalm.xml b/psalm.xml deleted file mode 100644 index 7272b57..0000000 --- a/psalm.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - diff --git a/src/Assertion/AssertionPluginManager.php b/src/Assertion/AssertionPluginManager.php index d8c4aff..2a6afb8 100644 --- a/src/Assertion/AssertionPluginManager.php +++ b/src/Assertion/AssertionPluginManager.php @@ -11,6 +11,6 @@ */ class AssertionPluginManager extends AbstractPluginManager { - /** @var string */ + /** @inheritDoc */ protected $instanceOf = AssertionInterface::class; } diff --git a/test/Assertion/FactoryTest.php b/test/Assertion/FactoryTest.php index a083228..371216f 100644 --- a/test/Assertion/FactoryTest.php +++ b/test/Assertion/FactoryTest.php @@ -48,7 +48,7 @@ public function assert(AuthorizationInterface $authorization, mixed $context = n $subject = new Factory($container, $assertionPluginManager); $result = $subject->create(['type' => 'testType']); - $this->assertInstanceOf(AssertionInterface::class, $result); + $this->assertContainsOnlyInstancesOf(AssertionInterface::class, [$result]); } /** @@ -62,6 +62,6 @@ public function testGetAssertionPluginManager(): void $subject = new Factory($container, $assertionPluginManager); $result = $subject->getAssertionPluginManager(); - $this->assertInstanceOf(AssertionPluginManager::class, $result); + $this->assertContainsOnlyInstancesOf(AssertionPluginManager::class, [$result]); } } diff --git a/test/Factory/AssertionPluginManagerFactoryTest.php b/test/Factory/AssertionPluginManagerFactoryTest.php index c25ae68..8854a9f 100644 --- a/test/Factory/AssertionPluginManagerFactoryTest.php +++ b/test/Factory/AssertionPluginManagerFactoryTest.php @@ -34,6 +34,6 @@ public function testCanCreateManager(): void ->willReturn($config); $result = (new AssertionPluginManagerFactory())($container); - $this->assertInstanceOf(AssertionPluginManager::class, $result); + $this->assertSame(AssertionPluginManager::class, $result::class); } } diff --git a/test/Factory/AuthenticationIdentityProviderFactoryTest.php b/test/Factory/AuthenticationIdentityProviderFactoryTest.php index 2e07256..8fd8d71 100644 --- a/test/Factory/AuthenticationIdentityProviderFactoryTest.php +++ b/test/Factory/AuthenticationIdentityProviderFactoryTest.php @@ -39,6 +39,6 @@ public function testWillCreateService(): void ]); $result = (new AuthenticationIdentityProviderFactory())($this->container); - $this->assertInstanceOf(AuthenticationIdentityProvider::class, $result); + $this->assertSame(AuthenticationIdentityProvider::class, $result::class); } } diff --git a/test/Factory/AuthorizationOptionFactoryTest.php b/test/Factory/AuthorizationOptionFactoryTest.php index 8434697..05a90c3 100644 --- a/test/Factory/AuthorizationOptionFactoryTest.php +++ b/test/Factory/AuthorizationOptionFactoryTest.php @@ -28,6 +28,6 @@ public function testCanCreateInterface(): void ->willReturn(['dot_authorization' => null]); $interface = (new AuthorizationOptionsFactory())($container); - $this->assertInstanceOf(AuthorizationOptions::class, $interface); + $this->assertSame(AuthorizationOptions::class, $interface::class); } } diff --git a/test/Factory/AuthorizationServiceFactoryTest.php b/test/Factory/AuthorizationServiceFactoryTest.php index 30ca242..3572089 100644 --- a/test/Factory/AuthorizationServiceFactoryTest.php +++ b/test/Factory/AuthorizationServiceFactoryTest.php @@ -47,6 +47,6 @@ public function testWillCreateService(): void ); $service = (new AuthorizationServiceFactory())($container); - $this->assertInstanceOf(AuthorizationService::class, $service); + $this->assertSame(AuthorizationService::class, $service::class); } } diff --git a/test/Factory/RoleProviderPluginManagerFactoryTest.php b/test/Factory/RoleProviderPluginManagerFactoryTest.php index a3bc459..74a39e9 100644 --- a/test/Factory/RoleProviderPluginManagerFactoryTest.php +++ b/test/Factory/RoleProviderPluginManagerFactoryTest.php @@ -35,6 +35,6 @@ public function testCanCreate(): void ->willReturn($config); $service = (new RoleProviderPluginManagerFactory())($container); - $this->assertInstanceOf(RoleProviderPluginManager::class, $service); + $this->assertSame(RoleProviderPluginManager::class, $service::class); } } diff --git a/test/Factory/RoleServiceFactoryTest.php b/test/Factory/RoleServiceFactoryTest.php index 7c85c2e..14399b4 100644 --- a/test/Factory/RoleServiceFactoryTest.php +++ b/test/Factory/RoleServiceFactoryTest.php @@ -44,7 +44,7 @@ public function testWillCreateService(): void $service = (new RoleServiceFactory())($container); - $this->assertInstanceOf(RoleService::class, $service); + $this->assertSame(RoleService::class, $service::class); } /** From 2979d9044277d6103015d3f3ff6cd552a193fa98 Mon Sep 17 00:00:00 2001 From: horea Date: Thu, 6 Mar 2025 17:01:56 +0200 Subject: [PATCH 2/5] Issue #30: Replace Psalm with PHPStan --- src/Assertion/AssertionPluginManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Assertion/AssertionPluginManager.php b/src/Assertion/AssertionPluginManager.php index 2a6afb8..6d94c84 100644 --- a/src/Assertion/AssertionPluginManager.php +++ b/src/Assertion/AssertionPluginManager.php @@ -11,6 +11,6 @@ */ class AssertionPluginManager extends AbstractPluginManager { - /** @inheritDoc */ + /** @var string */ protected $instanceOf = AssertionInterface::class; } From 37874912a7d418860ef927ddad9afad93cfa9345 Mon Sep 17 00:00:00 2001 From: horea Date: Thu, 6 Mar 2025 17:04:02 +0200 Subject: [PATCH 3/5] Issue #30: Replace Psalm with PHPStan Signed-off-by: horea --- src/Assertion/AssertionPluginManager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Assertion/AssertionPluginManager.php b/src/Assertion/AssertionPluginManager.php index 6d94c84..d8c4aff 100644 --- a/src/Assertion/AssertionPluginManager.php +++ b/src/Assertion/AssertionPluginManager.php @@ -11,6 +11,6 @@ */ class AssertionPluginManager extends AbstractPluginManager { - /** @var string */ + /** @var string */ protected $instanceOf = AssertionInterface::class; } From bf43b685ed8bb828d1a4f3c5e7f8b507c3d5662f Mon Sep 17 00:00:00 2001 From: horea Date: Mon, 10 Mar 2025 16:38:55 +0200 Subject: [PATCH 4/5] Issue #30: Replace Psalm with PHPStan Signed-off-by: horea --- README.md | 2 +- composer.json | 6 +++--- docs/book/index.md | 2 +- docs/book/v3/overview.md | 2 +- phpstan.neon | 7 +++++++ src/Assertion/AssertionPluginManager.php | 2 +- src/Role/Provider/RoleProviderPluginManager.php | 2 +- 7 files changed, 15 insertions(+), 8 deletions(-) mode change 100644 => 120000 docs/book/index.md diff --git a/README.md b/README.md index 3941b64..74547cd 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Documentation is available at: https://docs.dotkernel.org/dot-rbac/. ## Badges ![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-rbac) -![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.6.0) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.7.0) [![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/issues) [![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/network) diff --git a/composer.json b/composer.json index 0ee3a65..4b8ccbf 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "dotkernel/dot-rbac", "type": "library", - "description": "DotKernel RBAC authorization component", + "description": "Dotkernel RBAC authorization component", "license": "MIT", "homepage": "https://github.com/dotkernel/dot-rbac", "keywords": [ @@ -11,7 +11,7 @@ ], "authors": [ { - "name": "DotKernel Team", + "name": "Dotkernel Team", "email": "team@dotkernel.com" } ], @@ -29,7 +29,7 @@ "laminas/laminas-authentication": "2.16.0" }, "require-dev": { - "laminas/laminas-coding-standard": "^2.5", + "laminas/laminas-coding-standard": "^3.0", "phpstan/phpstan": "^2.1", "phpstan/phpstan-phpunit": "^2.0", "phpunit/phpunit": "^10.2" diff --git a/docs/book/index.md b/docs/book/index.md deleted file mode 100644 index ae42a26..0000000 --- a/docs/book/index.md +++ /dev/null @@ -1 +0,0 @@ -../../README.md diff --git a/docs/book/index.md b/docs/book/index.md new file mode 120000 index 0000000..fe84005 --- /dev/null +++ b/docs/book/index.md @@ -0,0 +1 @@ +../../README.md \ No newline at end of file diff --git a/docs/book/v3/overview.md b/docs/book/v3/overview.md index 4a61421..5eb606e 100644 --- a/docs/book/v3/overview.md +++ b/docs/book/v3/overview.md @@ -5,7 +5,7 @@ The rbac authorization service decides if the authenticated identity or guest ha ## Badges ![OSS Lifecycle](https://img.shields.io/osslifecycle/dotkernel/dot-rbac) -![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.6.0) +![PHP from Packagist (specify version)](https://img.shields.io/packagist/php-v/dotkernel/dot-rbac/3.7.0) [![GitHub issues](https://img.shields.io/github/issues/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/issues) [![GitHub forks](https://img.shields.io/github/forks/dotkernel/dot-rbac)](https://github.com/dotkernel/dot-rbac/network) diff --git a/phpstan.neon b/phpstan.neon index 349be25..bad3fa6 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -6,3 +6,10 @@ parameters: - src - test treatPhpDocTypesAsCertain: false + ignoreErrors: + - message: '#Call to method Laminas\\ServiceManager\\AbstractPluginManager::validate\(\) with ''test'' will always evaluate to false.#' + path: test/Assertion/AssertionPluginManagerTest.php + - message: '#PHPDoc type class-string\|null of property Dot\\Rbac\\Role\\Provider\\RoleProviderPluginManager::\$instanceOf is not covariant with PHPDoc type class-string\|null of overridden property Laminas\\ServiceManager\\AbstractPluginManager::\$instanceOf.#' + path: src/Role/Provider/RoleProviderPluginManager.php + - message: '#PHPDoc type class-string\|null of property Dot\\Rbac\\Assertion\\AssertionPluginManager::\$instanceOf is not covariant with PHPDoc type class-string\|null of overridden property Laminas\\ServiceManager\\AbstractPluginManager::\$instanceOf.#' + path: src/Assertion/AssertionPluginManager.php \ No newline at end of file diff --git a/src/Assertion/AssertionPluginManager.php b/src/Assertion/AssertionPluginManager.php index d8c4aff..a677b3d 100644 --- a/src/Assertion/AssertionPluginManager.php +++ b/src/Assertion/AssertionPluginManager.php @@ -11,6 +11,6 @@ */ class AssertionPluginManager extends AbstractPluginManager { - /** @var string */ + /** @var null|class-string $instanceOf */ protected $instanceOf = AssertionInterface::class; } diff --git a/src/Role/Provider/RoleProviderPluginManager.php b/src/Role/Provider/RoleProviderPluginManager.php index 70837b4..f51b006 100644 --- a/src/Role/Provider/RoleProviderPluginManager.php +++ b/src/Role/Provider/RoleProviderPluginManager.php @@ -12,7 +12,7 @@ */ class RoleProviderPluginManager extends AbstractPluginManager { - /** @var string */ + /** @var null|class-string $instanceOf */ protected $instanceOf = RoleProviderInterface::class; /** @var string[] */ From 1543771fe83a50ec9422af36372891a15c9888a9 Mon Sep 17 00:00:00 2001 From: Alex Karajos Date: Tue, 11 Mar 2025 08:01:06 +0200 Subject: [PATCH 5/5] Added missing empty line at the end of `phpstan.neon` --- phpstan.neon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpstan.neon b/phpstan.neon index bad3fa6..8f793ef 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -12,4 +12,4 @@ parameters: - message: '#PHPDoc type class-string\|null of property Dot\\Rbac\\Role\\Provider\\RoleProviderPluginManager::\$instanceOf is not covariant with PHPDoc type class-string\|null of overridden property Laminas\\ServiceManager\\AbstractPluginManager::\$instanceOf.#' path: src/Role/Provider/RoleProviderPluginManager.php - message: '#PHPDoc type class-string\|null of property Dot\\Rbac\\Assertion\\AssertionPluginManager::\$instanceOf is not covariant with PHPDoc type class-string\|null of overridden property Laminas\\ServiceManager\\AbstractPluginManager::\$instanceOf.#' - path: src/Assertion/AssertionPluginManager.php \ No newline at end of file + path: src/Assertion/AssertionPluginManager.php