Skip to content

frontend: crd: Guard against incomplete CRD spec in makeCRClass#5717

Open
WasThatRudy wants to merge 1 commit into
kubernetes-sigs:mainfrom
WasThatRudy:fix/crd-incomplete-spec-guards
Open

frontend: crd: Guard against incomplete CRD spec in makeCRClass#5717
WasThatRudy wants to merge 1 commit into
kubernetes-sigs:mainfrom
WasThatRudy:fix/crd-incomplete-spec-guards

Conversation

@WasThatRudy

@WasThatRudy WasThatRudy commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

CustomResourceDefinition.makeCRClass, getMainAPIGroup, the plural getter, and isNamespacedScope all assumed this.spec, this.spec.versions, and this.spec.names were fully populated. When a CRD reaches one of these methods with a partial spec (a transient watch update or in-flight refetch can leave the field undefined for a moment), the nested access throws and the whole dashboard view crashes with TypeError: Cannot read properties of undefined (reading 'names') or (reading 'versions').

Related Issue

Fixes #4824.

Changes

frontend/src/lib/k8s/crdSpec.ts (new)

Pure-helper module extracted so the validation and version-selection logic can be unit tested without instantiating CustomResourceDefinition (which transitively triggers a circular import in lib/k8s/index.ts).

  • CRDSpecLike, CRDVersionLike, UsableCRDVersion interfaces describing the subset of the CRD schema the helpers depend on.
  • validateCRDSpec(spec) returns { ok, missing, usableVersions }. ok=false lists the missing required fields. usableVersions is the subset filtered to name && served === true.
  • selectMainAPIGroup(spec) returns [group, version, plural] or null. Prefers the storage version, falls back to the first served version, honours the v1beta1 spec.version single-version shape only when spec.versions[] is empty or when spec.version matches a served entry.

Both helpers are pure: no logging, no module-level state, safe to call from render paths.

frontend/src/lib/k8s/crd.ts

  • makeCRClass() keeps its original non-nullable signature (typeof KubeObject<KubeCRD>). Throws with a clear error listing the missing fields when the spec is incomplete, so plugin/library consumers see the same kind of failure as before Crash Report: Cannot read properties of undefined (reading 'names') #4824 with a more diagnostic message and a pointer to the new API.
  • makeCRClassOrNull() (new) returns typeof KubeObject<KubeCRD> | null for callers that want to render a non-error UI state for partially-loaded or malformed CRDs. Pure: no console side effects, safe inside useMemo. names.singular is intentionally not required (Kubernetes server defaults it from kind); when absent we fall back to spec.names.kind.toLowerCase().
  • getMainAPIGroup() keeps its original non-nullable signature, returning ['', '', ''] for incomplete specs to preserve backward compatibility.
  • getMainAPIGroupOrNull() (new) returns the same tuple or null for callers that need to distinguish "incomplete CRD" from genuinely-empty fields.
  • get plural() uses optional chaining and returns '' when the spec is incomplete; return type stays string for backward compatibility. Callers needing an explicit signal should use getMainAPIGroupOrNull().
  • get isNamespacedScope() uses optional chaining on spec.scope.
  • makeCustomResourceClass.getBaseObject() consumes getMainAPIGroupOrNull() and falls back to apiInfoArgs[0] when the spec is incomplete.

Call sites updated to use the new nullable variants

