Skip to content

Add name field validation with maxLength to registry creation#6869

Merged
openshift-merge-bot[bot] merged 4 commits intoopendatahub-io:mainfrom
Philip-Carneiro:fix/registry-name-field-validation
Apr 15, 2026
Merged

Add name field validation with maxLength to registry creation#6869
openshift-merge-bot[bot] merged 4 commits intoopendatahub-io:mainfrom
Philip-Carneiro:fix/registry-name-field-validation

Conversation

@Philip-Carneiro
Copy link
Copy Markdown
Contributor

@Philip-Carneiro Philip-Carneiro commented Mar 25, 2026

Description

Adds maxLength=40 validation to the Name field in the Model Registry creation modal (CreateModal). When the user types a name longer than 40 characters, inline error feedback is shown and the submit button is disabled.

Changes:

  • Extended K8sNameDescriptionField to accept an optional maxNameLength prop and track invalidLength state
  • Added inline HelperText with ValidatedOptions.error when length exceeds limit
  • Blocked form submission in CreateModal when name length is invalid
  • Propagated nameState through RegisterAndStoreFields

How Has This Been Tested?

  • 4 cypress tests added
  • TypeScript: zero errors
  • Manual verification of error display and submit blocking

Test Impact

  • Unit tests: +38 new tests covering setupDefaults, handleUpdateLogic, error rendering, and form interaction
  • Cypress tests: N/A (validation is unit-testable)
  • Manual testing: Verified error appears at 254+ chars and submit is blocked

Request review criteria:

Self checklist (all need to be checked):

  • The developer has manually tested the changes and verified that the changes work
  • Testing instructions have been added in the PR body (for PRs involving changes that are not immediately obvious).
  • The developer has added tests or explained why testing cannot be added (unit or cypress tests for related changes)
  • The code follows our Best Practices (React coding standards, PatternFly usage, performance considerations)

If you have UI changes:

  • Included any necessary screenshots or gifs if it was a UI change.
  • Included tags to the UX team if it was a UI/UX change.

After the PR is posted & before it merges:

  • The developer has tested their solution on a cluster by using the image produced by the PR to main

Summary by CodeRabbit

  • New Features

    • Model registry names: 40-character maximum, live character-count feedback, and submission blocked when exceeded.
  • Refactor

    • Creation modal unified into a single content modal with clearer submit/cancel states, loading/disabled feedback, and consistent error/alert display; submit/cancel controls updated.
  • Bug Fixes

    • Validation tightened to rely on the explicit Kubernetes resource name field to prevent unexpected name fallbacks.
  • Tests

    • End-to-end tests added for name-length limits, UI feedback, and creation at the 40-character limit.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 25, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces the PatternFly modal composition in CreateModal with a single ContentModal and wires submit/cancel via buttonActions (primary → onSubmit, isLoading: isSubmitting, isDisabled: !canSubmit(), cancel → onCancelClose). Moves error/alert presentation into ContentModal and updates test IDs. Tightens Kubernetes name handling: metadata.name on create uses nameDesc.k8sName.value only and canSubmit now uses isK8sNameDescriptionDataValid(nameDesc). Adds MAX_MODEL_REGISTRY_NAME_LENGTH = 40, applies maxLength and limitNameResourceType: LimitNameResourceType.MODEL_REGISTRY to the name field, and adds Cypress tests validating max-length UI behavior and POST payload name length.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Security & Quality Issues

  • CWE-20 — Improper Input Validation: Frontend enforces a 40-char limit (maxLength) only at UI layer; this is insufficient as a security boundary.
    • Action: Ensure server-side validation rejects metadata.name exceeding 40 chars and returns a 4xx with a clear error payload.
  • CWE-602 — Client-Side Enforcement of Server-Side Security: Relying on client validation for Kubernetes name constraints risks bypass.
    • Action: Server must validate isValidK8sName(...) and the 40-char limit; add integration tests that attempt >40-char names and assert rejection.
  • Potential naming policy mismatch: Kubernetes DNS-1123 allows up to 63 chars; introducing a 40-char limit is an application policy that must be documented and enforced consistently across services.
    • Action: Document the 40-char constraint in API docs and internal guidelines; ensure downstream components accept or enforce the same limit.
  • Test coverage note: Cypress tests validate UI and intercepted POST payload; add API-level tests to cover server validation and error semantics (status codes and error messages).
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately summarizes the primary change: adding maxLength validation to the Name field in registry creation.
Description check ✅ Passed Description covers what changed, how it was tested (4 Cypress tests), and self-checklist is mostly complete, though cluster verification is pending.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 25, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 64.80%. Comparing base (596b3ea) to head (bfc4af9).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #6869      +/-   ##
==========================================
- Coverage   64.81%   64.80%   -0.02%     
==========================================
  Files        2441     2441              
  Lines       75996    75997       +1     
  Branches    19158    19156       -2     
