create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $this->actingAs($user); DB::statement('SET app.current_tenant_id = '.$tenant->id); $oldUrl = 'https://8.8.8.8/hook'; OutboundWebhookSubscription::factory()->create([ 'tenant_id' => $tenant->id, 'user_id' => $user->id, 'target_url' => $oldUrl, ]); $newUrl = 'https://1.1.1.1/hook'; $r = $this->putJson('/api/tenants/me/webhook-settings', [ 'target_url' => $newUrl, ]); $r->assertStatus(200); $row = DB::table('tenant_operations_log') ->where('event', 'webhook_settings.updated') ->where('tenant_id', $tenant->id) ->latest('id') ->first(); expect($row)->not->toBeNull() ->and($row->entity_type)->toBe('webhook_settings') ->and((int) $row->user_id)->toBe($user->id); $after = json_decode($row->payload_after, true); expect($after['target_url'] ?? null)->toBe($newUrl); $before = json_decode($row->payload_before, true); expect($before['target_url'] ?? null)->toBe($oldUrl); }); it('webhook_settings.updated logged when subscription created for first time', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $this->actingAs($user); DB::statement('SET app.current_tenant_id = '.$tenant->id); $newUrl = 'https://93.184.216.34/hook'; $r = $this->putJson('/api/tenants/me/webhook-settings', [ 'target_url' => $newUrl, ]); $r->assertStatus(200); $row = DB::table('tenant_operations_log') ->where('event', 'webhook_settings.updated') ->where('tenant_id', $tenant->id) ->latest('id') ->first(); expect($row)->not->toBeNull() ->and($row->entity_type)->toBe('webhook_settings') ->and((int) $row->user_id)->toBe($user->id); $after = json_decode($row->payload_after, true); expect($after['target_url'] ?? null)->toBe($newUrl); expect($row->payload_before)->toBeNull(); }); it('audit log does not contain webhook secret', function () { $tenant = Tenant::factory()->create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $this->actingAs($user); DB::statement('SET app.current_tenant_id = '.$tenant->id); $r = $this->putJson('/api/tenants/me/webhook-settings', [ 'target_url' => 'https://93.184.216.34/hook', ]); $r->assertStatus(200); $row = DB::table('tenant_operations_log') ->where('event', 'webhook_settings.updated') ->where('tenant_id', $tenant->id) ->latest('id') ->first(); expect($row)->not->toBeNull(); // Neither payload should contain secret_hash or the plaintext secret (whsec_...) $payloadAfterRaw = $row->payload_after ?? ''; expect($payloadAfterRaw)->not->toContain('secret_hash') ->and($payloadAfterRaw)->not->toContain('whsec_'); $payloadBeforeRaw = $row->payload_before ?? ''; expect($payloadBeforeRaw)->not->toContain('secret_hash') ->and($payloadBeforeRaw)->not->toContain('whsec_'); });