Skip to content

OCPBUGS-91634: CAPI: Fix ImageDigestFormat validation to allow deep registry paths#2918

Open
simkam wants to merge 2 commits into
openshift:masterfrom
simkam:image-path-validation
Open

OCPBUGS-91634: CAPI: Fix ImageDigestFormat validation to allow deep registry paths#2918
simkam wants to merge 2 commits into
openshift:masterfrom
simkam:image-path-validation

Conversation

@simkam

@simkam simkam commented Jul 8, 2026

Copy link
Copy Markdown

https://redhat.atlassian.net/browse/OCPBUGS-91634

The ImageDigestFormat CEL validation rejected OCI image references with
more than one path segment after the registry host, breaking disconnected
environments that mirror images to deep paths like:

registry.example.com/team/project/product/component/image@sha256:...

The fix rewrites the validation regex based on the canonical OCI
distribution reference implementation at:
https://github.com/distribution/reference/blob/main/regexp.go

Key changes:

  • Supports multiple path segments (fixes the original bug)
  • Enforces lowercase-only path components per OCI spec
  • Adds IPv6 address support in brackets: [fd00::1]
  • IPv4 addresses supported via domain name pattern
  • Validates domain labels must start/end with alphanumeric (no leading/trailing hyphens)
  • Supports structured path separators: ., _, __, or -+

The regex matches: domainAndPort "/" remoteName

  • domainAndPort = (domainName | "[" ipv6 "]") [ ":" port ]
  • domainName = label ("." label)*
  • remoteName = pathComponent ("/" pathComponent)*
  • pathComponent = [a-z0-9]+ separated by ".", "_", "__", or "-+"

Added comprehensive test coverage:

  • IPv4 addresses with/without port
  • IPv6 addresses with/without port
  • Deep path validation (5+ segments)
  • Uppercase rejection in both digest and path components

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. labels Jul 8, 2026
@openshift-ci

openshift-ci Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Hello @simkam! Some important instructions when contributing to openshift/api:
API design plays an important part in the user experience of OpenShift and as such API PRs are subject to a high level of scrutiny to ensure they follow our best practices. If you haven't already done so, please review the OpenShift API Conventions and ensure that your proposed changes are compliant. Following these conventions will help expedite the api review process for your PR.

@openshift-ci-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Jul 8, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@simkam: This pull request references Jira Issue OCPBUGS-91634, which is invalid:

  • expected the bug to target either version "5.0." or "openshift-5.0.", but it targets "4.22.z" instead

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

https://redhat.atlassian.net/browse/OCPBUGS-91634

The ImageDigestFormat CEL validation rejected OCI image references with more than one path segment after the registry host, breaking disconnected environments that mirror images to deep paths like:

registry.example.com/team/project/product/component/image@sha256:...

