Skip to content

Show EndpointSlice inventories for selected Services - #1997

Open
nadaverell wants to merge 6 commits into
mainfrom
feature/relationship-service-slices
Open

nadaverell wants to merge 6 commits into
mainfrom
feature/relationship-service-slices

Conversation

@nadaverell

@nadaverell nadaverell commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

A selector-backed Service can have manually managed EndpointSlices that its drawer never shows. Load namespace EndpointSlice inventory for every non-ExternalName Service, then let the shared UI associate it with the selected Service. The standard service-name label wins over a conflicting owner declaration; an unlabeled slice requires an exact core Service owner name and observed UID.

The expanded section distinguishes owner-only evidence and retains address counts and readiness. Loading, failed inventory and genuinely empty inventory have separate states. ExternalName Services do not request or show EndpointSlices. An EndpointSlice's label still navigates to its published Service; an owner-only declaration shows its name and UID as text because that drawer cannot verify the live owner incarnation.

Association semantics stay inside k8s-ui. The host passes raw inventory plus the existing label-filtered set: the new shared package consumes the raw inventory, while the actual older pinned SDK retains its existing behavior. Additive options preserve that published component's type and runtime contract without adding a new runtime SDK import or publishing a package.

Scope: shared Service and EndpointSlice drawers, the local host loader and SDK consumers through normal package updates. No topology, resourceContext, Diagnose, traffic trace or monitoring change is claimed. A declared/manual association does not assert controller management or working traffic.

Validation: helper/renderer identity, conflicting-label precedence, replaced-owner UID, raw-inventory package-boundary, loading/error/empty and host-query tests pass. Type check, full frontend/embed/backend build, complete shared UI suite (4159 tests, one skipped) and complete server tests pass. The changed host also type-checks against Hub's actual pinned k8s-ui 1.16.1. Actual isolated-kind browser checks cover a selector-backed Service, label and owner-only slices, conflicting labels, owner text without a forward link, label navigation, selectorless Service and ExternalName omission. Zero page errors; two settled fixture captures were inspected. Prior-art Service to EndpointSlice joins supplied the baseline; Kubernetes label/owner identity rules supplied the stricter contract.

Selected Service label and verified owner slice evidence

Unverified owner declaration shown without forward navigation


Note

Medium Risk
Changes Service/EndpointSlice drawer data loading and association semantics (label vs owner UID), which affects what users see and navigate to; backward compatibility is preserved via additive props for pinned SDK consumers.

Overview
Service drawers now load and display namespace EndpointSlice inventory for every non-ExternalName Service, not only selectorless/manual-endpoint Services. Shared endpoint-slices helpers decide which slices belong to the selected Service: kubernetes.io/service-name wins over conflicting owner metadata; unlabeled slices match only on an unambiguous core Service owner with an exact observed UID (stale/replaced owners are excluded).

The EndpointSlices section gains distinct loading, permission/read-failure, and empty states; owner-only associations are labeled so they are not presented as published endpoints. EndpointSlice drawers use the same rules—label-backed services stay navigable; owner-only declarations show name and UID as plain text without a forward link.

The web host fetches raw namespace inventory, surfaces query errors, and passes additive props (endpointSliceInventory, endpointSlicesEnabled, endpointSlicesError) into the shared renderer while keeping the legacy label-filtered endpointSlices prop for older pinned SDK consumers. Tests cover association edge cases and both renderers; the lookup-error ratchet baseline drops the prior ServiceRenderer carve-out.

Reviewed by Cursor Bugbot for commit 0b35649. Bugbot is set up for automated code reviews on this repo. Configure here.

@nadaverell
nadaverell requested a review from hisco as a code owner October 7, 2026 04:34
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Show EndpointSlice inventories for selected Services

✨ Enhancement 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Show matching EndpointSlices for selected Services, including Services with Pod selectors.
• Distinguish published-label matches from ownership-only links and preserve inventory loading,
 error, and empty states.
