hash('sha256', 'scope-detail'), 'status' => 'success', 'finished_at' => now()->subDays(2), ]); $current = createInventorySyncOperationRun($tenant, [ 'selection_hash' => $baseline->selection_hash, 'status' => 'success', 'finished_at' => now()->subDay(), ]); $finding = Finding::factory()->for($tenant)->create([ 'finding_type' => Finding::FINDING_TYPE_DRIFT, 'scope_key' => (string) $current->selection_hash, 'baseline_operation_run_id' => $baseline->getKey(), 'current_operation_run_id' => $current->getKey(), 'subject_type' => 'deviceConfiguration', 'subject_external_id' => 'policy-123', 'evidence_jsonb' => [ 'change_type' => 'modified', 'summary' => ['changed_fields' => ['assignments_hash']], ], ]); $inventoryItem = InventoryItem::factory()->for($tenant)->create([ 'external_id' => $finding->subject_external_id, 'display_name' => 'My Policy 123', ]); $this->actingAs($user) ->get(FindingResource::getUrl('view', ['record' => $finding], tenant: $tenant)) ->assertOk() ->assertSee($finding->fingerprint) ->assertSee($inventoryItem->display_name); }); test('finding detail explains protected changes without exposing hidden values', function () { bindFailHardGraphClient(); [$user, $tenant] = createUserWithTenant(role: 'manager'); $policy = Policy::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'external_id' => 'policy-redaction-note', 'policy_type' => 'settingsCatalogPolicy', 'display_name' => 'Policy redaction note', 'platform' => 'windows', ]); $baseline = PolicyVersion::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'policy_id' => (int) $policy->getKey(), 'version_number' => 1, 'policy_type' => 'settingsCatalogPolicy', 'platform' => 'windows', 'created_by' => 'spec120@example.com', 'captured_at' => now()->subMinute(), 'snapshot' => [ 'passwordMinimumLength' => 14, ], 'assignments' => [], 'scope_tags' => [], 'metadata' => ['source' => 'spec120_capture'], 'redaction_version' => 1, 'secret_fingerprints' => [ 'snapshot' => [], 'assignments' => [], 'scope_tags' => [], ], ]); $protectedCurrent = PolicyVersion::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'policy_id' => (int) $policy->getKey(), 'version_number' => 2, 'policy_type' => 'settingsCatalogPolicy', 'platform' => 'windows', 'created_by' => 'spec120@example.com', 'captured_at' => now(), 'snapshot' => [ 'passwordMinimumLength' => 14, 'clientSecret' => '[REDACTED]', ], 'assignments' => [], 'scope_tags' => [], 'metadata' => ['source' => 'spec120_capture'], 'redaction_version' => 1, 'secret_fingerprints' => [ 'snapshot' => ['/clientSecret' => 'abc123'], 'assignments' => [], 'scope_tags' => [], ], ]); $finding = Finding::factory()->for($tenant)->create([ 'finding_type' => Finding::FINDING_TYPE_DRIFT, 'subject_type' => 'deviceConfiguration', 'subject_external_id' => 'policy-redaction-note', 'evidence_jsonb' => [ 'change_type' => 'modified', 'summary' => ['kind' => 'policy_snapshot'], 'baseline' => [ 'policy_version_id' => (int) $baseline->getKey(), 'redaction_version' => 1, 'secret_fingerprints' => [ 'snapshot' => [], 'assignments' => [], 'scope_tags' => [], ], ], 'current' => [ 'policy_version_id' => (int) $protectedCurrent->getKey(), 'redaction_version' => 1, 'secret_fingerprints' => $protectedCurrent->secret_fingerprints, ], ], ]); InventoryItem::factory()->for($tenant)->create([ 'external_id' => $finding->subject_external_id, 'display_name' => 'Policy redaction note', ]); $this->actingAs($user) ->get(FindingResource::getUrl('view', ['record' => $finding], tenant: $tenant)) ->assertOk() ->assertSee('Protected values are intentionally hidden as [REDACTED]. Secret-only changes remain detectable without revealing the value.'); });