Implements spec 094 (assignment fetch/restore observability hardening): - Adds OperationRun tracking for assignment fetch (during backup) and assignment restore (during restore execution) - Normalizes failure codes/reason_code and sanitizes failure messages - Ensures exactly one audit log entry per assignment restore execution - Enforces correct guard/membership vs capability semantics on affected admin surfaces - Switches assignment Graph services to depend on GraphClientInterface Also includes Postgres-only FK defense-in-depth check and a discoverable `composer test:pgsql` runner (scoped to the FK constraint test). Tests: - `vendor/bin/sail artisan test --compact` (passed) - `vendor/bin/sail composer test:pgsql` (passed) Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #113
61 lines
2.0 KiB
PHP
61 lines
2.0 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Resources\BackupSetResource;
|
|
use App\Filament\Resources\BackupSetResource\Pages\EditBackupSet;
|
|
use App\Filament\Resources\BackupSetResource\RelationManagers\BackupItemsRelationManager;
|
|
use App\Models\BackupItem;
|
|
use App\Models\BackupSet;
|
|
use App\Models\User;
|
|
use App\Models\WorkspaceMembership;
|
|
use Filament\Facades\Filament;
|
|
use Livewire\Livewire;
|
|
|
|
it('returns 404 for non-members before capability checks on backup item actions', function (): void {
|
|
[$owner, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($owner);
|
|
$tenant->makeCurrent();
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
]);
|
|
$backupItem = BackupItem::factory()->for($backupSet)->for($tenant)->create();
|
|
|
|
$outsider = User::factory()->create();
|
|
WorkspaceMembership::factory()->create([
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $outsider->getKey(),
|
|
'role' => 'owner',
|
|
]);
|
|
|
|
$this->actingAs($outsider);
|
|
$tenant->makeCurrent();
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$this->get(BackupSetResource::getUrl('view', ['record' => $backupSet], tenant: $tenant))
|
|
->assertNotFound();
|
|
});
|
|
|
|
it('keeps actions visible but disabled for members missing capability', function (): void {
|
|
[$readonlyUser, $tenant] = createUserWithTenant(role: 'readonly');
|
|
|
|
$this->actingAs($readonlyUser);
|
|
$tenant->makeCurrent();
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$backupSet = BackupSet::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
]);
|
|
$backupItem = BackupItem::factory()->for($backupSet)->for($tenant)->create();
|
|
|
|
Livewire::test(BackupItemsRelationManager::class, [
|
|
'ownerRecord' => $backupSet,
|
|
'pageClass' => EditBackupSet::class,
|
|
])
|
|
->assertTableActionVisible('remove', $backupItem)
|
|
->assertTableActionDisabled('remove', $backupItem);
|
|
});
|