Skip to content

feat(permission): fresh-port Spatie permission package#402

Open
binaryfire wants to merge 23 commits into
0.4from
feature/permission-spatie-fresh-port
Open

feat(permission): fresh-port Spatie permission package#402
binaryfire wants to merge 23 commits into
0.4from
feature/permission-spatie-fresh-port

Conversation

@binaryfire

Copy link
Copy Markdown
Collaborator

Summary

Fresh-ports hypervel/permission from the current spatie/laravel-permission package and adapts it for Hypervel 0.4's long-lived Swoole/coroutine runtime.

This replaces the older Hypervel 0.3-era implementation with a current Spatie-compatible API surface, while preserving Hypervel-specific improvements such as forbidden permissions, coroutine-safe team state, and worker-aware caching.

What Changed

  • Archived the old permission implementation and tests under _archive/ for reference.
  • Rebuilt the package around Spatie's current public API:
    • HasRoles
    • HasPermissions
    • Role
    • Permission
    • PermissionRegistrar
    • middleware
    • route macros
    • Blade directives
    • commands
    • events
    • wildcard permissions
    • teams
  • Switched schema/API naming back to Spatie conventions:
    • model_has_roles
    • model_has_permissions
    • model_morph_key
  • Added teams support, including permission:setup-teams.
  • Added Passport client-credentials middleware support using fake client tests for now, with a todo to replace those with real Passport tests once Hypervel Passport is ported.
  • Preserved Hypervel's forbidden permissions feature:
    • direct forbidden permissions
    • role-inherited forbidden permissions
    • forbidden wins over allowed
    • forbidden pivot state in cache payloads
  • Added unit enum input support where Hypervel's enum_value() supports it.
  • Added package state cleanup to AfterEachTestSubscriber.
  • Added Auth\Factory::getDefaultDriver() so guard resolution can depend on the auth contract.
  • Added Model::flushGuardableColumns() as a narrow Eloquent helper for schema-mutating tests that need to clear cached guardable-column metadata without flushing all model state.
  • Rewrote the permission README and Boost docs for the new package.

Performance

The port keeps the public API close to Spatie, but adapts hot paths for Hypervel's worker model.

  • Permission data is cached through the configured cache store for cross-worker and cross-node freshness.
  • Repeated permission reads in the same coroutine use Hypervel's memoized cache layer.
  • Model assignment cache keys include morph class, model key, team id, and assignment-cache version.
  • Role/permission writes and assignment changes explicitly invalidate affected cache entries.
  • Stable config-derived metadata is held on the registrar for worker-lifetime reuse.
  • Team-aware syncRoles() avoids a redundant relation reload while preserving behavior.
  • Permission events are only dispatched when enabled and when listeners are registered.

Coroutine Safety

The port avoids storing request/team state on worker-lifetime singletons.

  • Current team id is stored in CoroutineContext.
  • Registrar-held state is limited to boot/config-derived data and cache metadata.
  • Mutable per-request/team state is isolated per coroutine.
  • Static and singleton-held package state has explicit cleanup hooks for tests.
  • Coroutine isolation tests cover the request/team state behavior.

Intentional Hypervel Differences

This is not a blind copy of Spatie/Laravel internals. The API is kept close to Spatie, but internals are adapted where Hypervel's runtime requires it.

  • Laravel Octane reset listeners are not ported. Hypervel is Swoole-native:
    • transient team/request state uses coroutine context
    • cache freshness is handled through configured cache stores, memoized reads, and explicit invalidation
  • Team state is not stored on a singleton resolver property because that would leak across concurrent coroutines.
  • Permission cache reads use Hypervel's cache manager memo layer rather than Laravel's request-per-process assumptions.
  • Event dispatch is guarded by events_enabled and hasListeners() to keep dormant framework events cheap.
  • Forbidden permissions are retained as a Hypervel improvement.
  • Deprecated/old 0.3 aliases and Hyperf-era package shapes were not preserved because Hypervel 0.4 is greenfield.

Testing

The fresh port includes broad coverage from upstream Spatie plus Hypervel-specific regression tests.

Added and ported coverage for:

  • commands
  • middleware
  • Passport client-credential fallback path
  • teams
  • wildcard permissions
  • route macros
  • Blade directives
  • gates and policies
  • multiple guards
  • cache behavior
  • permission registrar behavior
  • custom models
  • custom schema config
  • unit enum inputs
  • forbidden permissions
  • assignment events
  • coroutine isolation
  • public API expectations

