NO-JIRA: do not fall back to the raw resource field for empty children - #492
NO-JIRA: do not fall back to the raw resource field for empty children#492XIANLIBO wants to merge 1 commit into
Conversation
DetailsItem resolved its rendered value with `children || _.get(obj, path, defaultValue)`. An empty child therefore fell through to the raw resource field, which for paths such as `metadata.annotations` is a plain object. React rejects a plain object as a child, so the whole details page crashes with "Objects are not valid as a React child" (minified error openshift#31). This is reachable today on the Route details page in the Japanese locale. The Annotations item renders `t('{{count}} annotation', { count })` as its child when the user cannot patch the Route, and `useAccessReview` starts out as `false` while the SelfSubjectAccessReview is still in flight, so the very first render always takes that branch. In the `ja` locale `{{count}} annotation_other` resolves to an empty string, the fallback kicks in and `metadata.annotations` is handed to React, which throws before the access review resolves. Routes carrying two or more annotations are affected. Routes managed by Argo CD always are, because they carry both `argocd.argoproj.io/tracking-id` and `kubectl.kubernetes.io/last-applied-configuration`. Routes with a single annotation render fine, because `{{count}} annotation_one` is absent from the `ja` resource and the i18next fallback returns a non-empty string. The broken `ja` translations were repaired separately in 00e08ca, which removes the trigger but not the fallback that turns a falsy child into a rendered object. Use `??` so the raw resource field is used only when no children were provided at all.
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@XIANLIBO: This pull request explicitly references no jira issue. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: Repository: openshift/coderabbit/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: XIANLIBO The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @XIANLIBO. Thanks for your PR. I'm waiting for a openshift member to verify that this patch is reasonable to test. If it is, they should reply with Regular contributors should join the org to skip this step. Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
What this fixes
DetailsItemresolved its rendered value with:An empty child falls through to the raw resource field. For paths such as
metadata.annotationsthat field is a plain object, and React rejects a plainobject as a child, so the whole details page crashes:
How it is reachable today
Route details page, Japanese locale:
DetailsSectionLeftColumnrenders the Annotations item ascanUpdate ? <Button>{label}</Button> : label, wherelabel = t('{{count}} annotation', { count }).useAccessReviewinitialisesisAllowedtofalsewhile theSelfSubjectAccessReviewis in flight, so the first render always takes theplain-string branch — including for cluster admins.
jaresource,{{count}} annotation_otheris an empty string, sochildrenis''.'' || _.get(route, 'metadata.annotations')yields the annotations object,React throws, and the error boundary replaces the page.
Routes with two or more annotations are affected. Routes managed by Argo CD
always are, since they carry both
argocd.argoproj.io/tracking-idandkubectl.kubernetes.io/last-applied-configuration. Routes with exactly oneannotation render fine, because
{{count}} annotation_oneis absent from thejaresource and the i18next fallback returns a non-empty string.The locale resource as actually served
Captured from
/locales/resource.json?ns=plugin__networking-console-pluginon a4.21 cluster:
lng{{count}} annotation_one{{count}} annotation_otheren"{{count}} annotation_one""{{count}} annotation_other"ja""That is the whole asymmetry. Under
lng=enthe value is the key name itself, sothe Annotations row renders the literal string
2 annotation_other— wrongtext, but non-empty, so the
||fallback never fires. Underlng=jathe valueis
"", the fallback fires, and the page crashes.The English rendering is worth noting on its own: a details page showing a raw
i18next plural key to the user is already a visible defect, independent of the
crash.
Relation to 00e08ca
00e08ca ("Backport translations from 4.22") repairs those strings and removes
the trigger. It does not remove the fallback that turns a falsy child
into a rendered object, so any future empty or missing translation reintroduces
the same crash, in
DetailsItemfor every caller — not just Annotations.The change
??restores the intended contract: use the children when the caller providedthem, and read the resource field only when the caller provided none. A caller
passing a falsy child now renders that falsy child, which React handles, rather
than silently swapping in a value of an unrelated type.
I audited all 68
<DetailsItem>call sites — 49 with children, 19 self-closing.None relies on a falsy child falling through to the raw field:
{cond && ...}patterns in this repo wrap theDetailsItemelementitself, or sit alongside a sibling element so that
childrenis an array(truthy either way).
UDNLayer2Details/UDNLayer3Detailsreceivesubnets/joinSubnetsfromUDNLayerDetails.getList, which always returns an element —<List>whenthere are entries,
<MutedText>otherwise.IngressStatuspasses{ingress?.host}and{ingress?.wildcardPolicy}.Both are
undefinedwhen absent, which??still treats as "no children",so those items are unchanged.
??still falls through for the 19 self-closing call sites, so I checked thosetoo: every one points at a scalar path (
metadata.name,spec.host,spec.tls.termination,.mtu,.role,subnets[i].cidr, and so on). Theobject-valued paths in this repo —
metadata.labels,metadata.annotations,metadata.ownerReferences,spec.selector,spec.ports— are all renderedthrough element children, which
??never discards. So after this change thereis no remaining path in the repo by which the raw field can reach React as a
plain object.
Verification
npm run lint— 0 errors. (The one warning is pre-existing, inSyncedEditor.tsx.) Since.eslintrc.jsonsetsprettier/prettiertoerror, this also confirms the formatting is correct.npx tsc --noEmit -p tsconfig.json— 32 errors before and after the change,unchanged; none in the touched file.
npm run i18nproduces nochange to
locales/.On the missing Jira reference
CONTRIBUTING.md asks for
OCPBUGS-NNNNN:in the title. I do not haveissue-creation permission in the Red Hat Jira, so I could not file one — hence
NO-JIRA:. If you would like this tracked and backported to the active releasebranches, please attach or file an OCPBUGS and I will retitle the PR.
Observed on
OpenShift 4.21.27,
networking-console-pluginat release payload 4.21.27,1629 affected Routes on the cluster where this was found.