File Behaviour
frontend/src/components/crd/CustomResourceDetails.tsx Split into outer (CRClass null = Empty with "incomplete spec" message) + inner that takes a non-null CRClass prop. getExtraColumns guards spec?.versions?.find.
frontend/src/components/crd/CustomResourceInstancesList.tsx Filters incomplete CRDs at the parent (CrInstanceList) into a classified list, sorts by ${cluster}/${uid||name} so the child's per-entry useList hook order is stable across refetches. remountKey is a content-addressed fingerprint (two independent 32-bit hashes concatenated, no BigInt literals). When all CRDs are unusable, renders a non-loading Empty so users aren't stuck on an indefinite spinner.
frontend/src/components/crd/CustomResourceList.tsx Split into outer (CRClass + apiGroup null = Empty with "incomplete spec" message) + inner that takes them as non-null props. title falls back to crd.metadata.name when kind is missing.
frontend/src/components/resourceMap/sources/definitions/sources.tsx Early continue when spec?.names?.kind is missing; null guards getMainAPIGroupOrNull() and makeCRClassOrNull().
frontend/src/components/resourceMap/sources/definitions/relations.tsx flatMap drops CRDs whose makeCRClassOrNull() is null.
frontend/src/components/resourceMap/sources/GraphSources.tsx makeKubeObjectNode null guards getMainAPIGroupOrNull() before destructuring.

TypeScript enforces the null handling at compile time on the *OrNull paths; tsc fails if any consumer of the new APIs forgets to handle null.

Tests

  • frontend/src/lib/k8s/crd.test.ts (new): 16 unit tests covering selectMainAPIGroup (storage-vs-served precedence, served filtering, v1beta1 spec.version fallback, mismatched spec.version, all-empty inputs) and validateCRDSpec (complete vs incomplete spec, missing-field reporting, usable-version filter, v1beta1 shape, undefined input).
  • frontend/src/components/crd/CustomResourceDetails.test.tsx: asserts the empty-state message renders when makeCRClassOrNull() returns null.
  • frontend/src/components/crd/CustomResourceInstancesList.test.tsx: asserts CRDs with null makeCRClassOrNull() are filtered out without crashing.

Translations

The two new user-facing strings ("This CustomResourceDefinition has an incomplete spec." and "No CustomResourceDefinitions with usable specs were found.") are translated in all 15 non-English locales (ar, de, es, fr, he, hi, it, ja, ko, pt, ru, ta, ur, zh, zh-tw). CustomResourceDefinition is left untranslated since it's a Kubernetes API proper noun.

Steps to Test

  1. cd frontend && npm install
  2. npm run lint: passes.
  3. npm run tsc: passes.
  4. npx vitest run src/components/crd src/lib/k8s/crd.test.ts: 25 tests pass.
  5. Manual repro of the reported crash:
    • Open the resource map or a CRD details view while a CRD's spec hasn't fully arrived.
    • Before this PR: dashboard crashes with Cannot read properties of undefined (reading 'names') or (reading 'versions') and the whole view goes white.
    • After this PR: the dashboard stays mounted, the incomplete CRD is skipped (in list/map paths) or shown as an empty state (in detail/list paths) describing the incomplete spec.

Screenshots

N/A. The fix prevents a crash; visible effect is the absence of one.

Notes for the Reviewer

  • DCO sign-off applied in the commit.
  • Backward compatibility: makeCRClass() and getMainAPIGroup() keep their pre-existing non-nullable signatures so existing plugin consumers compile unchanged. New *OrNull() variants are the recommended path for code that needs to handle the incomplete-spec state without throwing.
  • Defensive-fix scope: this is a consumer-boundary fix. The deeper question of why a CRD reaches these methods with a partial spec (a websocket ADDED event delivering an incomplete payload? an early useMemo evaluation? a query-cache eviction?) needs reproduction and is left as a follow-up.
  • Independent of frontend: api/v2: Include class identity in kube object query keys #5716.

@k8s-ci-robot k8s-ci-robot requested review from illume and yolossn May 17, 2026 13:40
@k8s-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: WasThatRudy
Once this PR has been reviewed and has the lgtm label, please assign yolossn for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels May 17, 2026
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 3895192 to 882f9fc Compare May 17, 2026 14:00
@WasThatRudy

Copy link
Copy Markdown
Contributor Author

Pushed 882f9fc53 to fix the ci-lint failure. The original [item, error] = CRClass ? CRClass.useGet(...) : [null, null] violated react-hooks/rules-of-hooks because useGet is itself a hook and was being called conditionally. Local npm run lint passed because the project lint allows warnings, but ci-lint runs with --max-warnings 0 and rightly flagged it.