This occurred because the path validation pattern limited segments:
OLD: /([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?
(zero or one segment, then final name)

The same codebase already validates unlimited segments in config/v1/types_kmsencryption.go for KMS plugin images:
NEW: (/[a-zA-Z0-9-_.]+)+
(one or more segments with no length limit)

This commit adopts the proven KMS pattern for all ImageDigestFormat instances, making digest validation consistent with how KMS encryption and image mirrors (IDMS/ICSP) handle registry paths in disconnected environments.

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.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

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

This change broadens OCI image reference validation across the API to accept multiple nested namespace path segments (host[:port][/namespace[/namespace...]]/name@sha256:<digest>) instead of the previously supported single optional namespace segment. Updates span Go type XValidation rules and doc comments in machineconfiguration (v1, v1alpha1) and operator/v1alpha1 packages, corresponding generated CRD YAML manifests for InternalReleaseImage, MachineConfigNode, MachineOSConfig, MachineOSBuild, ClusterAPI, OSImageStream, and PinnedImageSet, and associated test fixtures. Test files were updated with revised expected error messages and new acceptance/rejection scenarios covering deep repository paths, localhost references, missing path segments, and invalid digest formats. The digest-suffix (@sha256:<64-hex>) validation logic remains unchanged throughout.

🚥 Pre-merge checks | ✅ 15
✅ Passed checks (15 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed No Ginkgo titles were added or changed; the only modified test names are static YAML case names with no dynamic data.
Test Structure And Quality ✅ Passed No Ginkgo test code changed; the PR only updates generated YAML validation fixtures/CRDs, so the Ginkgo-specific structure/timeout/assertion checks are not applicable.
Microshift Test Compatibility ✅ Passed No new Ginkgo tests were added; the diff only updates generated CRD/OpenAPI manifests, so MicroShift API compatibility isn't implicated.
Single Node Openshift (Sno) Test Compatibility ✅ Passed Added cases only validate image-reference strings in YAML fixtures; no node-count, scheduling, drain, or topology assumptions were introduced.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only updates OCI image validation regexes, comments, CRDs, and tests; no deployment/controller pod specs, nodeSelectors, affinities, or replica/topology logic were changed.
Ote Binary Stdout Contract ✅ Passed Touched Go files only define types/validation markers; no main/init/TestMain/BeforeSuite/RunSpecs stdout writes or klog/fmt.Print calls were found.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the changed YAMLs are CRD/schema validation manifests only, with no IPv4 assumptions or external-network calls.
No-Weak-Crypto ✅ Passed Touched files only add/adjust SHA-256 image-digest validation; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret comparisons found.
Container-Privileges ✅ Passed Touched files only change OCI image-reference validation/docs; no privileged, hostPID/Network/IPC, SYS_ADMIN, or allowPrivilegeEscalation settings were added.
No-Sensitive-Data-In-Logs ✅ Passed Modified files are validation/docs/tests only; targeted scans found no logging APIs or secret-printing in changed Go files.
Title check ✅ Passed The title accurately summarizes the main change: relaxing ImageDigestFormat validation to allow deep registry paths.
Description check ✅ Passed The description is directly about the validation fix and added path support, matching the pull request changes.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@openshift-ci openshift-ci Bot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Jul 8, 2026
@openshift-ci openshift-ci Bot requested review from JoelSpeed and cheesesashimi July 8, 2026 14:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
machineconfiguration/v1/types_machineconfignode.go (1)

221-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cross-file inconsistency: host validation pattern differs from ImageDigestFormat and InternalReleaseImageBundleStatus.Image.

This field's regex allows localhost as a host (localhost|([a-zA-Z0-9-]+\\.)+...), while the ImageDigestFormat type in machineconfiguration/v1/types_machineosconfig.go:206 and the InternalReleaseImageBundleStatus.Image field in machineconfiguration/v1/types_internalreleaseimage.go:140 require a dot-qualified domain name with no localhost alternative. This means the same image pull spec (e.g., localhost:5000/openshift/image@sha256:...) would pass validation here but fail for ImageDigestFormat fields.

This is pre-existing, but since this PR touches all these regex patterns together, consider aligning the host validation across all image reference fields — either by adding localhost support to ImageDigestFormat or documenting why MachineConfigNodeStatusInternalReleaseImageRef.Image has stricter host requirements.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@machineconfiguration/v1/types_machineconfignode.go` at line 221, Align the
image host validation used by
MachineConfigNodeStatusInternalReleaseImageRef.Image with the regexes in
ImageDigestFormat and InternalReleaseImageBundleStatus.Image so they enforce the
same host rules. Right now the XValidation on the
machineconfiguration/v1/types_machineconfignode.go field allows localhost while
the other image reference types do not, which creates inconsistent behavior for
the same pull spec. Update the shared pattern or explicitly document why this
field should be stricter/different, and make the choice consistent across the
relevant type definitions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@operator/v1alpha1/types_clusterapi.go`:
- Around line 247-253: Add tests for the new ImageDigestFormat validation to
ensure the Cluster API schema accepts valid image references and rejects invalid
ones. Update the existing test suite under
operator/v1alpha1/tests/clusterapis.operator.openshift.io/ to cover the
ImageDigestFormat rules, including multi-segment paths, single-segment paths,
and malformed references that should fail the XValidation constraints. Use the
ImageDigestFormat type and its validation behavior as the target for the new
cases so the tests stay aligned if implementation details move.

---

Nitpick comments:
In `@machineconfiguration/v1/types_machineconfignode.go`:
- Line 221: Align the image host validation used by
MachineConfigNodeStatusInternalReleaseImageRef.Image with the regexes in
ImageDigestFormat and InternalReleaseImageBundleStatus.Image so they enforce the
same host rules. Right now the XValidation on the
machineconfiguration/v1/types_machineconfignode.go field allows localhost while
the other image reference types do not, which creates inconsistent behavior for
the same pull spec. Update the shared pattern or explicitly document why this
field should be stricter/different, and make the choice consistent across the
relevant type definitions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: bdb19428-d635-4868-88cc-62d86408cf4b

📥 Commits

Reviewing files that changed from the base of the PR and between b1cc68a and 33cb756.

📒 Files selected for processing (6)
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • operator/v1alpha1/types_clusterapi.go

Comment thread operator/v1alpha1/types_clusterapi.go Outdated
Comment on lines +247 to +253
// ImageDigestFormat is a type that conforms to the format host[:port][/namespace[/namespace...]]/name@sha256:<digest>.
// The digest must be 64 characters long, and consist only of lowercase hexadecimal characters, a-f and 0-9.
// The length of the field must be between 1 to 447 characters.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=447
// +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:<digest>' suffix, where '<digest>' is 64 characters long"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for existing test suites that cover ImageDigestFormat or internal release image validation
rg -l 'ImageDigestFormat\|InternalReleaseImageBundle\|MachineConfigNodeStatusInternalReleaseImage' --glob '*.testsuite.yaml' --glob '*test*'

Repository: openshift/api

Length of output: 151


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== File outline =="
ast-grep outline operator/v1alpha1/types_clusterapi.go --view expanded || true

echo
echo "== Relevant lines =="
sed -n '220,290p' operator/v1alpha1/types_clusterapi.go

echo
echo "== Test suites in operator/v1alpha1 =="
fd -a --type f . operator/v1alpha1 | rg '\.testsuite\.yaml$|test'

echo
echo "== Search for image reference validation in tests =="
rg -n 'sha256:|ImageDigestFormat|image reference|internal release image|bundle' operator/v1alpha1 operator/v1 tests config route install -g '*.testsuite.yaml' -g '*.go' || true

Repository: openshift/api

Length of output: 38932


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the edited API type and any nearby tests/testdata in the same API group.
echo "== operator/v1alpha1 files =="
git ls-files 'operator/v1alpha1/**' | sed -n '1,200p'

echo
echo "== types_clusterapi.go around the change =="
sed -n '1,340p' operator/v1alpha1/types_clusterapi.go

echo
echo "== Any testsuite YAML under operator/v1alpha1 =="
git ls-files 'operator/v1alpha1/**/*.testsuite.yaml' 'operator/v1alpha1/**/tests/**' | sed -n '1,200p' || true

echo
echo "== Search for validation markers related to the changed regex =="
rg -n 'XValidation:rule=.*split\(@\)|ImageDigestFormat|InternalReleaseImageBundle|MachineConfigNodeStatusInternalReleaseImage|sha256:\[a-f0-9\]\{64\}' operator/v1alpha1 -g '*.go' -g '*.testsuite.yaml' || true

Repository: openshift/api

Length of output: 18544


Add tests for the new image-reference validation. Cover multi-segment paths, single-segment paths, and invalid references in operator/v1alpha1/tests/clusterapis.operator.openshift.io/.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@operator/v1alpha1/types_clusterapi.go` around lines 247 - 253, Add tests for
the new ImageDigestFormat validation to ensure the Cluster API schema accepts
valid image references and rejects invalid ones. Update the existing test suite
under operator/v1alpha1/tests/clusterapis.operator.openshift.io/ to cover the
ImageDigestFormat rules, including multi-segment paths, single-segment paths,
and malformed references that should fail the XValidation constraints. Use the
ImageDigestFormat type and its validation behavior as the target for the new
cases so the tests stay aligned if implementation details move.

Source: Coding guidelines

@simkam

simkam commented Jul 8, 2026

Copy link
Copy Markdown
Author

/hold local testing

@openshift-ci openshift-ci Bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 8, 2026
@mdbooth

mdbooth commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

This fix looks correct at a quick glance, but any validation this gnarly needs tests.

@simkam simkam force-pushed the image-path-validation branch from 33cb756 to 63d0a7b Compare July 9, 2026 10:50
@openshift-ci openshift-ci Bot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Jul 9, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml (1)

256-274: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Field description text not updated to match the new deep-path validation.

currentImagePullSpec's description (line 262) still reads host[:port][/namespace]/name@sha256:<digest> while the validation regex at lines 272-274 now permits [/namespace[/namespace...]]. Same drift as in other files in this cohort.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml`
around lines 256 - 274, Update the currentImagePullSpec field description to
match the deeper namespace validation used by the x-kubernetes-validations
rules. In the MachineOSConfigs CRD, align the documented image pull spec format
with the actual regex in currentImagePullSpec so it reflects
host[:port][/namespace[/namespace...]]/name@sha256:<digest> instead of the older
single-namespace wording.

Source: Coding guidelines

payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml (1)

119-158: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

osExtensionsImage/osImage descriptions not updated to reflect deep-path support.

Both fields' descriptions (lines 126-128, 146-148) still say host[:port][/namespace]/name@sha256:<digest>, but the validation rules at lines 136-138 and 156-158 were updated to accept multiple path segments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml`
around lines 119 - 158, Update the osExtensionsImage and osImage descriptions in
the CRD so they match the current validation rules: the documented image pull
spec still implies only a single namespace segment, while the
x-kubernetes-validations in the osExtensionsImage and osImage schema allow
multiple deep path segments. Adjust the description text to describe
host[:port][/namespace[/namespace...]]/name@sha256:<digest> consistently for
both fields so the docs align with the actual schema behavior.

Source: Coding guidelines

payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml (1)

161-181: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

ref field description not updated to reflect deep-path support.

The description at line 164 still says the reference must be a valid image digest reference in the format host[:port][/namespace]/name@sha256:<digest>, but the validation rule at lines 175-177 was updated to accept [/namespace[/namespace...]]. Note the upstream ImageDigestFormat type doc comment already uses the updated wording (per the provided context snippet from operator/v1alpha1/types_clusterapi.go), so only this field-specific description text lags behind.

📝 Suggested description fix
-                                  ref is an image reference to the image containing the component manifests. The reference
-                                  must be a valid image digest reference in the format host[:port][/namespace]/name@sha256:<digest>.
+                                  ref is an image reference to the image containing the component manifests. The reference
+                                  must be a valid image digest reference in the format host[:port][/namespace[/namespace...]]/name@sha256:<digest>.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml` around
lines 161 - 181, The Cluster API CRD schema for the ref field has an outdated
description that still documents only
host[:port][/namespace]/name@sha256:<digest>, while the validation now supports
deeper namespace paths. Update the ref description text in the CRD definition to
match the ImageDigestFormat wording and reflect
host[:port][/namespace[/namespace...]]/name@sha256:<digest>, keeping it
consistent with the type docs used elsewhere.

Source: Coding guidelines

payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml (1)

69-84: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

name description not updated to reflect deep-path support.

Description at line 72 still says host[:port][/namespace]/name@sha256:<digest> while the validation rule at lines 82-84 now accepts multiple /namespace segments.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml`
around lines 69 - 84, Update the `name` field description in the
`pinnedimagesets` CRD to match the current validation logic: the description
still says `host[:port][/namespace]/name@sha256:<digest>` but
`x-kubernetes-validations` in the same schema now allows multiple nested path
segments. Adjust the wording in the `name` property documentation so it reflects
deep-path support consistently with the rule on `name`.

Source: Coding guidelines

payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml (1)

306-321: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Field description text is stale relative to the updated validation rule.

The digestedImagePushSpec description (line 309) still says the format is host[:port][/namespace]/name@sha256:<digest> (singular namespace), while the validation rule at lines 319-321 now accepts [/namespace[/namespace...]]. This mismatch is misleading to API consumers reading the field docs. As per coding guidelines, "the comment must explicitly state ... Valid enum values ... Validation constraints", so the prose description should match the actual accepted format.

📝 Suggested description fix
-                  The format of the push spec is: host[:port][/namespace]/name@sha256:<digest>,
+                  The format of the push spec is: host[:port][/namespace[/namespace...]]/name@sha256:<digest>,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml`
around lines 306 - 321, The digestedImagePushSpec field documentation is stale
and no longer matches the validation rule. Update the description in the
MachineOSBuilds CRD so it reflects the accepted push spec format with repeated
path namespaces, matching the x-kubernetes-validations on digestedImagePushSpec.
Keep the prose aligned with the actual rule in the same schema block, including
the sha256 digest requirement and the allowed host[:port]/namespace.../name
structure.

Source: Coding guidelines

payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml (1)

120-159: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Same description drift as the SelfManagedHA variant.

osExtensionsImage/osImage descriptions (lines 127-129, 147-149) still say host[:port][/namespace]/name@sha256:<digest>, not matching the updated multi-segment validation rules at lines 137-139 and 157-159.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml`
around lines 120 - 159, The osExtensionsImage and osImage descriptions are out
of sync with their validation rules. Update the description text in the CRD
entries for osExtensionsImage and osImage so it matches the current
multi-segment image name format enforced by the x-kubernetes-validations rules,
keeping the wording aligned with the existing validation patterns and unique
symbols osExtensionsImage and osImage.

Source: Coding guidelines

payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml (1)

513-529: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

v1alpha1 still rejects deep registry paths

status.releases[].image in the served v1alpha1 schema still uses the old regex with only an optional single namespace segment, so valid deep mirror paths like host/ns1/ns2/name@sha256:... are rejected. Update this version to match the v1 pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml`
around lines 513 - 529, The v1alpha1 schema for status.releases[].image still
uses the old single-namespace regex, so deep registry paths are rejected. Update
the x-kubernetes-validations rule on the image field in this CRD to match the
newer v1 pattern and allow multiple nested namespace segments while keeping the
`@sha256` digest validation unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml`:
- Around line 160-312: The new onUpdate test cases are missing required
MachineConfigNode spec fields, so the resource cannot be created before the
status update is validated. Update each affected case in
NoRegistryClusterInstall.yaml to include spec.node and spec.configVersion
alongside spec.pool in both the initial and updated objects, using the existing
MachineConfigNode schema as the reference. Keep the test names and status
expectations unchanged so the cases still exercise the intended image validation
paths.

---

Outside diff comments:
In `@payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml`:
- Around line 161-181: The Cluster API CRD schema for the ref field has an
outdated description that still documents only
host[:port][/namespace]/name@sha256:<digest>, while the validation now supports
deeper namespace paths. Update the ref description text in the CRD definition to
match the ImageDigestFormat wording and reflect
host[:port][/namespace[/namespace...]]/name@sha256:<digest>, keeping it
consistent with the type docs used elsewhere.

In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml`:
- Around line 513-529: The v1alpha1 schema for status.releases[].image still
uses the old single-namespace regex, so deep registry paths are rejected. Update
the x-kubernetes-validations rule on the image field in this CRD to match the
newer v1 pattern and allow multiple nested namespace segments while keeping the
`@sha256` digest validation unchanged.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml`:
- Around line 306-321: The digestedImagePushSpec field documentation is stale
and no longer matches the validation rule. Update the description in the
MachineOSBuilds CRD so it reflects the accepted push spec format with repeated
path namespaces, matching the x-kubernetes-validations on digestedImagePushSpec.
Keep the prose aligned with the actual rule in the same schema block, including
the sha256 digest requirement and the allowed host[:port]/namespace.../name
structure.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml`:
- Around line 256-274: Update the currentImagePullSpec field description to
match the deeper namespace validation used by the x-kubernetes-validations
rules. In the MachineOSConfigs CRD, align the documented image pull spec format
with the actual regex in currentImagePullSpec so it reflects
host[:port][/namespace[/namespace...]]/name@sha256:<digest> instead of the older
single-namespace wording.

In
`@payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml`:
- Around line 120-159: The osExtensionsImage and osImage descriptions are out of
sync with their validation rules. Update the description text in the CRD entries
for osExtensionsImage and osImage so it matches the current multi-segment image
name format enforced by the x-kubernetes-validations rules, keeping the wording
aligned with the existing validation patterns and unique symbols
osExtensionsImage and osImage.

In
`@payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml`:
- Around line 119-158: Update the osExtensionsImage and osImage descriptions in
the CRD so they match the current validation rules: the documented image pull
spec still implies only a single namespace segment, while the
x-kubernetes-validations in the osExtensionsImage and osImage schema allow
multiple deep path segments. Adjust the description text to describe
host[:port][/namespace[/namespace...]]/name@sha256:<digest> consistently for
both fields so the docs align with the actual schema behavior.

In `@payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml`:
- Around line 69-84: Update the `name` field description in the
`pinnedimagesets` CRD to match the current validation logic: the description
still says `host[:port][/namespace]/name@sha256:<digest>` but
`x-kubernetes-validations` in the same schema now allows multiple nested path
segments. Adjust the wording in the `name` property documentation so it reflects
deep-path support consistently with the rule on `name`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 25cd856c-072f-40aa-a1a7-8f317a2bf74a

📥 Commits

Reviewing files that changed from the base of the PR and between 33cb756 and 63d0a7b.

⛔ Files ignored due to path filters (32)
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosbuilds.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosconfigs.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_pinnedimagesets.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/ImageModeStatusReporting.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosbuilds.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/pinnedimagesets.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • openapi/generated_openapi/zz_generated.openapi.go is excluded by !openapi/**, !**/zz_generated*
  • openapi/openapi.json is excluded by !openapi/**
  • operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
📒 Files selected for processing (22)
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
🚧 Files skipped from review as they are similar to previous changes (6)
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1alpha1/types.go
  • operator/v1alpha1/types_clusterapi.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go

@simkam simkam force-pushed the image-path-validation branch from 63d0a7b to 7d7608b Compare July 9, 2026 11:43

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml (1)

513-529: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Regenerate the v1alpha1 CRDs

machineconfiguration/v1alpha1/types_internalreleaseimage.go now allows host[:port][/namespace[/namespace...]]/name, but both payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml and payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml still use the old single-namespace regex/message for image. Run make update so the generated manifests match the type definition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml`
around lines 513 - 529, The generated CRD validation for image is still using
the old single-namespace pattern and message, while
machineconfiguration/v1alpha1/types_internalreleaseimage.go now permits
host[:port][/namespace[/namespace...]]/name. Regenerate the v1alpha1 CRDs via
make update so the x-kubernetes-validations on InternalReleaseImage.image in
both generated manifests reflect the updated type definition and messaging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml`:
- Line 306: The test expectation for the internal release image OCI name error
is out of sync with the v1alpha1 CRD schema. Update the expectedStatusError in
the NoRegistryClusterInstall test to match the actual v1alpha1 message emitted
by the schema, or regenerate the CRD if the v1alpha1 type change is intended.
Use the existing test case and the CRD-generated error text as the source of
truth, and keep the substring exactly aligned with what the generator matches in
tests/generator.go.

---

Outside diff comments:
In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml`:
- Around line 513-529: The generated CRD validation for image is still using the
old single-namespace pattern and message, while
machineconfiguration/v1alpha1/types_internalreleaseimage.go now permits
host[:port][/namespace[/namespace...]]/name. Regenerate the v1alpha1 CRDs via
make update so the x-kubernetes-validations on InternalReleaseImage.image in
both generated manifests reflect the updated type definition and messaging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: dd081f4a-86c9-4542-9b9f-9d092ec06755

📥 Commits

Reviewing files that changed from the base of the PR and between 63d0a7b and 7d7608b.

⛔ Files ignored due to path filters (32)
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosbuilds.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosconfigs.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_pinnedimagesets.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/ImageModeStatusReporting.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosbuilds.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/pinnedimagesets.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • openapi/generated_openapi/zz_generated.openapi.go is excluded by !openapi/**, !**/zz_generated*
  • openapi/openapi.json is excluded by !openapi/**
  • operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
📒 Files selected for processing (27)
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
✅ Files skipped from review due to trivial changes (3)
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
🚧 Files skipped from review as they are similar to previous changes (21)
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
  • machineconfiguration/v1alpha1/types.go
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • machineconfiguration/v1/types_machineconfignode.go
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/types_machineosconfig.go
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml

@simkam simkam force-pushed the image-path-validation branch from 7d7608b to 499880b Compare July 9, 2026 12:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml`:
- Around line 118-123: The renderedImagePushSpec documentation is out of sync
with the actual ImageTagFormat validation and still describes only a single
namespace segment. Update the Go doc comment on renderedImagePushSpec in the
machineconfiguration/v1 types (both MachineOSConfig and MachineOSBuild) to
describe nested namespace segments as supported by the regex, then regenerate
the CRD so the generated schema description matches the updated comment.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml`:
- Around line 181-186: The `renderedImagePushSpec` docs are out of sync with the
validator and should be updated to describe the accepted OCI image formats.
Change the field comment in `machineconfiguration/v1/types_machineosconfig.go`
so it matches the deeper `host[:port][/namespace[/namespace...]]/name:<tag>`
shape and the `.svc`-with-port form, then regenerate the CRD manifests so
`MachineOSConfig` documentation and validation stay aligned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 0b89bff3-479c-4864-815a-42e55edc5cfa

📥 Commits

Reviewing files that changed from the base of the PR and between 7d7608b and 499880b.

⛔ Files ignored due to path filters (32)
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosbuilds.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosconfigs.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_pinnedimagesets.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/ImageModeStatusReporting.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosbuilds.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/pinnedimagesets.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • openapi/generated_openapi/zz_generated.openapi.go is excluded by !openapi/**, !**/zz_generated*
  • openapi/openapi.json is excluded by !openapi/**
  • operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
📒 Files selected for processing (27)
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
✅ Files skipped from review due to trivial changes (4)
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
🚧 Files skipped from review as they are similar to previous changes (21)
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • machineconfiguration/v1/tests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1/types_machineconfignode.go
  • operator/v1alpha1/types_clusterapi.go
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • machineconfiguration/v1/types_machineosconfig.go
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml

Comment thread payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml Outdated
Comment thread payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml Outdated
// +kubebuilder:validation:MaxLength=447
// +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:<digest>' suffix, where '<digest>' is 64 characters long"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"

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.

Are we sure about dropping the length validation here? Also, the two character sets are not quite the same, I don't think this is the right change

I was expecting just the namespace to change from a zero or one repeat to a multi repeat?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

ok, let's go with minimal change. I'll update this. I couldn't figure out why the length validation is here. It doesn't seem to be elsewhere.

@JoelSpeed

Copy link
Copy Markdown
Contributor

We need to check with owners in each area we are touching that they are in agreement with relaxing this validation, can we blame on the authors and work out who we need to be talking to?

@simkam simkam force-pushed the image-path-validation branch from 499880b to 1394f97 Compare July 9, 2026 14:15

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@machineconfiguration/v1/types_machineosconfig.go`:
- Line 206: The XValidation rule on the machine OS config image name still
allows empty path components and an empty final image name. Update the regex in
the kubebuilder validation for the OCI image field so the repeated
namespace/path segment and terminal name both require non-empty components, and
keep the host[:port][/namespace[/namespace...]]/name shape enforced in the
validation attached to the MachineOSConfig types. This should make malformed
refs like registry.example.com/@sha256:... and
registry.example.com//image@sha256:... fail validation.

In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml`:
- Around line 258-260: The validation for the image name in the CRD is still
using the old single-namespace pattern and allows empty path segments. Update
the upstream marker used by the schema generation so the rule enforces non-empty
repeated path segments, then regenerate the CRD so both the v1 and v1alpha1
versions pick up the same corrected message and rule. Use the existing
image-name validation marker in the relevant API type as the source of truth
rather than patching only the generated YAML.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml`:
- Around line 319-321: The digestedImagePushSpec documentation and validation
are out of sync: the field comment still describes only a single optional
namespace while the rule in the CRD now allows nested path segments and empty
name/path components. Update the source comment for digestedImagePushSpec to
match the actual host[:port][/namespace[/namespace...]]/name behavior, and
tighten the validation in the related rule so repeated path segments are
non-empty before regenerating the CRD.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml`:
- Around line 272-274: The generated validation docs for currentImagePullSpec
are stale and the rule still allows empty path/name segments; update the Go
field comment so it matches the nested namespace wording, then regenerate the
CRD from the currentImagePullSpec source so the validation rule uses a non-empty
repeated path segment pattern instead of permitting empty components.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

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

Review profile: CHILL

Plan: Enterprise

Run ID: 60121916-d623-4b80-bf29-78e6cfa50734

📥 Commits

Reviewing files that changed from the base of the PR and between 499880b and 1394f97.

⛔ Files ignored due to path filters (32)
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosbuilds.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_machineosconfigs.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.crd-manifests/0000_80_machine-config_01_pinnedimagesets.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/ImageModeStatusReporting.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosbuilds.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/machineosconfigs.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.featuregated-crd-manifests/pinnedimagesets.machineconfiguration.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.crd-manifests/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.featuregated-crd-manifests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • machineconfiguration/v1alpha1/zz_generated.swagger_doc_generated.go is excluded by !**/zz_generated*
  • openapi/generated_openapi/zz_generated.openapi.go is excluded by !openapi/**, !**/zz_generated*
  • openapi/openapi.json is excluded by !openapi/**
  • operator/v1alpha1/zz_generated.crd-manifests/0000_30_cluster-api_01_clusterapis.crd.yaml is excluded by !**/zz_generated.crd-manifests/*
  • operator/v1alpha1/zz_generated.featuregated-crd-manifests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
📒 Files selected for processing (26)
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/types_machineosconfig.go
  • machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1alpha1/types.go
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
✅ Files skipped from review due to trivial changes (2)
  • machineconfiguration/v1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
  • machineconfiguration/v1alpha1/tests/osimagestreams.machineconfiguration.openshift.io/OSStreams.yaml
🚧 Files skipped from review as they are similar to previous changes (20)
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-SelfManagedHA.crd.yaml
  • machineconfiguration/v1alpha1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • machineconfiguration/v1/types_internalreleaseimage.go
  • machineconfiguration/v1/tests/internalreleaseimages.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-Hypershift.crd.yaml
  • operator/v1alpha1/types_clusterapi.go
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-TechPreviewNoUpgrade.crd.yaml
  • machineconfiguration/v1alpha1/types_internalreleaseimage.go
  • payload-manifests/crds/0000_80_machine-config_01_pinnedimagesets.crd.yaml
  • operator/v1alpha1/tests/clusterapis.operator.openshift.io/ClusterAPIMachineManagement.yaml
  • machineconfiguration/v1alpha1/types.go
  • payload-manifests/crds/0000_80_machine-config_01_osimagestreams-Hypershift.crd.yaml
  • payload-manifests/crds/0000_30_cluster-api_01_clusterapis.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-CustomNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-TechPreviewNoUpgrade.crd.yaml
  • machineconfiguration/v1/types_machineconfignode.go
  • machineconfiguration/v1/tests/machineconfignodes.machineconfiguration.openshift.io/NoRegistryClusterInstall.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-SelfManagedHA-DevPreviewNoUpgrade.crd.yaml
  • payload-manifests/crds/0000_80_machine-config_01_machineconfignodes-Hypershift-CustomNoUpgrade.crd.yaml

// +kubebuilder:validation:MaxLength=447
// +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:<digest>' suffix, where '<digest>' is 64 characters long"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Tighten the path regex to reject empty components.

Line 206 now documents /name as required, but the rule still accepts empty path components and an empty image name because of {0,61} plus the final *. Use the intended repeated non-empty segment pattern so malformed refs like registry.example.com/@sha256:... and registry.example.com//image@sha256:... fail validation.

Proposed fix
-// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"
+// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@machineconfiguration/v1/types_machineosconfig.go` at line 206, The
XValidation rule on the machine OS config image name still allows empty path
components and an empty final image name. Update the regex in the kubebuilder
validation for the OCI image field so the repeated namespace/path segment and
terminal name both require non-empty components, and keep the
host[:port][/namespace[/namespace...]]/name shape enforced in the validation
attached to the MachineOSConfig types. This should make malformed refs like
registry.example.com/@sha256:... and registry.example.com//image@sha256:... fail
validation.

Comment on lines +258 to +260
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Regenerate this validation with non-empty path segments for every served version.

The v1 rule still accepts empty names/components for the same reason as the Go marker, and this CRD’s v1alpha1 schema below still has the old single-namespace rule/message. Fix the upstream marker to use non-empty repeated path segments and regenerate both versions.

Proposed generated-rule shape
-                        rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))
+                        rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@payload-manifests/crds/0000_80_machine-config_01_internalreleaseimages-SelfManagedHA.crd.yaml`
around lines 258 - 260, The validation for the image name in the CRD is still
using the old single-namespace pattern and allows empty path segments. Update
the upstream marker used by the schema generation so the rule enforces non-empty
repeated path segments, then regenerate the CRD so both the v1 and v1alpha1
versions pick up the same corrected message and rule. Use the existing
image-name validation marker in the relevant API type as the source of truth
rather than patching only the generated YAML.

Comment on lines +319 to +321
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Keep digestedImagePushSpec docs and validation aligned.

Line 309 still documents only [/namespace], while this message now advertises nested namespaces. The rule also permits empty path/name segments. Update the source field comment and use non-empty repeated path segments before regenerating this CRD.

Proposed generated-rule shape
-                  rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))
+                  rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))

As per coding guidelines, validation constraints must be documented in field comments and enforced by validation rules.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosbuilds.crd.yaml`
around lines 319 - 321, The digestedImagePushSpec documentation and validation
are out of sync: the field comment still describes only a single optional
namespace while the rule in the CRD now allows nested path segments and empty
name/path components. Update the source comment for digestedImagePushSpec to
match the actual host[:port][/namespace[/namespace...]]/name behavior, and
tighten the validation in the related rule so repeated path segments are
non-empty before regenerating the CRD.

Source: Coding guidelines

Comment on lines +272 to +274
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Update currentImagePullSpec source docs and reject empty path segments.

The generated description still says host[:port][/namespace]/name, but the validation message now says nested namespaces are supported. The regex also accepts empty path/name components. Update the Go field comment and regenerate with a non-empty repeated segment rule.

Proposed generated-rule shape
-                  rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))
+                  rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))

As per coding guidelines, validation constraints must be documented in field comments and enforced by validation rules.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))
- message: the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name
format, resembling a valid URL without the scheme
rule: (self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?(/[a-zA-Z0-9-_.]+)+$'))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@payload-manifests/crds/0000_80_machine-config_01_machineosconfigs.crd.yaml`
around lines 272 - 274, The generated validation docs for currentImagePullSpec
are stale and the rule still allows empty path/name segments; update the Go
field comment so it matches the nested namespace wording, then regenerate the
CRD from the currentImagePullSpec source so the validation rule uses a non-empty
repeated path segment pattern instead of permitting empty components.

Source: Coding guidelines

@simkam simkam force-pushed the image-path-validation branch from 1394f97 to f344405 Compare July 9, 2026 16:06
@simkam

simkam commented Jul 9, 2026

Copy link
Copy Markdown
Author

@andfasano @yuqi-zhang since this changes the parts you added, would you mind taking a look at this?

@andfasano

Copy link
Copy Markdown
Contributor

@andfasano @yuqi-zhang since this changes the parts you added, would you mind taking a look at this?

Hi @simkam please revert all the IRI related changes (here and here). They belong to the Feature:NoRegistryClusterInstall and are not part of the MAPI/CAPI flows. In addition the feature is currently under promotion process, so we don't make any unnecessary change during this critical period.

@JoelSpeed

Copy link
Copy Markdown
Contributor

In addition the feature is currently under promotion process, so we don't make any unnecessary change during this critical period.

I think the bug raised here applies as well to IRI, no? If there's a bug in IRI, we should fix it before we promote

Comment thread operator/v1alpha1/types_clusterapi.go Outdated
// +kubebuilder:validation:MaxLength=447
// +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:<digest>' suffix, where '<digest>' is 64 characters long"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme"
// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)*[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, resembling a valid URL without the scheme"

@mdbooth mdbooth Jul 10, 2026

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.

Breaking this down:

# SOL anchor
^

# Hostname
([a-zA-Z0-9-]+\.)+ # At least one leading hostname segment, alphanumerics or '-' followed by '.'
[a-zA-Z0-9-]+      # Mandatory final hostname segment

# Optional port
(:[0-9]{2,5})?

# image path
/                       # Mandatory leading slash
([a-zA-Z0-9-_]{0,61}/)* # Zero or more path segments, each alphanumeric + '-' or '_' with length between 0 and 61 characters followed by a slash
[a-zA-Z0-9-_.]*?        # Optional final path segment, alphanumeric + '-', '_', or '.', no length limit

# EOL anchor
$

The only thing we've changed here is in the image path. The assertion used by be 'zero or one path segments', we've change it to 'zero or more path segments'.

Here's the canonical reference parser: https://github.com/distribution/reference/blob/0965666a6ade2e06035fe352e38344be1e68951a/reference.go#L6-L27

I see many potential pre-existing problems here.

To be clear, I'm the original author of those problems. But it was copy-pasta, so they exist elsewhere in the repo too.

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.

I traced this regex back to #1773. There's no indication of where this came from.

I'm going to propose we write a new one from scratch based on the canonical reference implementation here: https://github.com/distribution/reference/blob/main/regexp.go.

Attempting to use the reference jargon, we're explicitly matching only the 'name', i.e. excluding tag/digest here. By this reference, I believe that is namePat, except that in namePat specifically domainAndPort is optional. We don't want it to be optional, so I think we want here is:

domainAndPort+`/`+remoteName

I propose we:

  • Construct this exact regexp ourselves (manually or just get a clanker to do it)
  • Ensure a code comment (but not the published godoc) references exactly where it came from
  • Update the tests to cover ipv6 addresses.

@simkam simkam force-pushed the image-path-validation branch from f344405 to b66efaa Compare July 10, 2026 12:59
@openshift-ci openshift-ci Bot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Jul 10, 2026
@simkam simkam changed the title OCPBUGS-91634: MAPI/CAPI: Fix ImageDigestFormat validation to allow deep registry paths OCPBUGS-91634: CAPI: Fix ImageDigestFormat validation to allow deep registry paths Jul 10, 2026
@simkam

simkam commented Jul 10, 2026

Copy link
Copy Markdown
Author

As discussed here and offline, the regexp was updated to match the reference implementation and the change is limited only to clusterapis.operator.openshift.io

@andfasano

Copy link
Copy Markdown
Contributor

In addition the feature is currently under promotion process, so we don't make any unnecessary change during this critical period.

I think the bug raised here applies as well to IRI, no? If there's a bug in IRI, we should fix it before we promote

ATM in IRI we don't have any scenario where deeper registry paths are required, they are all in a pretty basic form (originally we build the registry content by mirroring official OCP release + some OLM operators), ie:

{
  "repositories": [
    ...
    "openshift/release",
    "openshift/release-bundles",
    "openshift/release-images",
    "rhel9/support-tools",
    "ubi8/ubi"
  ]
}

Whereas I will agree that a more flexible CEL validation rule would be useful (in the past we also had to relax it a little bit to match the specific IRI requirements), this particular case does not seem involving IRI.
Meanwhile we have in progress an IRI version bump to v1 over several repo (here's the latter openshift/machine-config-operator#6280) that is blocking the IRI (NoRegistryClusterInstall) feature promotion and the 4.22 backport (where the deeper registry paths will not be present), a critical high-priortiy activity that I wouldn't want to delay any further, if not strictly required.
Given the current lower priority for IRI, and the current opportunity window, a potential approach could be to split this bug in two, one for MAPI/CAPI and one for IRI, the latter to be addressed later in the 5.0 release cycle - but after we'll have completed the 4.22 backport.

Comment thread operator/v1alpha1/types_clusterapi.go Outdated
// It matches: domainAndPort "/" remoteName
//
// domainAndPort = (domainName | "[" ipv6 "]") [ ":" port ]
// domainName = label ("." label)+ — at least one dot required

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.

This is a deviation from the reference, which has:

	// domainName defines the structure of potential domain components
	// that may be part of image names. This is purposely a subset of what is
	// allowed by DNS to ensure backwards compatibility with Docker image
	// names. This includes IPv4 addresses on decimal format.
	domainName = domainNameComponent + `(?:\.` + domainNameComponent + `)*`

And I confirm this deviation is reflected in the validation below. Did you do this deliberately? Assuming the reason is good, we should call out the reason for it specifically in this comment.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

that is a mistake, fixed

simkam added 2 commits July 10, 2026 16:25
…eep registry paths

https://redhat.atlassian.net/browse/OCPBUGS-91634

The `ImageDigestFormat` CEL validation rejected OCI image references with more than one path segment after the registry host, breaking disconnected environments that mirror images to deep paths like:

```
registry.example.com/team/project/product/component/image@sha256:...
```

The fix rewrites the validation regex based on the canonical OCI distribution reference implementation at: https://github.com/distribution/reference/blob/main/regexp.go

Key changes:
- Supports multiple path segments (fixes the original bug)
- Enforces lowercase-only path components per OCI spec
- Adds IPv6 address support in brackets: `[fd00::1]`
- IPv4 addresses supported via domain name pattern
- Validates domain labels must start/end with alphanumeric (no leading/trailing hyphens)
- Supports structured path separators: `.`, `_`, `__`, or `-+`

The regex matches: `domainAndPort "/" remoteName`
  - domainAndPort = (domainName | "[" ipv6 "]") [ ":" port ]
  - domainName    = label ("." label)*
  - remoteName    = pathComponent ("/" pathComponent)*
  - pathComponent = [a-z0-9]+ separated by ".", "_", "__", or "-+"

Added comprehensive test coverage:
- IPv4 addresses with/without port
- IPv6 addresses with/without port
- Deep path validation (5+ segments)
- Uppercase rejection in both digest and path components
@simkam simkam force-pushed the image-path-validation branch from b66efaa to 1b05df0 Compare July 10, 2026 14:31
@simkam

simkam commented Jul 10, 2026

Copy link
Copy Markdown
Author

/hold cancel

@openshift-ci openshift-ci Bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jul 10, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@simkam: This pull request references Jira Issue OCPBUGS-91634, which is invalid:

  • expected the bug to target only the "5.0.0" version, but multiple target versions were set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

/jira refresh

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.

@simkam

simkam commented Jul 10, 2026

Copy link
Copy Markdown
Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Jul 10, 2026
@openshift-ci-robot

Copy link
Copy Markdown

@simkam: This pull request references Jira Issue OCPBUGS-91634, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state ASSIGNED, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

/jira refresh

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.

@openshift-ci-robot

Copy link
Copy Markdown

@simkam: This pull request references Jira Issue OCPBUGS-91634, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (5.0.0) matches configured target version for branch (5.0.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)
Details

In response to this:

https://redhat.atlassian.net/browse/OCPBUGS-91634

The ImageDigestFormat CEL validation rejected OCI image references with
more than one path segment after the registry host, breaking disconnected
environments that mirror images to deep paths like:

registry.example.com/team/project/product/component/image@sha256:...

The fix rewrites the validation regex based on the canonical OCI
distribution reference implementation at:
https://github.com/distribution/reference/blob/main/regexp.go

Key changes:

  • Supports multiple path segments (fixes the original bug)
  • Enforces lowercase-only path components per OCI spec
  • Adds IPv6 address support in brackets: [fd00::1]
  • IPv4 addresses supported via domain name pattern
  • Validates domain labels must start/end with alphanumeric (no leading/trailing hyphens)
  • Supports structured path separators: ., _, __, or -+

The regex matches: domainAndPort "/" remoteName

  • domainAndPort = (domainName | "[" ipv6 "]") [ ":" port ]
  • domainName = label ("." label)*
  • remoteName = pathComponent ("/" pathComponent)*
  • pathComponent = [a-z0-9]+ separated by ".", "_", "__", or "-+"

Added comprehensive test coverage:

  • IPv4 addresses with/without port
  • IPv6 addresses with/without port
  • Deep path validation (5+ segments)
  • Uppercase rejection in both digest and path components

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.

@mdbooth mdbooth 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.

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 10, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-hypershift
/test e2e-aws-ovn-hypershift-conformance
/test e2e-aws-ovn-techpreview
/test e2e-aws-serial-1of2
/test e2e-aws-serial-2of2
/test e2e-aws-serial-techpreview-1of2
/test e2e-aws-serial-techpreview-2of2
/test e2e-azure
/test e2e-gcp
/test e2e-upgrade
/test e2e-upgrade-out-of-change
/test minor-e2e-upgrade-minor

@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mdbooth
Once this PR has been reviewed and has the lgtm label, please assign everettraven 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

@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

@simkam: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-serial-techpreview-2of2 1b05df0 link true /test e2e-aws-serial-techpreview-2of2
ci/prow/e2e-aws-ovn-hypershift-conformance 1b05df0 link true /test e2e-aws-ovn-hypershift-conformance
ci/prow/e2e-azure 1b05df0 link true /test e2e-azure

Full PR test history. Your PR dashboard.

Details

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 kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/severity-important Referenced Jira bug's severity is important for the branch this PR is targeting. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants