From 9d0c884251c426ac3bc744817d1341151a4b075f Mon Sep 17 00:00:00 2001 From: ahmido Date: Sun, 15 Feb 2026 21:56:37 +0000 Subject: [PATCH] fix: prevent null workspace_id in tenant_permissions (#116) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds workspace_id to the TenantPermission::updateOrCreate(...) payload and gates persistence when $tenant->workspace_id is null: TenantPermissionService.php Updates/extends tests so this is covered: Persists with workspace even if events are disabled Does not persist at all when tenant workspace is missing TenantPermissionServiceTest.php ## Summary ## Spec-Driven Development (SDD) - [ ] Es gibt eine Spec unter `specs/-/` - [ ] Enthaltene Dateien: `plan.md`, `tasks.md`, `spec.md` - [ ] Spec beschreibt Verhalten/Acceptance Criteria (nicht nur Implementation) - [ ] Wenn sich Anforderungen während der Umsetzung geändert haben: Spec/Plan/Tasks wurden aktualisiert ## Implementation - [ ] Implementierung entspricht der Spec - [ ] Edge cases / Fehlerfälle berücksichtigt - [ ] Keine unbeabsichtigten Änderungen außerhalb des Scopes ## Tests - [ ] Tests ergänzt/aktualisiert (Pest/PHPUnit) - [ ] Relevante Tests lokal ausgeführt (`./vendor/bin/sail artisan test` oder `php artisan test`) ## Migration / Config / Ops (falls relevant) - [ ] Migration(en) enthalten und getestet - [ ] Rollback bedacht (rückwärts kompatibel, sichere Migration) - [ ] Neue Env Vars dokumentiert (`.env.example` / Doku) - [ ] Queue/cron/storage Auswirkungen geprüft ## UI (Filament/Livewire) (falls relevant) - [ ] UI-Flows geprüft - [ ] Screenshots/Notizen hinzugefügt ## Notes Co-authored-by: Ahmed Darrazi Reviewed-on: https://git.cloudarix.de/ahmido/TenantAtlas/pulls/116 --- .../Intune/TenantPermissionService.php | 3 +- tests/Unit/TenantPermissionServiceTest.php | 40 +++++++++++++++++-- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/app/Services/Intune/TenantPermissionService.php b/app/Services/Intune/TenantPermissionService.php index 42e1ef4..df97dc3 100644 --- a/app/Services/Intune/TenantPermissionService.php +++ b/app/Services/Intune/TenantPermissionService.php @@ -143,7 +143,7 @@ public function compare( $hasErrors = false; $checkedAt = now(); - $canPersist = $persist; + $canPersist = $persist && $tenant->workspace_id !== null; if ($canPersist && $liveCheckMeta['attempted'] === true && $liveCheckMeta['succeeded'] === false) { // Enterprise-safe: never overwrite stored inventory when we could not refresh it. @@ -191,6 +191,7 @@ public function compare( 'permission_key' => $key, ], [ + 'workspace_id' => $tenant->workspace_id, 'status' => $status, 'details' => $details, 'last_checked_at' => $checkedAt, diff --git a/tests/Unit/TenantPermissionServiceTest.php b/tests/Unit/TenantPermissionServiceTest.php index 3259d12..a5f0a53 100644 --- a/tests/Unit/TenantPermissionServiceTest.php +++ b/tests/Unit/TenantPermissionServiceTest.php @@ -31,7 +31,7 @@ function requiredPermissions(): array ])); }); - $tenant = Tenant::create([ + $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-ok', 'name' => 'Tenant OK', ]); @@ -64,7 +64,7 @@ function requiredPermissions(): array ])); }); - $tenant = Tenant::create([ + $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-missing', 'name' => 'Tenant Missing', ]); @@ -100,7 +100,7 @@ function requiredPermissions(): array ->andReturn(new GraphResponse(false, [], 500, ['Graph API error'])); }); - $tenant = Tenant::create([ + $tenant = Tenant::factory()->create([ 'tenant_id' => 'tenant-error', 'name' => 'Tenant Error', ]); @@ -159,3 +159,37 @@ function requiredPermissions(): array config()->set('intune_permissions.permissions', $originalPermissions); config()->set('intune_permissions.granted_stub', $originalStub); }); + +it('persists permissions with workspace_id even when model events are disabled', function () { + $tenant = Tenant::factory()->create(); + + ensureDefaultProviderConnection($tenant, 'microsoft'); + + TenantPermission::withoutEvents(function () use ($tenant): void { + app(TenantPermissionService::class)->compare($tenant); + }); + + $this->assertDatabaseHas('tenant_permissions', [ + 'tenant_id' => $tenant->id, + 'workspace_id' => $tenant->workspace_id, + ]); +}); + +it('does not persist when tenant workspace_id is missing', function () { + $tenant = Tenant::withoutEvents(function (): Tenant { + return Tenant::create([ + 'tenant_id' => 'tenant-no-workspace', + 'external_id' => 'tenant-no-workspace', + 'name' => 'Tenant No Workspace', + 'status' => Tenant::STATUS_ACTIVE, + 'environment' => 'other', + 'workspace_id' => null, + ]); + }); + + ensureDefaultProviderConnection($tenant, 'microsoft'); + + app(TenantPermissionService::class)->compare($tenant, persist: true); + + expect(TenantPermission::query()->where('tenant_id', (int) $tenant->getKey())->count())->toBe(0); +});