TenantAtlas/apps/platform/tests/Feature/SupportDiagnostics/SupportDiagnosticAuditTest.php
Ahmed Darrazi 45e6142a67
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m0s
feat(support-diagnostics): guardrail refactor and UI polish (agent)
2026-04-26 01:30:28 +02:00

186 lines
7.7 KiB
PHP

<?php
declare(strict_types=1);
use App\Filament\Pages\Operations\TenantlessOperationRunViewer;
use App\Filament\Pages\TenantDashboard;
use App\Models\AuditLog;
use App\Models\OperationRun;
use App\Models\ProviderConnection;
use App\Models\StoredReport;
use App\Models\Tenant;
use App\Models\User;
use App\Support\Audit\AuditActionId;
use App\Support\OperationRunOutcome;
use App\Support\OperationRunStatus;
use App\Support\OperationRunType;
use App\Support\Providers\ProviderReasonCodes;
use App\Support\Providers\ProviderVerificationStatus;
use App\Support\Workspaces\WorkspaceContext;
use Filament\Facades\Filament;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Queue;
use Livewire\Livewire;
function supportDiagnosticsTenantAuditComponent(User $user, Tenant $tenant): \Livewire\Features\SupportTesting\Testable
{
test()->actingAs($user);
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
setTenantPanelContext($tenant);
return Livewire::actingAs($user)->test(TenantDashboard::class);
}
function supportDiagnosticsOperationAuditComponent(User $user, OperationRun $run): \Livewire\Features\SupportTesting\Testable
{
test()->actingAs($user);
Filament::setTenant(null, true);
session()->put(WorkspaceContext::SESSION_KEY, (int) $run->workspace_id);
return Livewire::actingAs($user)->test(TenantlessOperationRunViewer::class, ['run' => $run]);
}
function seedSupportDiagnosticsAuditFixture(string $role = 'owner'): array
{
$tenant = Tenant::factory()->create(['name' => 'Audit Tenant']);
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: $role);
$connection = ProviderConnection::factory()
->withCredential()
->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'display_name' => 'Audit connection',
'verification_status' => ProviderVerificationStatus::Blocked->value,
'last_error_reason_code' => ProviderReasonCodes::ProviderPermissionMissing,
'last_error_message' => 'raw-provider-secret-message',
'last_health_check_at' => now()->subMinutes(15),
]);
$run = OperationRun::factory()
->forTenant($tenant)
->create([
'type' => OperationRunType::BaselineCompare->value,
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Failed->value,
'summary_counts' => [
'total' => 0,
'processed' => 0,
],
'context' => [
'provider_connection_id' => (int) $connection->getKey(),
'raw_response_body' => 'secret-provider-body',
],
'completed_at' => now()->subMinutes(10),
]);
StoredReport::factory()->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'report_type' => StoredReport::REPORT_TYPE_PERMISSION_POSTURE,
'payload' => [
'raw_response_body' => 'stored-report-secret-body',
],
]);
AuditLog::query()->create([
'workspace_id' => (int) $tenant->workspace_id,
'tenant_id' => (int) $tenant->getKey(),
'operation_run_id' => (int) $run->getKey(),
'action' => 'operation.failed',
'resource_type' => 'operation_run',
'resource_id' => (string) $run->getKey(),
'target_label' => 'Operation #'.$run->getKey(),
'metadata' => [
'raw_response_body' => 'audit-secret-body',
],
'outcome' => 'success',
'recorded_at' => now()->subMinutes(5),
]);
return [$user, $tenant, $run];
}
it('audits tenant support diagnostics opens with redacted metadata and no side effects', function (): void {
[$user, $tenant] = seedSupportDiagnosticsAuditFixture();
bindFailHardGraphClient();
Bus::fake();
Queue::fake();
$operationRunCount = OperationRun::query()->count();
assertNoOutboundHttp(function () use ($user, $tenant): void {
supportDiagnosticsTenantAuditComponent($user, $tenant)
->mountAction('openSupportDiagnostics')
->assertMountedActionModalSee('Support diagnostics');
});
Bus::assertNothingDispatched();
Queue::assertNothingPushed();
$audit = AuditLog::query()
->where('action', AuditActionId::SupportDiagnosticsOpened->value)
->latest('id')
->firstOrFail();
$metadataJson = json_encode($audit->metadata, JSON_THROW_ON_ERROR);
expect(OperationRun::query()->count())->toBe($operationRunCount)
->and(AuditLog::query()->where('action', AuditActionId::SupportDiagnosticsOpened->value)->count())->toBe(1)
->and(AuditLog::query()->where('action', AuditActionId::BaselineCompareStarted->value)->count())->toBe(0)
->and($audit->resource_type)->toBe('support_diagnostic_bundle')
->and($audit->resource_id)->toBe('tenant:'.$tenant->getKey())
->and($audit->operation_run_id)->toBeNull()
->and($audit->metadata['context_type'] ?? null)->toBe('tenant')
->and($audit->metadata['redaction_mode'] ?? null)->toBe('default_redacted')
->and($audit->metadata['section_count'] ?? null)->toBe(8)
->and($audit->metadata['reference_count'] ?? null)->toBeGreaterThan(0)
->and($audit->metadata['primary_context_id'] ?? null)->toBe((string) $tenant->getKey())
->and($metadataJson)->not->toContain('raw-provider-secret-message')
->and($metadataJson)->not->toContain('secret-provider-body')
->and($metadataJson)->not->toContain('stored-report-secret-body')
->and($metadataJson)->not->toContain('audit-secret-body');
});
it('audits operation support diagnostics opens with redacted metadata and no side effects', function (): void {
[$user, $tenant, $run] = seedSupportDiagnosticsAuditFixture();
bindFailHardGraphClient();
Bus::fake();
Queue::fake();
$operationRunCount = OperationRun::query()->count();
assertNoOutboundHttp(function () use ($user, $run): void {
supportDiagnosticsOperationAuditComponent($user, $run)
->mountAction('openSupportDiagnostics')
->assertMountedActionModalSee('Support diagnostics');
});
Bus::assertNothingDispatched();
Queue::assertNothingPushed();
$audit = AuditLog::query()
->where('action', AuditActionId::SupportDiagnosticsOpened->value)
->latest('id')
->firstOrFail();
$metadataJson = json_encode($audit->metadata, JSON_THROW_ON_ERROR);
expect(OperationRun::query()->count())->toBe($operationRunCount)
->and(AuditLog::query()->where('action', AuditActionId::SupportDiagnosticsOpened->value)->count())->toBe(1)
->and(AuditLog::query()->where('action', AuditActionId::BaselineCompareStarted->value)->count())->toBe(0)
->and($audit->resource_type)->toBe('support_diagnostic_bundle')
->and($audit->resource_id)->toBe('operation_run:'.$run->getKey())
->and($audit->operation_run_id)->toBe((int) $run->getKey())
->and($audit->metadata['context_type'] ?? null)->toBe('operation_run')
->and($audit->metadata['redaction_mode'] ?? null)->toBe('default_redacted')
->and($audit->metadata['section_count'] ?? null)->toBe(8)
->and($audit->metadata['reference_count'] ?? null)->toBeGreaterThan(0)
->and($audit->metadata['primary_context_id'] ?? null)->toBe((string) $run->getKey())
->and($metadataJson)->not->toContain('raw-provider-secret-message')
->and($metadataJson)->not->toContain('secret-provider-body')
->and($metadataJson)->not->toContain('stored-report-secret-body')
->and($metadataJson)->not->toContain('audit-secret-body');
});