Refactored CustomResourceDetailsRenderer into two components: the outer one returns the Loader when CRClass is null, the inner CustomResourceDetailsItem receives a non-null CRClass as a prop and calls useGet unconditionally. Standard React pattern for hook-on-conditional-class scenarios. No behaviour change; tests still 7/7 in src/components/crd.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens CRD handling in the frontend by making CustomResourceDefinition.makeCRClass() and related helpers resilient to transient/incomplete CRD specs (e.g., partial watch updates), preventing dashboard crashes like Cannot read properties of undefined (reading 'names'|'versions').

Changes:

  • Made CustomResourceDefinition.makeCRClass() return null (with a warning) instead of throwing when required CRD spec fields are missing, and added safer defaults to getMainAPIGroup(), plural, and isNamespacedScope.
  • Updated CRD consumers (CRD details/list/resource map) to handle a nullable CR class by skipping incomplete CRDs or showing a loader.
  • Adjusted typing at call sites to enforce null-handling via TypeScript.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
frontend/src/lib/k8s/crd.ts Adds defensive guards/defaults and makes makeCRClass() nullable to avoid crashes on partial CRD specs.
frontend/src/components/crd/CustomResourceDetails.tsx Shows a loader when makeCRClass() returns null and avoids calling useGet without a valid class.
frontend/src/components/crd/CustomResourceInstancesList.tsx Skips CRDs with incomplete specs when building per-CRD list queries.
frontend/src/components/crd/CustomResourceList.tsx Widens CRClass type to `...
frontend/src/components/resourceMap/sources/definitions/sources.tsx Skips creating graph sources for CRDs whose makeCRClass() returns null.
frontend/src/components/resourceMap/sources/definitions/relations.tsx Drops owner relations for CRDs that can’t build a class due to incomplete spec.
Comments suppressed due to low confidence (2)

frontend/src/components/crd/CustomResourceInstancesList.tsx:38

  • Switching from map to flatMap here breaks positional alignment between queries/dataClassCrds and the original crds array. Later code indexes crds[i] / crds[index] when iterating over queries, which will now refer to the wrong CRD (or the wrong name in the warning) whenever any CRD is skipped. Use the filtered dataClassCrds[i].crd instead of crds[i], or avoid filtering before building these index-based mappings.
  const dataClassCrds = crds.flatMap(crd => {
    const crdClass = crd.makeCRClass();
    if (!crdClass) {
      // CRD with incomplete spec; skip rather than crash on useList (#4824).
      return [];
    }
    const data = crdClass.useList({ cluster: crd.cluster, namespace: namespaces });
    return [{ data, crdClass, crd }];
  });

frontend/src/components/crd/CustomResourceInstancesList.tsx:38

  • There are existing component tests for this file, but none cover the new “skip incomplete CRD” behavior introduced by returning [] when makeCRClass() returns null. Adding a test case with one CRD returning null would validate both the skip behavior and that the warning/error mapping still refers to the correct CRD.
  const dataClassCrds = crds.flatMap(crd => {
    const crdClass = crd.makeCRClass();
    if (!crdClass) {
      // CRD with incomplete spec; skip rather than crash on useList (#4824).
      return [];
    }
    const data = crdClass.useList({ cluster: crd.cluster, namespace: namespaces });
    return [{ data, crdClass, crd }];
  });

Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 882f9fc to 121f373 Compare May 17, 2026 19:06
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels May 17, 2026
@WasThatRudy

Copy link
Copy Markdown
Contributor Author

Pushed 121f37366 addressing @copilot's review:

  1. Hook count instability in CustomResourceInstancesList.tsx — fair catch. The original flatMap over crds conditionally called useList, so a CRD transitioning from incomplete to complete spec would change the number of hook calls between renders and trigger React's "Rendered more/fewer hooks than expected" error. Refactored: the parent CrInstanceList now classifies CRDs (filters out the ones with null makeCRClass) and passes a ClassifiedCrd[] to CrInstancesView. The child component's useList count is now stable per mount, and the key derived from classified-CRD names triggers a clean remount on transition.

  2. spec.group can be undefined at runtime — agreed, defaulting it to '' in makeCRClass's apiInfo construction so a partial spec with present versions/names but missing group still produces a usable class.

  3. Test coverage for the null branch — added it('skips CRDs whose makeCRClass returns null without crashing (#4824)') to CustomResourceInstancesList.test.tsx. The test passes an incomplete-CRD mock alongside a healthy one; the rendered row count and absence of warning Alert confirm the null-handling. 8/8 tests pass in src/components/crd. A crd.test.ts would still be ideal for testing makeCRClass directly but is blocked by the circular-import problem in lib/k8s/ I noted in the original PR description.

@WasThatRudy

Copy link
Copy Markdown
Contributor Author

cc @illume — both @copilot comments addressed in 121f37366 (hook-count fix by filtering at parent + spec.group default + new null-handling test). Ready for a look whenever you have a moment.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/components/resourceMap/sources/definitions/sources.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 121f373 to 89b7a2e Compare May 18, 2026 08:06
@WasThatRudy

WasThatRudy commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

all five follow-ups are addressed in 89b7a2e:

  • lib/k8s/crd.tsconsole.warn now dedupes per CRD via a module-level Set keyed by metadata.uid (falling back to metadata.name). The first transient incomplete spec for a given CRD logs once; subsequent calls during the same session no longer spam.
  • components/crd/CustomResourceList.tsxtitle default and additionalPrinterCols lookup now use optional chaining on crd.spec?.names?.kind and crd.jsonData.spec?.versions?.find(...), so a transiently undefined spec doesn't crash before the !CRClass bail-out is reached.
  • components/resourceMap/sources/definitions/sources.tsxgenerateCRSources derives kind via crd.spec?.names?.kind and continues on missing, so an incomplete CRD can't crash the resource map before the makeCRClass() guard runs.
  • components/crd/CustomResourceInstancesList.tsx — removed the misleading key: string from CrInstancesView's props type; React's key attribute is still applied at the JSX site for remount semantics.
  • components/crd/CustomResourceDetails.test.tsx — added a regression test that mocks crd.makeCRClass() to return null and asserts the renderer shows the loader (via aria-label="Loading custom resource details") without mounting MainInfoSection.

cc @illume — pushed as an amend; lint, tsc, and the relevant suites (hooks.test.tsx, CustomResourceDetails.test.tsx, CustomResourceInstancesList.test.tsx) are green locally.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceDetails.tsx
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 81263ed to 9972482 Compare May 20, 2026 22:29
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/i18n/locales/zh/translation.json Outdated
Comment thread frontend/src/i18n/locales/zh/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 9972482 to 45d533d Compare May 20, 2026 22:45
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 5 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crdSpec.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 45d533d to 8ba2394 Compare May 20, 2026 22:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.test.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 5 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.test.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx
Comment thread frontend/src/components/crd/CustomResourceDetails.test.tsx
Comment thread frontend/src/lib/k8s/crd.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@illume illume left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for these changes.

It looks like this PR has git conflicts. Can you please fix them?

How to resolve conflicts

Rebase or merge the latest main into your branch, resolve the conflicts, and push the updated branch.

@WasThatRudy

Copy link
Copy Markdown
Contributor Author

@illume done. i have rebased the PR, it does not have conflicts anymore.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx
Comment thread frontend/src/i18n/locales/hi/translation.json Outdated

@illume illume left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution.

There are some open Copilot review comments — could you take a look at them? Please mark each one as resolved once you've addressed it.

@WasThatRudy

Copy link
Copy Markdown
Contributor Author

@illume Rebased onto current main on 2026-05-28 (only the recurring hi/translation.json conflict, resolved by taking my branch's version and re-running npm run i18n — 831 non-empty Hindi entries preserved). All previously-open Copilot threads are resolved; nothing currently open on my end. Ready for another look.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/resourceMap/sources/GraphSources.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/i18n/locales/hi/translation.json Outdated

@illume illume left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for these changes.

Can you please address the open review comments? Once you've resolved each one, please mark it as resolved.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crdSpec.ts Outdated
Comment thread frontend/src/lib/k8s/crdSpec.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/lib/k8s/crdSpec.ts Outdated
Comment on lines +76 to +81
export function validateCRDSpec(spec: CRDSpecLike | undefined): CRDValidation {
const missing: string[] = [];
if (!spec?.names?.plural) missing.push('names.plural');
if (!spec?.names?.kind) missing.push('names.kind');
if (!spec?.group) missing.push('group');
if (!spec?.scope) missing.push('scope');
Comment on lines +138 to +144
throw new Error(
`CustomResourceDefinition "${
this.metadata?.name ?? '<unknown>'
}" has an incomplete spec (missing: ${validation.missing.join(
', '
)}); use makeCRClassOrNull() if a null return is expected.`
);
Comment on lines +48 to +64
function fingerprint(keys: string[]): string {
let hashA = 0x811c9dc5 | 0; // FNV-1a 32-bit offset basis
let hashB = 0xdeadbeef | 0; // arbitrary independent seed
for (const k of keys) {
for (let i = 0; i < k.length; i++) {
const c = k.charCodeAt(i);
hashA = Math.imul(hashA ^ c, 0x01000193) | 0;
hashB = Math.imul(hashB ^ c, 0x5bd1e995) | 0;
}
// Entry separator so `['ab','c']` and `['a','bc']` produce distinct hashes.
hashA = Math.imul(hashA ^ 0x1f, 0x01000193) | 0;
hashB = Math.imul(hashB ^ 0x1f, 0x5bd1e995) | 0;
}
const a = (hashA >>> 0).toString(36);
const b = (hashB >>> 0).toString(36);
return `${keys.length}:${a}.${b}`;
}
CRD watch updates can deliver an object whose spec is still being
populated, which would crash `CustomResourceDefinition.makeCRClass()`
with `Cannot read properties of undefined (reading 'names' /
'versions')` the moment any consumer touched it. Reports like kubernetes-sigs#4824
were exactly that path: dashboard panels mounted before the CRD's
spec was fully materialized on the API server side.

Extract the CRD spec validation and version-selection logic into a
standalone `crdSpec.ts` module that the rest of the codebase can
import without pulling in `lib/k8s/index.ts` (which transitively
loads every built-in resource class and creates a circular import
in isolation tests). Expose two new explicit-nullable variants,
`makeCRClassOrNull()` and `getMainAPIGroupOrNull()`, that return
null on an incomplete spec instead of throwing. Render paths now
use the nullable variants and show a non-loading empty state when
the CRD turns out to be persistently malformed.

Plugin bundles ship their own copy of this module's code, so a
plugin built before these methods existed only has the legacy
`getMainAPIGroup()` on its CRD instance at runtime. The shared
`resolveCRDApiGroup` helper duck-types method presence and falls
back to the legacy method while rejecting the new in-tree all-empty
sentinel, so older plugin SDK bundles keep working.

Re-memoize the per-render CR class and API group lookups in the
list and details views: useList/useGet return a fresh CRD instance
on every update, so memoizing on the instance keeps class identity
stable across renders and avoids cascading useMemo recomputation
through the cols memo's dependency array.

Add regression tests for selectMainAPIGroup, validateCRDSpec, and
the incomplete-spec branches of the CRD details and instance-list
components.

Bug report: 4824.

Signed-off-by: Rudraksha Singh Sengar <rudraksharss@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash Report: Cannot read properties of undefined (reading 'names')

4 participants