• Test association precedence, navigation evidence, and ExternalName exclusion.
Diagram

graph TD
  S["Selected Service"] --> W["App wrapper"] --> I["Slice inventory"] --> A["Association helper"] --> D["Service drawer"] --> E["Slice drawer"]
  E --> A
Loading
High-Level Assessment

The existing namespace inventory plus a shared association helper fits the goal: selector-derived Pods cannot establish published slice membership, while a label-only query would miss unlabeled, ownership-linked slices. Keeping inventory fetching in the app wrapper also lets shared drawers remain independent of that capability.

Files changed (7) +156 / -11

Enhancement (4) +66 / -11
EndpointSliceRenderer.tsxShow evidence-aware Service links in EndpointSlice details +5/-4

Show evidence-aware Service links in EndpointSlice details

• Resolves the associated Service through the shared helper instead of reading only the service-name label. Labels ownership-only links as “Owner Service” and specifies the core API group for navigation.

packages/k8s-ui/src/components/resources/renderers/EndpointSliceRenderer.tsx

ServiceRenderer.tsxDisplay EndpointSlices for Services with selectors +9/-2

Display EndpointSlices for Services with selectors

• Shows the inventory section when the wrapper supplies that capability, without removing the existing selectorless behavior. Adds read-error messaging and marks unlabeled owner-linked slices as ownership evidence rather than published endpoints.

packages/k8s-ui/src/components/resources/renderers/ServiceRenderer.tsx

endpoint-slices.tsCentralize label-first EndpointSlice association +45/-0

Centralize label-first EndpointSlice association

• Adds pure helpers that resolve a Service from the standard label or an unambiguous exact core Service owner. Reverse matching also checks an observed Service UID before accepting an owner-only link.

packages/k8s-ui/src/utils/endpoint-slices.ts

ServiceRenderer.tsxQuery slices for every eligible selected Service +7/-5

Query slices for every eligible selected Service

• Removes the selectorless-only query restriction, filters results with the shared association helper, and passes inventory availability and errors to the shared drawer.

web/src/components/resources/renderers/ServiceRenderer.tsx

Tests (3) +90 / -0
ServiceRenderer.test.tsxTest selected-Service inventory presentation +29/-0

Test selected-Service inventory presentation

• Covers slice counts, unavailable/loading/empty states, ExternalName exclusion, and the ownership-only explanation.

packages/k8s-ui/src/components/resources/renderers/ServiceRenderer.test.tsx

endpoint-slices.test.tsTest exact Service–EndpointSlice associations +28/-0

Test exact Service–EndpointSlice associations

• Verifies label precedence, namespace and API-group checks, unambiguous core owners, and rejection of stale owner UIDs.

packages/k8s-ui/src/utils/endpoint-slices.test.ts

ServiceRenderer.test.tsxTest app-wrapper inventory queries and filtering +33/-0

Test app-wrapper inventory queries and filtering

• Checks selected-Service queries, label and owner matches, stale-owner rejection, read errors, and disabled queries for ExternalName Services.

web/src/components/resources/renderers/ServiceRenderer.test.tsx

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Hub builds fail after upgrade ✓ Resolved
Description
radar-app now imports endpointSliceMatchesService from k8s-ui, but its peer dependency still
permits versions that predate that new export. If Radar Hub Web upgrades radar-app while retaining
its locked k8s-ui 1.16.2, the new import cannot resolve and the Hub build fails.
Code

web/src/components/resources/renderers/ServiceRenderer.tsx[9]

+import { endpointSliceMatchesService } from '@skyhook-io/k8s-ui/utils/endpoint-slices'
Evidence
The added import requires a new k8s-ui module, while radar-app's unchanged peer range accepts Hub
Web's older locked version. Radar's publication workflow explicitly identifies newly imported
exports as requiring a peer-floor increase.