Validation run before opening this PR:

composer fix

Result:

  • PHP CS Fixer: green
  • PHPStan: green
  • ParaTest: green

Claude reviewed and signed off on the final implementation after the full validation run.

Add a package:install command that scaffolds a Hypervel Workbench application for package development.

The command creates Workbench directories, writes testbench.yaml, generates auth-ready Workbench stubs, wires composer autoload-dev namespaces, optionally exports the runtime .env example, creates the runtime SQLite database, and refreshes Composer autoloads.

Move standalone Testbench CLI providers into the early extra.providers path so commands contributed by TestbenchServiceProvider are discoverable before the console kernel loads command definitions.

Document the new install flow, force/basic options, and intentional Workbench surface differences from Orchestra.

Add regression coverage for default and basic scaffolds, composer autoload idempotency, namespace conflicts, existing namespace reuse, sqlite creation, env export prompt paths, and command registration.
Add the implementation plans used for the fresh hypervel/permission port from spatie/laravel-permission.

Capture the porting decisions, Hypervel-specific architecture notes, test strategy, and review context so the package rewrite has durable background for future maintenance.
Move the previous Hypervel 0.3-era permission package, docs, and tests into the archive for reference.

Remove the old manager, singular traits, broad exception wrappers, legacy command location, and old tests so the new package can be rebuilt around the current Spatie surface and Hypervel 0.4 architecture.
Add the new permission package metadata, root autoload wiring, configuration file, and migration stubs for the Spatie-based port.

The schema uses Spatie model_* naming, supports teams, includes forbidden permission pivots, and keeps the upgrade migration for enabling teams after initial installation.
Port the Spatie permission contracts and typed exception classes to Hypervel namespaces and strict PHP types.

Replace the old broad RoleException and PermissionException surfaces with precise exceptions for missing roles, missing permissions, guard mismatches, teams, wildcard validation, and authorization failures.
Add the new PermissionRegistrar, config access layer, guard resolver, coroutine-safe team resolver, and helper functions.

The registrar uses configured cache repositories plus memoized reads, keeps team state in CoroutineContext, stores worker-lifetime config-derived state explicitly, and exposes cache invalidation paths for long-lived Hypervel workers.
Port the Spatie Role and Permission models to Hypervel with strict typing, model_* schema naming, configured table and key support, teams-aware lookups, and forbidden permission pivot support.

Keep Spatie public APIs such as findByName, findById, findOrCreate, users, roles, and permissions while adapting lookup and cache behavior for Hypervel's singleton registrar.
Port Spatie's permission, role, assigned-model, cache-refresh, and wildcard trait behavior into the fresh Hypervel package.

Integrate forbidden permissions, unit-enum inputs, team-aware relation handling, model assignment cache invalidation, and wildcard checks without keeping old 0.3 singular trait aliases.
Port Spatie's role, permission, and role-or-permission middleware to Hypervel.

Support pipe, array, enum, guard, Passport client credential fallback, and canonical Spatie method names while preserving Hypervel strict typing and exception behavior.
Port Spatie's role and permission assignment event classes to Hypervel.

These events back attach and detach hooks while the package dispatch path remains guarded by configuration and Hypervel listener checks so dormant events stay cheap.
Port the permission console commands to Hypervel command conventions.

Add role and permission creation, role assignment, cache reset, permission table display, and setup-teams migration generation with strict types and Hypervel path/config behavior.
Wire the fresh permission package into Hypervel through its service provider.

Register config, publishes, commands, contract bindings, middleware aliases, route macros, Blade directives, Gate permission checks, and About command output while documenting the intentional Octane omission at the future-porting point.
Add getDefaultDriver() to the auth factory contract so permission guard resolution can depend on the contract instead of the concrete auth manager.

This is the getter counterpart to the existing shouldUse() setter and represents behavior all conforming auth factories need to provide.
Add Model::flushGuardableColumns() as a narrow reset for cached guardable-column metadata.

This lets tests and schema-mutating flows clear stale table-column metadata without calling the broader Model::flushState(), and keeps flushState behavior unchanged by delegating through the new helper. Add focused coverage proving other model static state is preserved.
Register the permission team resolver and registrar with the global after-test cleanup subscriber.

This prevents worker-lifetime registrar state and coroutine-backed team state from leaking across the permission test suite while matching the existing Hypervel static-state cleanup pattern.
Add the Hypervel testbench base case and package fixtures for the fresh permission port.

The harness configures guards, providers, schema, cache isolation, Passport-style fake clients, team setup helpers, custom model fixtures, Blade fixture views, and package-specific route helpers used by the ported test suite.
Port and adapt command tests for the fresh permission package.

Cover role and permission creation, duplicate handling, command output, teams setup migration generation and execution, role assignment, team-aware assignment, and team display behavior under Hypervel testbench.
Port and expand middleware tests for permission, role, role-or-permission, wildcard, and Passport client credential behavior.

The Passport tests use a local fake guard and client until Hypervel Passport exists, while preserving the upstream client-credential behavior matrix and recording the later real-Passport replacement in the todo list.
Port and adapt model and trait tests for roles, permissions, teams, custom models, assigned models, wildcard permissions, nesting, and soft-delete behavior.

Include Hypervel-specific coverage for forbidden permissions, team-scoped query optimization, cross-team deletion, custom schema behavior, and UUID custom model replacements.
Port integration-style tests for Blade directives, route macros, gate integration, custom gates, cache behavior, multiple guards, policies, wildcard routes, and registrar behavior.

These tests exercise the package through Hypervel's container, auth, routing, view, cache, and gate layers rather than only direct model calls.
Add Hypervel-specific and port-completeness tests for the permission package.

Cover coroutine isolation, forbidden permissions, event dispatch behavior, schema customization, teams schema, public API expectations, unit enum inputs, and wildcard permission parsing/matching.
Rewrite the permission package README and Boost docs for the fresh Spatie-based Hypervel port.

Document installation, traits, roles, permissions, teams, guards, middleware, routes, Blade directives, commands, wildcards, events, forbidden permissions, cache behavior, and differences from Spatie/Laravel. Add a durable todo to replace fake Passport client tests with real Passport coverage after Passport is ported.
@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Too many files changed for review. (175 files found, 100 file limit)

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 175 files, which is 25 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16962b76-1605-483a-b365-f64f3c52c7a1

📥 Commits

Reviewing files that changed from the base of the PR and between 113a726 and 16f58d7.

