seed([RolePermissionSeeder::class, DeviceCatalogSeeder::class]); } public function test_tenant_admin_can_create_device_and_other_tenant_cannot_see_it(): void { [$tenantA, $adminA] = $this->tenant('tenant-a'); [, $adminB] = $this->tenant('tenant-b'); $vendor = DeviceVendor::where('slug', 'mikrotik')->firstOrFail(); $type = DeviceType::where('slug', 'router')->firstOrFail(); $this->actingAs($adminA)->post(route('devices.store'), [ 'name' => 'Router Jakarta', 'management_address' => 'router.example.test', 'management_port' => 8728, 'connection_type' => 'routeros_api', 'device_vendor_id' => $vendor->id, 'device_type_id' => $type->id, 'initial_username' => 'admin', 'initial_password' => '', 'remove_legacy_users_on_activation' => true, ])->assertRedirect(route('devices.index')); $device = Device::withoutGlobalScope('tenant')->firstOrFail(); $this->assertSame($tenantA->id, $device->tenant_id); $credential = DeviceCredential::withoutGlobalScope('tenant')->where('device_id', $device->id)->firstOrFail(); $this->assertSame('admin', $credential->username); $this->assertSame('', $credential->password); $this->assertTrue($device->remove_legacy_users_on_activation); $this->actingAs($adminB)->get(route('devices.show', $device))->assertNotFound(); } public function test_tenant_user_create_access_follows_tenant_policy(): void { [$tenant, $admin] = $this->tenant('tenant-a'); setPermissionsTeamId($tenant->id); $user = User::factory()->for($tenant)->create(); $user->assignRole(SystemRole::TenantUser->value); $tenant->devicePolicy()->update(['tenant_user_can_create' => false]); $this->actingAs($user)->get(route('devices.create'))->assertForbidden(); $this->actingAs($admin)->put(route('device-policy.update'), [ 'tenant_user_can_create' => true, 'tenant_user_can_update_own' => true, 'tenant_user_can_delete_own' => false, ])->assertRedirect(); $this->actingAs($user)->get(route('devices.create'))->assertOk(); } public function test_device_password_is_encrypted_and_hidden(): void { [$tenant, $admin] = $this->tenant('tenant-a'); $device = Device::create([ 'tenant_id' => $tenant->id, 'name' => 'Router', 'device_vendor_id' => DeviceVendor::first()->id, 'device_type_id' => DeviceType::first()->id, 'management_address' => '10.0.0.1', 'management_port' => 22, 'connection_type' => 'ssh', 'created_by' => $admin->id, ]); $credential = DeviceCredential::create([ 'tenant_id' => $tenant->id, 'device_id' => $device->id, 'name' => 'Management', 'username' => 'admin', 'password' => 'DeviceSecret!123', 'connection_type' => 'ssh', ]); $this->assertNotSame('DeviceSecret!123', DB::table('device_credentials')->value('password')); $this->assertSame('DeviceSecret!123', $credential->password); $this->assertArrayNotHasKey('password', $credential->toArray()); } private function tenant(string $slug): array { $tenant = app(TenantProvisioningService::class)->createWithOwner([ 'name' => strtoupper($slug), 'slug' => $slug, 'owner_name' => 'Admin '.$slug, 'owner_email' => $slug.'@test.local', 'owner_password' => 'Strong!Password123', ]); return [$tenant, User::withoutGlobalScope('tenant')->where('tenant_id', $tenant->id)->firstOrFail()]; } }