From e4c1106e2dc8d8a22329f7314db2816c01e163b2 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 6 Jan 2026 00:36:20 -0500 Subject: [PATCH 1/5] use phpunit --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d2bab5c..a923130 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,4 +44,4 @@ jobs: run: php artisan key:generate - name: Execute tests - run: php artisan test + run: php vendor/bin/phpunit From f90ebd99cdf173888506be6cbeb673ba5ce17eea Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 6 Jan 2026 00:40:59 -0500 Subject: [PATCH 2/5] add workflow_dispatch --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a923130..d6d4807 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -8,6 +8,7 @@ on: pull_request: schedule: - cron: "0 0 * * *" + workflow_dispatch: permissions: contents: read From 48350c63865144456f1725a6489b9f0fccd99859 Mon Sep 17 00:00:00 2001 From: Jason Vertucio Date: Tue, 6 Jan 2026 15:52:28 -0500 Subject: [PATCH 3/5] Include current spatie migrations --- .github/workflows/tests.yml | 8 + config/logging.php | 8 +- config/permission.php | 202 ++++++++++++++++++ ...4_01_01_00002_create_permission_tables.php | 134 ++++++++++++ ...2024_01_01_00004_create_passkeys_table.php | 32 +++ 5 files changed, 380 insertions(+), 4 deletions(-) create mode 100644 config/permission.php create mode 100644 database/migrations/2024_01_01_00002_create_permission_tables.php create mode 100644 database/migrations/2024_01_01_00004_create_passkeys_table.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d6d4807..494e283 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,5 +44,13 @@ jobs: - name: Generate app key run: php artisan key:generate + - name: Run migrations + run: php artisan migrate:fresh + + - name: Seed database + run: | + php artisan db:seed + php artisan db:seed --class=AuthKitSeeder + - name: Execute tests run: php vendor/bin/phpunit diff --git a/config/logging.php b/config/logging.php index 9e998a4..506d4bd 100644 --- a/config/logging.php +++ b/config/logging.php @@ -60,14 +60,14 @@ 'single' => [ 'driver' => 'single', - 'path' => storage_path('logs/laravel.log'), + 'path' => storage_path('logs/authkit.log'), 'level' => env('LOG_LEVEL', 'debug'), 'replace_placeholders' => true, ], 'daily' => [ 'driver' => 'daily', - 'path' => storage_path('logs/laravel.log'), + 'path' => storage_path('logs/authkit.log'), 'level' => env('LOG_LEVEL', 'debug'), 'days' => env('LOG_DAILY_DAYS', 14), 'replace_placeholders' => true, @@ -89,7 +89,7 @@ 'handler_with' => [ 'host' => env('PAPERTRAIL_URL'), 'port' => env('PAPERTRAIL_PORT'), - 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://' . env('PAPERTRAIL_URL') . ':' . env('PAPERTRAIL_PORT'), ], 'processors' => [PsrLogMessageProcessor::class], ], @@ -124,7 +124,7 @@ ], 'emergency' => [ - 'path' => storage_path('logs/laravel.log'), + 'path' => storage_path('logs/emergency.log'), ], ], diff --git a/config/permission.php b/config/permission.php new file mode 100644 index 0000000..f39f6b5 --- /dev/null +++ b/config/permission.php @@ -0,0 +1,202 @@ + [ + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * Eloquent model should be used to retrieve your permissions. Of course, it + * is often just the "Permission" model but you may use whatever you like. + * + * The model you want to use as a Permission model needs to implement the + * `Spatie\Permission\Contracts\Permission` contract. + */ + + 'permission' => Spatie\Permission\Models\Permission::class, + + /* + * When using the "HasRoles" trait from this package, we need to know which + * Eloquent model should be used to retrieve your roles. Of course, it + * is often just the "Role" model but you may use whatever you like. + * + * The model you want to use as a Role model needs to implement the + * `Spatie\Permission\Contracts\Role` contract. + */ + + 'role' => Spatie\Permission\Models\Role::class, + + ], + + 'table_names' => [ + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'roles' => 'roles', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your permissions. We have chosen a basic + * default value but you may easily change it to any table you like. + */ + + 'permissions' => 'permissions', + + /* + * When using the "HasPermissions" trait from this package, we need to know which + * table should be used to retrieve your models permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_permissions' => 'model_has_permissions', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your models roles. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'model_has_roles' => 'model_has_roles', + + /* + * When using the "HasRoles" trait from this package, we need to know which + * table should be used to retrieve your roles permissions. We have chosen a + * basic default value but you may easily change it to any table you like. + */ + + 'role_has_permissions' => 'role_has_permissions', + ], + + 'column_names' => [ + /* + * Change this if you want to name the related pivots other than defaults + */ + 'role_pivot_key' => null, // default 'role_id', + 'permission_pivot_key' => null, // default 'permission_id', + + /* + * Change this if you want to name the related model primary key other than + * `model_id`. + * + * For example, this would be nice if your primary keys are all UUIDs. In + * that case, name this `model_uuid`. + */ + + 'model_morph_key' => 'model_id', + + /* + * Change this if you want to use the teams feature and your related model's + * foreign key is other than `team_id`. + */ + + 'team_foreign_key' => 'team_id', + ], + + /* + * When set to true, the method for checking permissions will be registered on the gate. + * Set this to false if you want to implement custom logic for checking permissions. + */ + + 'register_permission_check_method' => true, + + /* + * When set to true, Laravel\Octane\Events\OperationTerminated event listener will be registered + * this will refresh permissions on every TickTerminated, TaskTerminated and RequestTerminated + * NOTE: This should not be needed in most cases, but an Octane/Vapor combination benefited from it. + */ + 'register_octane_reset_listener' => false, + + /* + * Events will fire when a role or permission is assigned/unassigned: + * \Spatie\Permission\Events\RoleAttached + * \Spatie\Permission\Events\RoleDetached + * \Spatie\Permission\Events\PermissionAttached + * \Spatie\Permission\Events\PermissionDetached + * + * To enable, set to true, and then create listeners to watch these events. + */ + 'events_enabled' => false, + + /* + * Teams Feature. + * When set to true the package implements teams using the 'team_foreign_key'. + * If you want the migrations to register the 'team_foreign_key', you must + * set this to true before doing the migration. + * If you already did the migration then you must make a new migration to also + * add 'team_foreign_key' to 'roles', 'model_has_roles', and 'model_has_permissions' + * (view the latest version of this package's migration file) + */ + + 'teams' => false, + + /* + * The class to use to resolve the permissions team id + */ + 'team_resolver' => \Spatie\Permission\DefaultTeamResolver::class, + + /* + * Passport Client Credentials Grant + * When set to true the package will use Passports Client to check permissions + */ + + 'use_passport_client_credentials' => false, + + /* + * When set to true, the required permission names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_permission_in_exception' => false, + + /* + * When set to true, the required role names are added to exception messages. + * This could be considered an information leak in some contexts, so the default + * setting is false here for optimum safety. + */ + + 'display_role_in_exception' => false, + + /* + * By default wildcard permission lookups are disabled. + * See documentation to understand supported syntax. + */ + + 'enable_wildcard_permission' => false, + + /* + * The class to use for interpreting wildcard permissions. + * If you need to modify delimiters, override the class and specify its name here. + */ + // 'wildcard_permission' => Spatie\Permission\WildcardPermission::class, + + /* Cache-specific settings */ + + 'cache' => [ + + /* + * By default all permissions are cached for 24 hours to speed up performance. + * When permissions or roles are updated the cache is flushed automatically. + */ + + 'expiration_time' => \DateInterval::createFromDateString('24 hours'), + + /* + * The cache key used to store all permissions. + */ + + 'key' => 'spatie.permission.cache', + + /* + * You may optionally indicate a specific cache driver to use for permission and + * role caching using any of the `store` drivers listed in the cache.php config + * file. Using 'default' here means to use the `default` set in cache.php. + */ + + 'store' => 'default', + ], +]; diff --git a/database/migrations/2024_01_01_00002_create_permission_tables.php b/database/migrations/2024_01_01_00002_create_permission_tables.php new file mode 100644 index 0000000..66ce1f9 --- /dev/null +++ b/database/migrations/2024_01_01_00002_create_permission_tables.php @@ -0,0 +1,134 @@ +engine('InnoDB'); + $table->bigIncrements('id'); // permission id + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) { + // $table->engine('InnoDB'); + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format) + $table->string('guard_name'); // For MyISAM use string('guard_name', 25); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) { + $table->unsignedBigInteger($pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) { + $table->unsignedBigInteger($pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) { + $table->unsignedBigInteger($pivotPermission); + $table->unsignedBigInteger($pivotRole); + + $table->foreign($pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign($pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $tableNames = config('permission.table_names'); + + throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +}; diff --git a/database/migrations/2024_01_01_00004_create_passkeys_table.php b/database/migrations/2024_01_01_00004_create_passkeys_table.php new file mode 100644 index 0000000..926e3aa --- /dev/null +++ b/database/migrations/2024_01_01_00004_create_passkeys_table.php @@ -0,0 +1,32 @@ +getTable(); + + Schema::create('passkeys', function (Blueprint $table) use ($authenticatableTableName,$authenticatableClass) { + $table->id(); + + $table + ->foreignIdFor($authenticatableClass, 'authenticatable_id') + ->constrained(table: $authenticatableTableName, indexName: 'passkeys_authenticatable_fk') + ->cascadeOnDelete(); + + $table->text('name'); + $table->text('credential_id'); + $table->json('data'); + + $table->timestamp('last_used_at')->nullable(); + $table->timestamps(); + }); + } +}; From cd26ce1a644b6b67cf54bfa0da84869878f4da6d Mon Sep 17 00:00:00 2001 From: Jason Vertucio Date: Tue, 6 Jan 2026 16:00:53 -0500 Subject: [PATCH 4/5] Ensure testing database is created for this workflow --- .github/workflows/tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 494e283..e16d557 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -44,6 +44,11 @@ jobs: - name: Generate app key run: php artisan key:generate + - name: Prepare SQLite database + run: | + mkdir -p database + touch database/database.sqlite + - name: Run migrations run: php artisan migrate:fresh From d1f20e1d85182241153c15200b47efced5cf19ba Mon Sep 17 00:00:00 2001 From: Jason Vertucio Date: Tue, 6 Jan 2026 16:03:51 -0500 Subject: [PATCH 5/5] Simplify test steps --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e16d557..b8e2d50 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -53,9 +53,7 @@ jobs: run: php artisan migrate:fresh - name: Seed database - run: | - php artisan db:seed - php artisan db:seed --class=AuthKitSeeder + run: php artisan db:seed --class=AuthKitSeeder - name: Execute tests run: php vendor/bin/phpunit