==========================================
- Hits        49257    49249       -8     
- Misses      26739    26748       +9     
Files with missing lines Coverage Δ
.../src/concepts/k8s/K8sNameDescriptionField/utils.ts 98.30% <100.00%> (+0.05%) ⬆️
...nd/src/pages/modelRegistrySettings/CreateModal.tsx 91.04% <100.00%> (-0.09%) ⬇️
frontend/src/pages/modelRegistrySettings/const.ts 100.00% <100.00%> (ø)

... and 11 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 596b3ea...bfc4af9. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Philip-Carneiro Philip-Carneiro force-pushed the fix/registry-name-field-validation branch from 72d8b88 to 36b07cb Compare March 26, 2026 10:20
@Philip-Carneiro
Copy link
Copy Markdown
Contributor Author

SS of the change:
image

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts (2)

370-383: Test validates length constraint but not the transformed name value.

The test types 40 'a' characters as display name, but the K8s name will be derived via translateDisplayNameForK8s. The assertion only checks length.at.most(40) but doesn't verify the actual transformed name matches expectations. Consider also asserting the expected name value to catch potential translation logic issues.

♻️ Strengthen assertion
     cy.wait('@createModelRegistry').then((interception) => {
-      expect(interception.request.body.modelRegistry.metadata.name).to.have.length.at.most(40);
+      const name = interception.request.body.modelRegistry.metadata.name;
+      expect(name).to.have.length.at.most(40);
+      expect(name).to.equal('a'.repeat(40)); // or the expected translated value
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts`
around lines 370 - 383, The test only checks the k8s name length after
submitting a 40-char display name but doesn't assert the actual transformed
value; update the spec in modelRegistrySettings.cy.ts to compute the expected
K8s-safe name using the same logic as translateDisplayNameForK8s (or call that
helper if accessible) and assert
interception.request.body.modelRegistry.metadata.name equals that expected
transformed string in addition to the length check, referencing the interception
alias '@createModelRegistry' and the modelRegistry.metadata.name property to
locate where to assert.

360-368: Brittle assertion: cy.contains('Cannot exceed 40 characters') relies on exact UI text.

If the warning message changes, this test breaks. Consider using a data-testid on the warning element and asserting visibility, or at minimum documenting why exact text matching is acceptable here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts`
around lines 360 - 368, The test "should show character count warning when name
approaches 40 limit" uses a brittle text match (cy.contains('Cannot exceed 40
characters')); update the app to add a stable test id on the name-length warning
(e.g., data-testid="name-length-warning") and change the spec to assert
visibility via that test id (use
cy.get('[data-testid="name-length-warning"]').should('be.visible')); keep the
existing remaining-count assertion (cy.contains('remaining')) or similarly
replace it with a test id if available, and locate changes around
modelRegistrySettings.findFormField(FormFieldSelector.NAME) where the warning is
triggered.
frontend/src/pages/modelRegistrySettings/CreateModal.tsx (1)

390-391: Duplicated k8sName computation logic.

The k8sName derivation (nameDesc.k8sName.value || translateDisplayNameForK8s(nameDesc.name)) appears identically on line 323 in onSubmit. Consider extracting to a memoized value or helper to avoid logic drift between validation and submission.

♻️ Extract shared k8sName computation
+  const effectiveK8sName = nameDesc.k8sName.value || translateDisplayNameForK8s(nameDesc.name);
+
   const canSubmit = () => {
-    const k8sName = nameDesc.k8sName.value || translateDisplayNameForK8s(nameDesc.name);
-    const isValidName = isValidK8sName(k8sName) && k8sName.length <= MAX_MODEL_REGISTRY_NAME_LENGTH;
+    const isValidName = isValidK8sName(effectiveK8sName) && effectiveK8sName.length <= MAX_MODEL_REGISTRY_NAME_LENGTH;

Then use effectiveK8sName in onSubmit as well (line 323).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/modelRegistrySettings/CreateModal.tsx` around lines 390 -
391, Duplicate k8sName logic: extract the expression nameDesc.k8sName.value ||
translateDisplayNameForK8s(nameDesc.name) into a single reusable value (e.g.,
effectiveK8sName) computed once (use useMemo or a small helper function) and
replace both uses (the validation isValidName and the onSubmit flow) so
validation (isValidName) and submission (onSubmit) both reference
effectiveK8sName; keep the same length check with MAX_MODEL_REGISTRY_NAME_LENGTH
and ensure names used in isValidK8sName and submit payload reference the new
symbol.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/pages/modelRegistrySettings/CreateModal.tsx`:
- Around line 390-391: Duplicate k8sName logic: extract the expression
nameDesc.k8sName.value || translateDisplayNameForK8s(nameDesc.name) into a
single reusable value (e.g., effectiveK8sName) computed once (use useMemo or a
small helper function) and replace both uses (the validation isValidName and the
onSubmit flow) so validation (isValidName) and submission (onSubmit) both
reference effectiveK8sName; keep the same length check with
MAX_MODEL_REGISTRY_NAME_LENGTH and ensure names used in isValidK8sName and
submit payload reference the new symbol.

In
`@packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts`:
- Around line 370-383: The test only checks the k8s name length after submitting
a 40-char display name but doesn't assert the actual transformed value; update
the spec in modelRegistrySettings.cy.ts to compute the expected K8s-safe name
using the same logic as translateDisplayNameForK8s (or call that helper if
accessible) and assert interception.request.body.modelRegistry.metadata.name
equals that expected transformed string in addition to the length check,
referencing the interception alias '@createModelRegistry' and the
modelRegistry.metadata.name property to locate where to assert.
- Around line 360-368: The test "should show character count warning when name
approaches 40 limit" uses a brittle text match (cy.contains('Cannot exceed 40
characters')); update the app to add a stable test id on the name-length warning
(e.g., data-testid="name-length-warning") and change the spec to assert
visibility via that test id (use
cy.get('[data-testid="name-length-warning"]').should('be.visible')); keep the
existing remaining-count assertion (cy.contains('remaining')) or similarly
replace it with a test id if available, and locate changes around
modelRegistrySettings.findFormField(FormFieldSelector.NAME) where the warning is
triggered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 3287a93d-3af8-48fa-9038-57084b33e320

📥 Commits

Reviewing files that changed from the base of the PR and between 6a0fbf3 and 36b07cb.

📒 Files selected for processing (3)
  • frontend/src/pages/modelRegistrySettings/CreateModal.tsx
  • frontend/src/pages/modelRegistrySettings/const.ts
  • packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
frontend/src/pages/modelRegistrySettings/CreateModal.tsx (2)

420-441: ContentModal integration is correct; consider disabling Cancel during submission.

The buttonActions array properly wires submit/cancel handlers with isLoading and isDisabled. However, Cancel remains clickable while isSubmitting=true. If clicked mid-flight, onBeforeClose() resets state and closes the modal while the async operation is still pending—leading to state updates on an unmounted component.

🛠️ Optional: Disable Cancel during submission
         {
           label: 'Cancel',
           onClick: onCancelClose,
           variant: 'link',
+          isDisabled: isSubmitting,
           dataTestId: 'modal-cancel-button',
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/modelRegistrySettings/CreateModal.tsx` around lines 420 -
441, Cancel remains clickable during submission; update the Cancel action in the
ContentModal's buttonActions so it is disabled while isSubmitting is true (e.g.,
set the Cancel action's isDisabled: isSubmitting or guard onCancelClose to
return early when isSubmitting) to prevent closing/resetting state mid-flight;
reference the buttonActions array, the Cancel action entry, the isSubmitting
flag and the onCancelClose handler when making the change.

444-449: Add maxLength attribute to resource name input for consistent UX.

The display name field has maxLength={MAX_MODEL_REGISTRY_NAME_LENGTH} preventing user input beyond the limit. The resource name field lacks this attribute, allowing users to type beyond the limit; validation only blocks submission via canSubmit(). Add maxLength to the resource name input in ResourceNameField to match the display name behavior and provide immediate visual feedback.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/modelRegistrySettings/CreateModal.tsx` around lines 444 -
449, The resource name input is missing a maxLength causing inconsistent UX; add
a maxLength prop with the same constant used for the display name. Update the
ResourceNameField usage to pass maxLength={MAX_MODEL_REGISTRY_NAME_LENGTH} and
ensure the ResourceNameField component forwards that prop to the underlying
input element (or adds it to the input JSX inside ResourceNameField). Reference
symbols: ResourceNameField and MAX_MODEL_REGISTRY_NAME_LENGTH.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@frontend/src/pages/modelRegistrySettings/CreateModal.tsx`:
- Around line 420-441: Cancel remains clickable during submission; update the
Cancel action in the ContentModal's buttonActions so it is disabled while
isSubmitting is true (e.g., set the Cancel action's isDisabled: isSubmitting or
guard onCancelClose to return early when isSubmitting) to prevent
closing/resetting state mid-flight; reference the buttonActions array, the
Cancel action entry, the isSubmitting flag and the onCancelClose handler when
making the change.
- Around line 444-449: The resource name input is missing a maxLength causing
inconsistent UX; add a maxLength prop with the same constant used for the
display name. Update the ResourceNameField usage to pass
maxLength={MAX_MODEL_REGISTRY_NAME_LENGTH} and ensure the ResourceNameField
component forwards that prop to the underlying input element (or adds it to the
input JSX inside ResourceNameField). Reference symbols: ResourceNameField and
MAX_MODEL_REGISTRY_NAME_LENGTH.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 6ccb9fec-f577-469a-9379-33aee04b31a2

📥 Commits

Reviewing files that changed from the base of the PR and between 36b07cb and 138f90f.

📒 Files selected for processing (2)
  • frontend/src/pages/modelRegistrySettings/CreateModal.tsx
  • packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/cypress/cypress/tests/mocked/modelRegistrySettings/modelRegistrySettings.cy.ts

Comment thread frontend/src/pages/modelRegistrySettings/const.ts
Comment thread frontend/src/pages/modelRegistrySettings/CreateModal.tsx Outdated
Comment thread frontend/src/pages/modelRegistrySettings/CreateModal.tsx Outdated
@Philip-Carneiro
Copy link
Copy Markdown
Contributor Author

/retest

@Philip-Carneiro Philip-Carneiro force-pushed the fix/registry-name-field-validation branch from bdd80e8 to 52cf7ed Compare March 30, 2026 13:19
@Philip-Carneiro
Copy link
Copy Markdown
Contributor Author

/retest

@Philip-Carneiro Philip-Carneiro force-pushed the fix/registry-name-field-validation branch from a9ae525 to bb0dd8c Compare April 2, 2026 11:06
@Philip-Carneiro
Copy link
Copy Markdown
Contributor Author

/retest

@Philip-Carneiro Philip-Carneiro force-pushed the fix/registry-name-field-validation branch from 7e0c05a to 1c8c5a2 Compare April 14, 2026 16:53
Signed-off-by: Philip Colares Carneiro <philip.colares@gmail.com>
Signed-off-by: Philip Colares Carneiro <philip.colares@gmail.com>
Signed-off-by: Philip Colares Carneiro <philip.colares@gmail.com>
Signed-off-by: Philip Colares Carneiro <philip.colares@gmail.com>
@Philip-Carneiro Philip-Carneiro force-pushed the fix/registry-name-field-validation branch from 1c8c5a2 to bfc4af9 Compare April 15, 2026 07:32
@YuliaKrimerman
Copy link
Copy Markdown
Contributor

/lgtm
/approve

@openshift-ci openshift-ci Bot added the lgtm label Apr 15, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented Apr 15, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: YuliaKrimerman

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

The pull request process is described 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

@openshift-merge-bot openshift-merge-bot Bot merged commit e9fa6c1 into opendatahub-io:main Apr 15, 2026
47 of 53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants