Use policy-aware resource search labels

This commit is contained in:
rcourtman
2026-03-19 17:38:50 +00:00
parent a682e9dfd7
commit 92a6de3fbc
5 changed files with 41 additions and 2 deletions
@@ -124,6 +124,10 @@ alternate name when policy requires governed handling. That keeps the
policy-aware label path inside the same hot-row rendering budget instead of
adding a second display branch for redacted fleets, and the proof for that
behavior lives in `UnifiedResourceTable.performance.contract.test.tsx`.
The shared infrastructure selector search path now also routes through that
same policy-aware display contract, so governed resources do not reappear via
raw-name search candidates while the selector stays on the same hot-path
budget.
The aggregate `/api/charts/workloads-summary` endpoint now also has its own
explicit API p95 budget constant, aligned with the per-workload charts budget,
and `internal/api/slo_bench_test.go` must fail if that aggregate budget or its
@@ -382,6 +382,10 @@ that drawer now route
through the canonical infrastructure resource filter, so the resource history
remains navigable from the history surface instead of being purely
descriptive text.
The same infrastructure selector pipeline now also uses the policy-aware
display contract for search candidates, so governed resources do not reappear
through raw-name search forks even though the selector stays on the same
hot-path budget.
`ResourceFacetSummary` now consumes the shared
`frontend-modern/src/utils/resourceChangePresentation.ts` label helper for
canonical change kinds, source types, and adapter provenance, so the chip
@@ -8,6 +8,7 @@ import { getPreferredResourceDisplayName } from '@/utils/resourceIdentity';
import {
buildStatusOptions,
filterResources,
matchesSearch,
sortResources,
groupResources,
splitPrimaryAndServiceResources,
@@ -179,6 +180,21 @@ describe('UnifiedResourceTable performance contract', () => {
expect(filtered[0]?.platformData?.sources).toEqual(['proxmox']);
});
it('keeps governed resource search aligned with the safe display label', () => {
const governedResource = makeResource(9, {
name: 'secret-host-9',
displayName: 'secret-host-9',
policy: {
sensitivity: 'restricted',
routing: { scope: 'local-only', redact: ['hostname'] },
},
aiSafeSummary: 'Production Host',
});
expect(matchesSearch(governedResource, 'Production')).toBe(true);
expect(matchesSearch(governedResource, 'secret-host-9')).toBe(false);
});
it('renders facet summary badges without changing the Profile S row budget', async () => {
const resources = makeResources(PROFILES.S, (i) =>
i === 0
@@ -58,6 +58,21 @@ describe('infrastructureSelectors', () => {
expect(matchesSearch(resource, 'NODE-123')).toBe(true);
});
it('matches governed resources by their safe label instead of raw name', () => {
const governedResource = makeResource(2, {
name: 'secret-node-2',
displayName: 'secret-node-2',
policy: {
sensitivity: 'restricted',
routing: { scope: 'local-only', redact: ['hostname'] },
},
aiSafeSummary: 'Production Node',
});
expect(matchesSearch(governedResource, 'Production')).toBe(true);
expect(matchesSearch(governedResource, 'secret-node-2')).toBe(false);
});
it('matches by ip and tag and returns false when missing', () => {
expect(matchesSearch(resource, '192.168.1.10')).toBe(true);
expect(matchesSearch(resource, 'database')).toBe(true);
@@ -132,6 +147,7 @@ describe('infrastructureSelectors', () => {
}),
makeResource(3, {
name: 'gamma-node',
displayName: 'Gamma Node',
status: 'degraded',
tags: ['prod', 'db'],
platformData: { sources: ['k8s'] },
@@ -130,8 +130,7 @@ export const matchesSearch = (resource: Resource, term: string): boolean => {
if (!term) return true;
const normalizedTerm = term.toLowerCase();
const candidates: string[] = [
resource.name,
resource.displayName,
getDisplayName(resource),
resource.id,
resource.identity?.hostname ?? '',
...(resource.identity?.ips ?? []),