192 lines
7.8 KiB
PHP
192 lines
7.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\Operations\TenantlessOperationRunViewer;
|
|
use App\Models\AuditLog;
|
|
use App\Models\EvidenceSnapshot;
|
|
use App\Models\Finding;
|
|
use App\Models\OperationRun;
|
|
use App\Models\ProviderConnection;
|
|
use App\Models\ReviewPack;
|
|
use App\Models\StoredReport;
|
|
use App\Models\Tenant;
|
|
use App\Models\TenantReview;
|
|
use App\Models\User;
|
|
use App\Models\Workspace;
|
|
use App\Models\WorkspaceMembership;
|
|
use App\Support\OperationRunLinks;
|
|
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\Actions\Action;
|
|
use Filament\Facades\Filament;
|
|
use Livewire\Livewire;
|
|
|
|
function operationSupportDiagnosticsComponent(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]);
|
|
}
|
|
|
|
it('opens a redacted support diagnostic bundle from the tenantless operation viewer', function (): void {
|
|
$tenant = Tenant::factory()->create(['name' => 'Contoso Support Tenant']);
|
|
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'operator');
|
|
|
|
$connection = ProviderConnection::factory()
|
|
->withCredential()
|
|
->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'display_name' => 'Contoso Microsoft 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',
|
|
],
|
|
'failure_summary' => [[
|
|
'message' => 'Run failed after provider validation.',
|
|
]],
|
|
'completed_at' => now()->subMinutes(10),
|
|
]);
|
|
|
|
$finding = Finding::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'current_operation_run_id' => (int) $run->getKey(),
|
|
'severity' => Finding::SEVERITY_HIGH,
|
|
'last_seen_at' => now()->subMinutes(8),
|
|
]);
|
|
|
|
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',
|
|
],
|
|
'fingerprint' => 'permission-fingerprint',
|
|
]);
|
|
|
|
$evidenceSnapshot = EvidenceSnapshot::query()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'initiated_by_user_id' => (int) $user->getKey(),
|
|
'fingerprint' => fake()->sha256(),
|
|
'status' => 'active',
|
|
'completeness_state' => 'complete',
|
|
'summary' => [
|
|
'dimension_count' => 1,
|
|
'missing_dimensions' => 0,
|
|
'stale_dimensions' => 0,
|
|
],
|
|
'generated_at' => now()->subMinutes(7),
|
|
]);
|
|
|
|
$review = TenantReview::factory()->ready()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'evidence_snapshot_id' => (int) $evidenceSnapshot->getKey(),
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'generated_at' => now()->subMinutes(7),
|
|
]);
|
|
|
|
$pack = ReviewPack::factory()->ready()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'tenant_review_id' => (int) $review->getKey(),
|
|
'operation_run_id' => (int) $run->getKey(),
|
|
'generated_at' => now()->subMinutes(6),
|
|
]);
|
|
|
|
$review->forceFill(['current_export_review_pack_id' => (int) $pack->getKey()])->save();
|
|
|
|
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',
|
|
'reason_code' => 'provider_permission_missing',
|
|
],
|
|
'outcome' => 'success',
|
|
'recorded_at' => now()->subMinutes(5),
|
|
]);
|
|
|
|
operationSupportDiagnosticsComponent($user, $run)
|
|
->assertActionVisible('openSupportDiagnostics')
|
|
->assertActionEnabled('openSupportDiagnostics')
|
|
->assertActionExists('openSupportDiagnostics', fn (Action $action): bool => $action->getLabel() === 'Open support diagnostics')
|
|
->assertActionHasIcon('openSupportDiagnostics', 'heroicon-o-lifebuoy')
|
|
->mountAction('openSupportDiagnostics')
|
|
->assertMountedActionModalSee('Support diagnostics')
|
|
->assertMountedActionModalSee(OperationRunLinks::identifier($run))
|
|
->assertMountedActionModalSee('The compare finished, but no decision-grade result is available yet.')
|
|
->assertMountedActionModalSee('Contoso Microsoft connection')
|
|
->assertMountedActionModalSee('High finding #'.$finding->getKey())
|
|
->assertMountedActionModalSee('permission posture report')
|
|
->assertMountedActionModalSee('Tenant review #'.$review->getKey())
|
|
->assertMountedActionModalSee('Review pack #'.$pack->getKey())
|
|
->assertMountedActionModalSee('Operation failed')
|
|
->assertMountedActionModalSee('default-redacted')
|
|
->assertMountedActionModalSee('[REDACTED]')
|
|
->assertMountedActionModalDontSee('raw-provider-secret-message')
|
|
->assertMountedActionModalDontSee('secret-provider-body')
|
|
->assertMountedActionModalDontSee('stored-report-secret-body')
|
|
->assertMountedActionModalDontSee('audit-secret-body');
|
|
});
|
|
|
|
it('keeps tenantless operation detail deny-as-not-found for workspace members without tenant entitlement', function (): void {
|
|
$workspace = Workspace::factory()->create();
|
|
$tenant = Tenant::factory()->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
]);
|
|
|
|
$user = User::factory()->create();
|
|
|
|
WorkspaceMembership::factory()->create([
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'user_id' => (int) $user->getKey(),
|
|
'role' => 'owner',
|
|
]);
|
|
|
|
$run = OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $workspace->getKey(),
|
|
'type' => OperationRunType::BaselineCompare->value,
|
|
'status' => OperationRunStatus::Completed->value,
|
|
'outcome' => OperationRunOutcome::Succeeded->value,
|
|
'completed_at' => now(),
|
|
]);
|
|
|
|
$this->actingAs($user)
|
|
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
|
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
|
->assertNotFound();
|
|
}); |