66 lines
2.5 KiB
PHP
66 lines
2.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use App\Services\Audit\OperationsLogger;
|
|
use Illuminate\Database\QueryException;
|
|
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class, DatabaseTransactions::class);
|
|
|
|
it('writes tenant_operations_log row with all fields', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$user = User::factory()->for($tenant)->create();
|
|
|
|
app(OperationsLogger::class)->record(
|
|
tenantId: $tenant->id,
|
|
userId: $user->id,
|
|
entityType: 'project',
|
|
entityId: 42,
|
|
event: 'project.created',
|
|
payloadBefore: null,
|
|
payloadAfter: ['name' => 'X', 'limit' => 10],
|
|
ip: '1.2.3.4',
|
|
userAgent: 'UA',
|
|
);
|
|
|
|
$row = DB::table('tenant_operations_log')->latest('id')->first();
|
|
expect($row->event)->toBe('project.created')
|
|
->and($row->entity_type)->toBe('project')
|
|
->and((int) $row->entity_id)->toBe(42)
|
|
->and((int) $row->user_id)->toBe($user->id)
|
|
->and((int) $row->tenant_id)->toBe($tenant->id)
|
|
->and((string) $row->ip_address)->toBe('1.2.3.4')
|
|
->and(json_decode($row->payload_after, true))->toBe(['name' => 'X', 'limit' => 10])
|
|
->and($row->payload_before)->toBeNull();
|
|
});
|
|
|
|
it('allows system actor (user_id NULL) for system operations', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
$before = DB::table('tenant_operations_log')->where('tenant_id', $tenant->id)->count();
|
|
|
|
app(OperationsLogger::class)->record(
|
|
tenantId: $tenant->id, userId: null,
|
|
entityType: 'webhook_settings', entityId: null,
|
|
event: 'webhook_settings.system_purge',
|
|
payloadBefore: null, payloadAfter: null, ip: null, userAgent: null,
|
|
);
|
|
expect(DB::table('tenant_operations_log')->where('tenant_id', $tenant->id)->count())->toBe($before + 1);
|
|
});
|
|
|
|
it('append-only: UPDATE blocked by audit_block_mutation', function () {
|
|
$tenant = Tenant::factory()->create();
|
|
app(OperationsLogger::class)->record(
|
|
tenantId: $tenant->id, userId: null, entityType: 'project', entityId: 1,
|
|
event: 'project.created', payloadBefore: null, payloadAfter: ['x' => 1],
|
|
ip: null, userAgent: null,
|
|
);
|
|
$id = (int) DB::table('tenant_operations_log')->latest('id')->value('id');
|
|
expect(fn () => DB::table('tenant_operations_log')->where('id', $id)->update(['event' => 'x']))
|
|
->toThrow(QueryException::class);
|
|
});
|