79 lines
5.3 KiB
PHP
79 lines
5.3 KiB
PHP
<?php
|
|
|
|
use App\Services\OrganizationAccess;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Inertia\Testing\AssertableInertia as Assert;
|
|
|
|
require_once __DIR__.'/../Support/ReceiptFixture.php';
|
|
require_once __DIR__.'/../Support/SupplyFixture.php';
|
|
|
|
beforeEach(function () {
|
|
$this->withoutVite();
|
|
$this->f = receiptFixture();
|
|
supplyGrant($this->f['receiver'], ['audit_metadata_read']);
|
|
$this->actingAs($this->f['receiver']);
|
|
$this->ids = [];
|
|
foreach (range(1, 30) as $index) {
|
|
$this->ids[] = DB::table('audit_logs')->insertGetId(['tenant_id' => $this->f['tenant']->id, 'user_id' => $this->f['receiver']->id,
|
|
'action' => $index % 3 === 0 ? 'people.selected' : 'receipt.confirmed', 'created_at' => '2026-11-01 12:00:00',
|
|
'before' => json_encode(['bank' => 'PRIVATE-BEFORE']), 'after' => json_encode(['secret' => 'PRIVATE-AFTER'])]);
|
|
}
|
|
});
|
|
|
|
test('audit metadata block paginates oldest events and exposes only the four allowed metadata fields', function () {
|
|
$before = DB::table('audit_logs')->orderBy('id')->get()->toArray();
|
|
$this->get('/auditoria/eventos')->assertOk()->assertHeader('Cache-Control', 'max-age=0, no-store, private')
|
|
->assertDontSee('PRIVATE-BEFORE')->assertDontSee('PRIVATE-AFTER')
|
|
->assertInertia(fn (Assert $p) => $p->component('audit/metadata')->where('events.total', 30)->has('events.data', 25)
|
|
->where('events.data.0.id', $this->ids[0])->where('events.data.24.id', $this->ids[24])
|
|
->missing('events.data.0.before')->missing('events.data.0.after')->missing('events.data.0.tenant_id'));
|
|
$this->get('/auditoria/eventos?page=2')->assertOk()->assertInertia(fn (Assert $p) => $p->has('events.data', 5)->where('events.data.0.id', $this->ids[25]));
|
|
expect(DB::table('audit_logs')->orderBy('id')->get()->toArray())->toEqual($before);
|
|
});
|
|
|
|
test('audit metadata block exports the complete filtered scope independently of the screen page and protects spreadsheet cells', function () {
|
|
$query = '?action=people.selected&actor_id='.$this->f['receiver']->id.'&from=2026-11-01&to=2026-11-01';
|
|
$this->get('/auditoria/eventos'.$query)->assertOk()->assertInertia(fn (Assert $p) => $p->where('events.total', 10));
|
|
$csv = $this->get('/auditoria/eventos.csv'.$query.'&page=2')->assertOk()->streamedContent();
|
|
expect(substr_count($csv, 'people.selected'))->toBe(10)->and($csv)->not->toContain('receipt.confirmed', 'PRIVATE-BEFORE', 'PRIVATE-AFTER');
|
|
$this->get('/auditoria/eventos?to=2026-11-01')->assertOk();
|
|
$this->getJson('/auditoria/eventos?from=2026-11-02&to=2026-11-01')->assertUnprocessable();
|
|
DB::table('audit_logs')->insert(['tenant_id' => $this->f['tenant']->id, 'user_id' => $this->f['receiver']->id, 'action' => '=1+1', 'created_at' => now(), 'after' => '{}']);
|
|
$formula = $this->get('/auditoria/eventos.csv?action='.urlencode('=1+1'))->assertOk()->streamedContent();
|
|
expect($formula)->toContain("'=1+1");
|
|
$all = $this->get('/auditoria/eventos.csv')->assertOk()->streamedContent();
|
|
expect(substr_count($all, 'receipt.confirmed'))->toBe(20)->and(substr_count($all, 'people.selected'))->toBe(10);
|
|
});
|
|
|
|
test('audit metadata block requires an explicit current nonmaintenance grant even for administrators', function (string $mode) {
|
|
if ($mode === 'administrator') {
|
|
supplyGrant($this->f['issuer'], ['admin']);
|
|
$this->actingAs($this->f['issuer']);
|
|
} elseif ($mode === 'expired') {
|
|
DB::table('organization_memberships')->where('user_id', $this->f['receiver']->id)->update(['expires_at' => now()->subMinute()]);
|
|
} elseif ($mode === 'maintenance') {
|
|
DB::table('organization_memberships')->where('user_id', $this->f['receiver']->id)->update(['maintenance' => true]);
|
|
} else {
|
|
DB::table('organization_profiles')->where('tenant_id', $this->f['tenant']->id)->update(['permissions' => '[]']);
|
|
}
|
|
$this->get('/auditoria/eventos')->assertForbidden();
|
|
$this->get('/auditoria/eventos.csv')->assertForbidden();
|
|
})->with(['administrator', 'expired', 'maintenance', 'revoked']);
|
|
|
|
test('audit metadata block isolates companies and adds no grants or audit events during consultation', function () {
|
|
$foreign = receiptFixture();
|
|
supplyGrant($foreign['receiver'], ['audit_metadata_read']);
|
|
DB::table('audit_logs')->insert(['tenant_id' => $foreign['tenant']->id, 'user_id' => $foreign['receiver']->id, 'action' => 'FOREIGN-ONLY', 'created_at' => now(), 'after' => '{}']);
|
|
$before = [];
|
|
foreach (['audit_logs', 'users', 'organization_profiles', 'organization_memberships', 'approval_steps', 'stock_movements'] as $table) {
|
|
$before[$table] = DB::table($table)->orderBy('id')->get()->toArray();
|
|
}
|
|
$this->actingAs($this->f['receiver'])->get('/auditoria/eventos')->assertOk()->assertDontSee('FOREIGN-ONLY');
|
|
$this->actingAs($foreign['receiver'])->get('/auditoria/eventos')->assertOk()->assertInertia(fn (Assert $p) => $p->where('events.total', 1)->where('events.data.0.action', 'FOREIGN-ONLY'));
|
|
expect($this->get('/auditoria/eventos.csv')->assertOk()->streamedContent())->toContain('FOREIGN-ONLY')->not->toContain('people.selected');
|
|
foreach ($before as $table => $rows) {
|
|
expect(DB::table($table)->orderBy('id')->get()->toArray())->toEqual($rows);
|
|
}
|
|
expect(array_key_exists('audit_metadata_read', OrganizationAccess::PERMISSIONS))->toBeTrue();
|
|
});
|