Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions config/v1/tests/images.config.openshift.io/AAA_ungated.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,102 @@ tests:
apiVersion: config.openshift.io/v1
kind: Image
spec: {}
- name: Should not allow creating an Image with a tagged registry entry in blockedRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
expectedError: "spec.registrySources.blockedRegistries[0]"
- name: Should not allow creating an Image with a tagged registry entry in allowedRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
allowedRegistries: ["registry.io/myrepo:latest"]
expectedError: "spec.registrySources.allowedRegistries[0]"
- name: Should not allow creating an Image with a tagged registry entry in insecureRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
insecureRegistries: ["registry.io/myrepo:latest"]
expectedError: "spec.registrySources.insecureRegistries[0]"
- name: Should not allow creating an Image with a digest registry entry in blockedRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo@sha256:abc123"]
expectedError: "spec.registrySources.blockedRegistries[0]"
- name: Should not allow creating an Image with a digest registry entry in allowedRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
allowedRegistries: ["registry.io/myrepo@sha256:abc123"]
expectedError: "spec.registrySources.allowedRegistries[0]"
- name: Should not allow creating an Image with a digest registry entry in insecureRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
insecureRegistries: ["registry.io/myrepo@sha256:abc123"]
expectedError: "spec.registrySources.insecureRegistries[0]"
- name: Should allow creating an Image with valid registry entries in blockedRegistries and insecureRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries:
- "registry.io"
- "registry.io/myrepo"
- "*.example.com"
- "localhost:5000/repo"
insecureRegistries:
- "insecure.registry.io"
- "*.insecure.example.com"
expected: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries:
- "registry.io"
- "registry.io/myrepo"
- "*.example.com"
- "localhost:5000/repo"
insecureRegistries:
- "insecure.registry.io"
- "*.insecure.example.com"
- name: Should allow creating an Image with valid registry entries in allowedRegistries
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
allowedRegistries:
- "registry.io"
- "registry.io/myrepo"
- "*.example.com"
- "localhost:5000/repo"
expected: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
allowedRegistries:
- "registry.io"
- "registry.io/myrepo"
- "*.example.com"
- "localhost:5000/repo"
onUpdate:
- name: Should allow updating other fields with an invalid persisted registrySources in spec
initialCRDPatches:
Expand Down Expand Up @@ -114,3 +210,109 @@ tests:
allowedRegistries: ["test"]
blockedRegistries: ["test"]
expectedError: 'Only one of blockedRegistries or allowedRegistries may be set'
- name: Should allow updating other fields when an invalid tagged blockedRegistries entry is persisted
initialCRDPatches:
- op: remove
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/registrySources/properties/blockedRegistries/items/pattern
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
updated: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
expected: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
- name: Should allow updating other fields when an invalid tagged allowedRegistries entry is persisted
initialCRDPatches:
- op: remove
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/registrySources/properties/allowedRegistries/items/pattern
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
allowedRegistries: ["registry.io/myrepo:latest"]
updated: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
allowedRegistries: ["registry.io/myrepo:latest"]
expected: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
allowedRegistries: ["registry.io/myrepo:latest"]
- name: Should allow updating other fields when an invalid tagged insecureRegistries entry is persisted
initialCRDPatches:
- op: remove
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/registrySources/properties/insecureRegistries/items/pattern
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
insecureRegistries: ["registry.io/myrepo:latest"]
updated: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
insecureRegistries: ["registry.io/myrepo:latest"]
expected: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
externalRegistryHostnames: ["registry.example.com"]
registrySources:
insecureRegistries: ["registry.io/myrepo:latest"]
- name: Should not allow adding a new invalid tagged entry to blockedRegistries even when an invalid entry is already persisted
initialCRDPatches:
- op: remove
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/registrySources/properties/blockedRegistries/items/pattern
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
updated: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest", "other.com/repo:v1"]
expectedError: "spec.registrySources.blockedRegistries"
- name: Should not allow appending to blockedRegistries when an invalid entry is already persisted because listType atomic re-validates the whole list
initialCRDPatches:
- op: remove
path: /spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/registrySources/properties/blockedRegistries/items/pattern
initial: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest"]
updated: |
apiVersion: config.openshift.io/v1
kind: Image
spec:
registrySources:
blockedRegistries: ["registry.io/myrepo:latest", "valid.registry.io"]
expectedError: "spec.registrySources.blockedRegistries"
18 changes: 18 additions & 0 deletions config/v1/types_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,20 +165,38 @@ type RegistryLocation struct {
// +kubebuilder:validation:XValidation:rule="has(self.blockedRegistries) ? !has(self.allowedRegistries) : true",message="Only one of blockedRegistries or allowedRegistries may be set"
type RegistrySources struct {
// insecureRegistries are registries which do not have a valid TLS certificates or only support HTTP connections.
// Each entry must be a valid registry scope in the format hostname[:port][/path],
// optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
// The hostname must consist of valid DNS labels separated by dots, where each label
// contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
// Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").
// +optional
// +listType=atomic
// +kubebuilder:validation:items:Pattern=`^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$`
InsecureRegistries []string `json:"insecureRegistries,omitempty"`
// blockedRegistries cannot be used for image pull and push actions. All other registries are permitted.
// Each entry must be a valid registry scope in the format hostname[:port][/path],
// optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
// The hostname must consist of valid DNS labels separated by dots, where each label
// contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
// Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").
//
// Only one of BlockedRegistries or AllowedRegistries may be set.
// +optional
// +listType=atomic
// +kubebuilder:validation:items:Pattern=`^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$`
BlockedRegistries []string `json:"blockedRegistries,omitempty"`
// allowedRegistries are the only registries permitted for image pull and push actions. All other registries are denied.
// Each entry must be a valid registry scope in the format hostname[:port][/path],
// optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
// The hostname must consist of valid DNS labels separated by dots, where each label
// contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
// Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").
//
// Only one of BlockedRegistries or AllowedRegistries may be set.
// +optional
// +listType=atomic
// +kubebuilder:validation:items:Pattern=`^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$`
AllowedRegistries []string `json:"allowedRegistries,omitempty"`
Comment on lines 167 to 200
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Omitted behavior undocumented lists 📘 Rule violation ⚙ Maintainability

InsecureRegistries, BlockedRegistries, and AllowedRegistries are marked +optional and now
have item Pattern validation, but their comments do not document what happens when the fields are
omitted/defaulted. This violates the requirement to document optionality and omitted/default
behavior for API fields with validation markers.
Agent Prompt
## Issue description
`RegistrySources` optional list fields (`insecureRegistries`, `blockedRegistries`, `allowedRegistries`) have validation markers but their Go doc comments do not describe what happens when the field is omitted (default behavior).

## Issue Context
These fields are `+optional` and now include per-item `Pattern` validation, so the field documentation must also state omitted/default behavior in human-readable terms.

## Fix Focus Areas
- config/v1/types_image.go[167-200]

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

// containerRuntimeSearchRegistries are registries that will be searched when pulling images that do not have fully qualified
// domains in their pull specs. Registries will be searched in the order provided in the list.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,18 +129,30 @@ spec:
allowedRegistries:
description: |-
allowedRegistries are the only registries permitted for image pull and push actions. All other registries are denied.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").

Only one of BlockedRegistries or AllowedRegistries may be set.
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
blockedRegistries:
description: |-
blockedRegistries cannot be used for image pull and push actions. All other registries are permitted.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").

Only one of BlockedRegistries or AllowedRegistries may be set.
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
Expand All @@ -156,9 +168,15 @@ spec:
type: array
x-kubernetes-list-type: set
insecureRegistries:
description: insecureRegistries are registries which do not have
a valid TLS certificates or only support HTTP connections.
description: |-
insecureRegistries are registries which do not have a valid TLS certificates or only support HTTP connections.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,30 @@ spec:
allowedRegistries:
description: |-
allowedRegistries are the only registries permitted for image pull and push actions. All other registries are denied.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").

Only one of BlockedRegistries or AllowedRegistries may be set.
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
blockedRegistries:
description: |-
blockedRegistries cannot be used for image pull and push actions. All other registries are permitted.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").

Only one of BlockedRegistries or AllowedRegistries may be set.
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
Expand All @@ -139,9 +151,15 @@ spec:
type: array
x-kubernetes-list-type: set
insecureRegistries:
description: insecureRegistries are registries which do not have
a valid TLS certificates or only support HTTP connections.
description: |-
insecureRegistries are registries which do not have a valid TLS certificates or only support HTTP connections.
Each entry must be a valid registry scope in the format hostname[:port][/path],
optionally prefixed with "*." for wildcard subdomains (e.g., "*.example.com").
The hostname must consist of valid DNS labels separated by dots, where each label
contains only alphanumeric characters and hyphens and does not start or end with a hyphen.
Entries must not include tags (e.g., ":latest") or digests (e.g., "@sha256:...").
items:
pattern: ^\*(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+$|^((?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?)(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$
type: string
type: array
x-kubernetes-list-type: atomic
Expand Down
Loading