radar -> radar-hub-web
web/src/components/resources/renderers/ServiceRenderer.tsx[9-9]
packages/k8s-ui/src/utils/endpoint-slices.ts[40-45]
web/package.json[56-59]
.github/workflows/publish-radar-app.yml[3-10]
External repo: skyhook-dev/radar-hub-web, package.json [16-20]
External repo: skyhook-dev/radar-hub-web, package-lock.json [1420-1423]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new radar-app import requires a k8s-ui release containing `endpointSliceMatchesService`, but radar-app still declares compatibility with older releases used by Radar Hub Web.
## Fix Focus Areas
- web/src/components/resources/renderers/ServiceRenderer.tsx[9-9]
- web/package.json[56-59]
- /cross_repos/radar-hub-web/package.json[16-20]
## Recommended Fix
Raise radar-app's k8s-ui peer minimum to the first published version containing the helper. Publish k8s-ui before radar-app, and update both packages together in Radar Hub Web.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Slice section omits expansion setting ✓ Resolved
Description
The broadened EndpointSlices section renders inventory and status content without explicitly
setting defaultExpanded={true}. When a selected Service has a selector and endpointSlicesEnabled
is true, the section now appears in that drawer while its initial expansion relies on Section's
implicit default.
Code

packages/k8s-ui/src/components/resources/renderers/ServiceRenderer.tsx[117]

+      {!isExternalName && (hasNoSelector || endpointSlicesEnabled) && (
Evidence
The changed condition makes the EndpointSlices section available to selected Services with
selectors. That section contains inventory or status content, omits the explicit expansion prop, and
is not marked low-priority; the Section component supplies its default internally.

Rule 3036709: Renderer sections with content must explicitly set defaultExpanded to true
packages/k8s-ui/src/components/resources/renderers/ServiceRenderer.tsx[117-124]
packages/k8s-ui/src/components/ui/drawer-components.tsx[80-91]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The newly broadened EndpointSlices section contains content but relies on the Section component's implicit expansion default.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/ServiceRenderer.tsx[117-119]
## Recommended Fix
Add `defaultExpanded={true}` to the EndpointSlices `Section`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Stale owners open the wrong Service ✓ Resolved
Description
EndpointSliceRenderer creates an Owner Service link from serviceAssociation.name but does not
retain or check the owner's UID when navigating. If an unlabeled slice retains a reference to a
deleted Service and another Service takes its namespace and name, the link opens the replacement,
even though endpointSliceMatchesService rejects that UID mismatch.
Code

packages/k8s-ui/src/components/resources/renderers/EndpointSliceRenderer.tsx[R31-32]

+  const serviceAssociation = endpointSliceServiceAssociation(data)
+  const serviceName = serviceAssociation?.name
Evidence
The association retains the owner UID, but the newly offered link passes only namespace and name.
The destination fetch also uses only those fields, while reverse matching explicitly checks the UID
to avoid associating a replacement Service.

packages/k8s-ui/src/utils/endpoint-slices.ts[31-44]
packages/k8s-ui/src/components/resources/renderers/EndpointSliceRenderer.tsx[31-51]
web/src/components/workload/WorkloadView.tsx[585-588]
web/src/api/client.ts[2584-2598]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new owner-reference fallback offers an Owner Service link using only namespace and name. A stale owner reference can therefore navigate to a replacement Service with a different UID.
## Fix Focus Areas
- packages/k8s-ui/src/components/resources/renderers/EndpointSliceRenderer.tsx[31-51]
- packages/k8s-ui/src/utils/endpoint-slices.ts[31-44]
## Recommended Fix
Before making an owner-only association navigable, resolve the current Service and compare its UID with the owner-reference UID. If identity cannot be verified or differs, display the owner information without a navigation link; keep label-based navigation unchanged.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can route each severity your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread web/src/components/resources/renderers/ServiceRenderer.tsx Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant