set('tenantpilot.baselines.full_content_capture.enabled', true); config()->set('tenantpilot.baselines.full_content_capture.max_items_per_run', 50); config()->set('tenantpilot.baselines.full_content_capture.max_concurrency', 1); config()->set('tenantpilot.baselines.full_content_capture.max_retries', 0); [$user, $tenant] = createUserWithTenant(role: 'owner'); $profile = BaselineProfile::factory()->active()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'capture_mode' => BaselineCaptureMode::FullContent->value, 'scope_jsonb' => [ 'policy_types' => ['deviceConfiguration'], 'foundation_types' => ['roleScopeTag'], ], ]); $snapshot = BaselineSnapshot::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'baseline_profile_id' => (int) $profile->getKey(), 'captured_at' => now()->subMinute(), ]); $profile->update(['active_snapshot_id' => (int) $snapshot->getKey()]); $policySubjectKey = BaselineSubjectKey::fromDisplayName('Deterministic Missing Policy'); $foundationSubjectKey = BaselineSubjectKey::fromDisplayName('Deterministic Foundation'); BaselineSnapshotItem::factory()->create([ 'baseline_snapshot_id' => (int) $snapshot->getKey(), 'subject_type' => 'policy', 'subject_external_id' => BaselineSubjectKey::workspaceSafeSubjectExternalId('deviceConfiguration', (string) $policySubjectKey), 'subject_key' => (string) $policySubjectKey, 'policy_type' => 'deviceConfiguration', 'baseline_hash' => hash('sha256', 'deterministic-policy'), 'meta_jsonb' => ['display_name' => 'Deterministic Missing Policy'], ]); BaselineSnapshotItem::factory()->create([ 'baseline_snapshot_id' => (int) $snapshot->getKey(), 'subject_type' => 'policy', 'subject_external_id' => BaselineSubjectKey::workspaceSafeSubjectExternalId('roleScopeTag', (string) $foundationSubjectKey), 'subject_key' => (string) $foundationSubjectKey, 'policy_type' => 'roleScopeTag', 'baseline_hash' => hash('sha256', 'deterministic-foundation'), 'meta_jsonb' => ['display_name' => 'Deterministic Foundation'], ]); $inventorySyncRun = createInventorySyncOperationRunWithCoverage( tenant: $tenant, statusByType: [ 'deviceConfiguration' => 'succeeded', 'roleScopeTag' => 'succeeded', ], foundationTypes: ['roleScopeTag'], ); InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'external_id' => 'deterministic-policy', 'policy_type' => 'deviceConfiguration', 'display_name' => 'Deterministic Missing Policy', 'meta_jsonb' => ['odata_type' => '#microsoft.graph.deviceConfiguration', 'etag' => 'etag-deterministic-policy'], 'last_seen_operation_run_id' => (int) $inventorySyncRun->getKey(), 'last_seen_at' => now(), ]); InventoryItem::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'external_id' => 'deterministic-foundation', 'policy_type' => 'roleScopeTag', 'display_name' => 'Deterministic Foundation', 'meta_jsonb' => ['odata_type' => '#microsoft.graph.roleScopeTag', 'etag' => 'etag-deterministic-foundation'], 'last_seen_operation_run_id' => (int) $inventorySyncRun->getKey(), 'last_seen_at' => now(), ]); $captureRunA = OperationRun::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'type' => OperationRunType::BaselineCapture->value, 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => [ 'baseline_profile_id' => (int) $profile->getKey(), 'source_tenant_id' => (int) $tenant->getKey(), 'effective_scope' => [ 'policy_types' => ['deviceConfiguration'], 'foundation_types' => ['roleScopeTag'], 'truthful_types' => ['deviceConfiguration', 'roleScopeTag'], ], 'capture_mode' => BaselineCaptureMode::FullContent->value, ], 'user_id' => (int) $user->getKey(), ]); $captureRunB = OperationRun::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'type' => OperationRunType::BaselineCapture->value, 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => $captureRunA->context, 'user_id' => (int) $user->getKey(), ]); (new CaptureBaselineSnapshotJob($captureRunA))->handle( app(BaselineSnapshotIdentity::class), app(InventoryMetaContract::class), app(AuditLogger::class), app(OperationRunService::class), ); (new CaptureBaselineSnapshotJob($captureRunB))->handle( app(BaselineSnapshotIdentity::class), app(InventoryMetaContract::class), app(AuditLogger::class), app(OperationRunService::class), ); $compareRunA = OperationRun::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'type' => OperationRunType::BaselineCompare->value, 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => [ 'baseline_profile_id' => (int) $profile->getKey(), 'baseline_snapshot_id' => (int) $snapshot->getKey(), 'effective_scope' => [ 'policy_types' => ['deviceConfiguration'], 'foundation_types' => ['roleScopeTag'], 'truthful_types' => ['deviceConfiguration', 'roleScopeTag'], ], 'capture_mode' => BaselineCaptureMode::FullContent->value, ], 'user_id' => (int) $user->getKey(), ]); $compareRunB = OperationRun::factory()->create([ 'workspace_id' => (int) $tenant->workspace_id, 'tenant_id' => (int) $tenant->getKey(), 'type' => OperationRunType::BaselineCompare->value, 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, 'context' => $compareRunA->context, 'user_id' => (int) $user->getKey(), ]); (new CompareBaselineToTenantJob($compareRunA))->handle( app(BaselineSnapshotIdentity::class), app(AuditLogger::class), app(OperationRunService::class), ); (new CompareBaselineToTenantJob($compareRunB))->handle( app(BaselineSnapshotIdentity::class), app(AuditLogger::class), app(OperationRunService::class), ); $captureSubjectsA = collect(data_get($captureRunA->fresh()->context, 'baseline_capture.gaps.subjects', []))->sortBy('policy_type')->values()->all(); $captureSubjectsB = collect(data_get($captureRunB->fresh()->context, 'baseline_capture.gaps.subjects', []))->sortBy('policy_type')->values()->all(); $compareSubjectsA = collect(data_get($compareRunA->fresh()->context, 'baseline_compare.evidence_gaps.subjects', []))->sortBy('policy_type')->values()->all(); $compareSubjectsB = collect(data_get($compareRunB->fresh()->context, 'baseline_compare.evidence_gaps.subjects', []))->sortBy('policy_type')->values()->all(); expect($captureSubjectsA)->toBe($captureSubjectsB) ->and($compareSubjectsA)->toBe($compareSubjectsB); });