📒 Files selected for processing (175)
  • _archive/docs/permission.md
  • _archive/src/permission/LICENSE.md
  • _archive/src/permission/README.md
  • _archive/src/permission/composer.json
  • _archive/src/permission/config/permission.php
  • _archive/src/permission/database/migrations/2025_07_02_000000_create_permission_tables.php
  • _archive/src/permission/src/Console/ShowCommand.php
  • _archive/src/permission/src/Contracts/Factory.php
  • _archive/src/permission/src/Contracts/Permission.php
  • _archive/src/permission/src/Contracts/Role.php
  • _archive/src/permission/src/Exceptions/PermissionException.php
  • _archive/src/permission/src/Exceptions/RoleException.php
  • _archive/src/permission/src/Exceptions/UnauthorizedException.php
  • _archive/src/permission/src/Middleware/PermissionMiddleware.php
  • _archive/src/permission/src/Middleware/RoleMiddleware.php
  • _archive/src/permission/src/Models/Permission.php
  • _archive/src/permission/src/Models/Role.php
  • _archive/src/permission/src/PermissionManager.php
  • _archive/src/permission/src/PermissionServiceProvider.php
  • _archive/src/permission/src/Traits/HasPermission.php
  • _archive/src/permission/src/Traits/HasRole.php
  • _archive/tests/Permission/Enums/Permission.php
  • _archive/tests/Permission/Enums/Role.php
  • _archive/tests/Permission/HasPermissionTest.php
  • _archive/tests/Permission/HasRoleTest.php
  • _archive/tests/Permission/Middleware/PermissionMiddlewareTest.php
  • _archive/tests/Permission/Middleware/RoleMiddlewareTest.php
  • _archive/tests/Permission/Models/User.php
  • _archive/tests/Permission/PermissionManagerTest.php
  • _archive/tests/Permission/PermissionTestCase.php
  • _archive/tests/Permission/migrations/2025_07_01_000000_create_users_table.php
  • composer.json
  • docs/plans/2026-06-24-2406-permission-fresh-spatie-port.md
  • docs/plans/permission-package-fresh-port.md
  • src/boost/docs/permission.md
  • src/boost/docs/testbench.md
  • src/boost/todo.md
  • src/contracts/src/Auth/Factory.php
  • src/database/src/Eloquent/Model.php
  • src/permission/LICENSE.md
  • src/permission/README.md
  • src/permission/composer.json
  • src/permission/config/permission.php
  • src/permission/database/migrations/2025_07_02_000000_create_permission_tables.php
  • src/permission/database/migrations/add_teams_fields.php.stub
  • src/permission/src/Commands/AssignRoleCommand.php
  • src/permission/src/Commands/CacheResetCommand.php
  • src/permission/src/Commands/CreatePermissionCommand.php
  • src/permission/src/Commands/CreateRoleCommand.php
  • src/permission/src/Commands/ShowCommand.php
  • src/permission/src/Commands/UpgradeForTeamsCommand.php
  • src/permission/src/Contracts/Permission.php
  • src/permission/src/Contracts/PermissionsTeamResolver.php
  • src/permission/src/Contracts/Role.php
  • src/permission/src/Contracts/Wildcard.php
  • src/permission/src/DefaultTeamResolver.php
  • src/permission/src/Events/PermissionAttachedEvent.php
  • src/permission/src/Events/PermissionDetachedEvent.php
  • src/permission/src/Events/RoleAttachedEvent.php
  • src/permission/src/Events/RoleDetachedEvent.php
  • src/permission/src/Exceptions/GuardDoesNotMatch.php
  • src/permission/src/Exceptions/PermissionAlreadyExists.php
  • src/permission/src/Exceptions/PermissionDoesNotExist.php
  • src/permission/src/Exceptions/RoleAlreadyExists.php
  • src/permission/src/Exceptions/RoleDoesNotExist.php
  • src/permission/src/Exceptions/TeamModelNotConfigured.php
  • src/permission/src/Exceptions/TeamsNotEnabled.php
  • src/permission/src/Exceptions/UnauthorizedException.php
  • src/permission/src/Exceptions/WildcardPermissionInvalidArgument.php
  • src/permission/src/Exceptions/WildcardPermissionNotImplementsContract.php
  • src/permission/src/Exceptions/WildcardPermissionNotProperlyFormatted.php
  • src/permission/src/Guard.php
  • src/permission/src/Middleware/PermissionMiddleware.php
  • src/permission/src/Middleware/RoleMiddleware.php
  • src/permission/src/Middleware/RoleOrPermissionMiddleware.php
  • src/permission/src/Models/Permission.php
  • src/permission/src/Models/Role.php
  • src/permission/src/PermissionRegistrar.php
  • src/permission/src/PermissionServiceProvider.php
  • src/permission/src/Support/Config.php
  • src/permission/src/Traits/HasAssignedModels.php
  • src/permission/src/Traits/HasPermissions.php
  • src/permission/src/Traits/HasRoles.php
  • src/permission/src/Traits/RefreshesPermissionCache.php
  • src/permission/src/WildcardPermission.php
  • src/permission/src/helpers.php
  • src/testbench/src/Console/Commander.php
  • src/testbench/src/Foundation/Console/InstallCommand.php
  • src/testbench/src/Foundation/Console/stubs/database-seeder.stub
  • src/testbench/src/Foundation/Console/stubs/provider.stub
  • src/testbench/src/Foundation/Console/stubs/routes.api.stub
  • src/testbench/src/Foundation/Console/stubs/routes.console.stub
  • src/testbench/src/Foundation/Console/stubs/routes.web.stub
  • src/testbench/src/Foundation/Console/stubs/testbench.basic.yaml.stub
  • src/testbench/src/Foundation/Console/stubs/testbench.yaml.stub
  • src/testbench/src/Foundation/Console/stubs/user-factory.stub
  • src/testbench/src/Foundation/Console/stubs/user.stub
  • src/testbench/src/Foundation/Console/stubs/workbench.gitignore
  • src/testbench/src/TestbenchServiceProvider.php
  • tests/AfterEachTestSubscriber.php
  • tests/Cache/CacheMemoizedStoreTest.php
  • tests/Database/DatabaseEloquentModelTest.php
  • tests/Permission/CacheTest.php
  • tests/Permission/Commands/CommandTest.php
  • tests/Permission/Commands/TeamCommandTest.php
  • tests/Permission/CoroutineIsolationTest.php
  • tests/Permission/CustomGateTest.php
  • tests/Permission/CustomSchemaConfigTest.php
  • tests/Permission/Events/EventTest.php
  • tests/Permission/Fixtures/ContentPolicy.php
  • tests/Permission/Fixtures/Models/Admin.php
  • tests/Permission/Fixtures/Models/Client.php
  • tests/Permission/Fixtures/Models/Content.php
  • tests/Permission/Fixtures/Models/Manager.php
  • tests/Permission/Fixtures/Models/Permission.php
  • tests/Permission/Fixtures/Models/Role.php
  • tests/Permission/Fixtures/Models/RuntimeRole.php
  • tests/Permission/Fixtures/Models/SoftDeletingUser.php
  • tests/Permission/Fixtures/Models/Team.php
  • tests/Permission/Fixtures/Models/TestRolePermissionsEnum.php
  • tests/Permission/Fixtures/Models/User.php
  • tests/Permission/Fixtures/Models/UserWithoutHasRoles.php
  • tests/Permission/Fixtures/Models/WildcardPermission.php
  • tests/Permission/Fixtures/PassportGuard.php
  • tests/Permission/Fixtures/TestHelper.php
  • tests/Permission/Fixtures/views/can.blade.php
  • tests/Permission/Fixtures/views/guardHasAllRoles.blade.php
  • tests/Permission/Fixtures/views/guardHasAllRolesArray.blade.php
  • tests/Permission/Fixtures/views/guardHasAllRolesPipe.blade.php
  • tests/Permission/Fixtures/views/guardHasAnyRole.blade.php
  • tests/Permission/Fixtures/views/guardHasAnyRolePipe.blade.php
  • tests/Permission/Fixtures/views/guardHasRole.blade.php
  • tests/Permission/Fixtures/views/guardRole.blade.php
  • tests/Permission/Fixtures/views/guardunlessrole.blade.php
  • tests/Permission/Fixtures/views/hasAllRoles.blade.php
  • tests/Permission/Fixtures/views/hasAnyRole.blade.php
  • tests/Permission/Fixtures/views/hasRole.blade.php
  • tests/Permission/Fixtures/views/haspermission.blade.php
  • tests/Permission/Fixtures/views/role.blade.php
  • tests/Permission/Fixtures/views/unlessrole.blade.php
  • tests/Permission/ForbiddenPermissionTest.php
  • tests/Permission/GateTest.php
  • tests/Permission/Integration/BladeTest.php
  • tests/Permission/Integration/CacheTest.php
  • tests/Permission/Integration/MultipleGuardsTest.php
  • tests/Permission/Integration/PermissionRegistrarTest.php
  • tests/Permission/Integration/PolicyTest.php
  • tests/Permission/Integration/RouteTest.php
  • tests/Permission/Integration/WildcardRouteTest.php
  • tests/Permission/Middleware/PassportClientMiddlewareTest.php
  • tests/Permission/Middleware/PermissionMiddlewareTest.php
  • tests/Permission/Middleware/RoleMiddlewareTest.php
  • tests/Permission/Middleware/RoleOrPermissionMiddlewareTest.php
  • tests/Permission/Middleware/WildcardMiddlewareTest.php
  • tests/Permission/Models/PermissionTest.php
  • tests/Permission/Models/RoleTest.php
  • tests/Permission/Models/RoleWithNestingTest.php
  • tests/Permission/Models/WildcardRoleTest.php
  • tests/Permission/PublicApiTest.php
  • tests/Permission/SchemaConfigTest.php
  • tests/Permission/TeamsTest.php
  • tests/Permission/TestCase.php
  • tests/Permission/Traits/HasAssignedModelsTest.php
  • tests/Permission/Traits/HasPermissionsTest.php
  • tests/Permission/Traits/HasPermissionsWithCustomModelsTest.php
  • tests/Permission/Traits/HasRolesTest.php
  • tests/Permission/Traits/HasRolesWithCustomModelsTest.php
  • tests/Permission/Traits/TeamHasPermissionsTest.php
  • tests/Permission/Traits/TeamHasRolesTest.php
  • tests/Permission/Traits/TeamScopeTest.php
  • tests/Permission/Traits/WildcardHasPermissionsTest.php
  • tests/Permission/UnitEnumTest.php
  • tests/Permission/WildcardPermissionTest.php
  • tests/Testbench/Foundation/Console/InstallCommandTest.php
  • tests/Testbench/Foundation/TestbenchServiceProviderTest.php

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/permission-spatie-fresh-port

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@hypervel hypervel deleted a comment from coderabbitai Bot Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant