@@ -108,9 +108,9 @@ func ClusterNameValidator(name interface{}) error {
108108 if str , ok := name .(string ); ok {
109109 str := strings .Trim (str , " \t " )
110110 if ! IsValidClusterName (str ) {
111- return fmt .Errorf ("Cluster name must consist of no more than %d lowercase " +
111+ return fmt .Errorf ("cluster name must consist of no more than %d lowercase " +
112112 "alphanumeric characters or '-', start with a letter, and end with an " +
113- "alphanumeric character. " , MaxClusterNameLength )
113+ "alphanumeric character" , MaxClusterNameLength )
114114 }
115115 return nil
116116 }
@@ -125,30 +125,88 @@ func ClusterDomainPrefixValidator(domainPrefix interface{}) error {
125125 if str , ok := domainPrefix .(string ); ok {
126126 str := strings .Trim (str , " \t " )
127127 if str != "" && ! IsValidClusterDomainPrefix (str ) {
128- return fmt .Errorf ("Cluster domain prefix must consist of no more than %d lowercase " +
128+ return fmt .Errorf ("cluster domain prefix must consist of no more than %d lowercase " +
129129 "alphanumeric characters or '-', start with a letter, and end with an " +
130- "alphanumeric character. " , MaxClusterDomainPrefixLength )
130+ "alphanumeric character" , MaxClusterDomainPrefixLength )
131131 }
132132 return nil
133133 }
134134 return fmt .Errorf ("can only validate strings, got '%v'" , domainPrefix )
135135}
136136
137- func ValidateHTTPProxy (val interface {}) error {
138- if httpProxy , ok := val .(string ); ok {
139- if httpProxy == "" {
140- return nil
141- }
142- url , err := url .ParseRequestURI (httpProxy )
143- if err != nil {
144- return fmt .Errorf ("Invalid http-proxy value '%s'" , httpProxy )
137+ // validateProxyURL validates common proxy URL requirements
138+ func validateProxyURL (proxyURL string , proxyType string , expectedScheme string ) error {
139+ if strings .Contains (proxyURL , " " ) {
140+ return fmt .Errorf ("invalid %s value: URL cannot contain spaces" , proxyType )
141+ }
142+
143+ if credValidation := helper .ValidateURLCredentials (proxyURL ); credValidation .HasInvalid {
144+ return fmt .Errorf ("invalid %s value: %s contains invalid character '%c'" ,
145+ proxyType , credValidation .Field , credValidation .InvalidChar )
146+ }
147+
148+ parsedURL , err := url .Parse (proxyURL )
149+ if err != nil {
150+ return fmt .Errorf ("invalid %s value: %v" , proxyType , err )
151+ }
152+
153+ if parsedURL .Scheme == "" {
154+ return fmt .Errorf ("invalid %s value: URL scheme is missing (e.g., %s://)" , proxyType , expectedScheme )
155+ }
156+ if parsedURL .Scheme != expectedScheme {
157+ return errors .Errorf ("%s" , fmt .Sprintf ("expected %s to have an %s:// scheme" , proxyType , expectedScheme ))
158+ }
159+
160+ if parsedURL .Host == "" {
161+ return fmt .Errorf ("invalid %s value: host is missing" , proxyType )
162+ }
163+
164+ // Proxy URLs shouldn't have a path
165+ if parsedURL .Path != "" && parsedURL .Path != "/" {
166+ return fmt .Errorf ("invalid %s value: proxy URL should not contain a path" , proxyType )
167+ }
168+
169+ // Validate hostname/IP and port
170+ host , port , err := net .SplitHostPort (parsedURL .Host )
171+ if err != nil {
172+ // No port specified, just validate the host
173+ host = parsedURL .Host
174+ } else {
175+ // Validate port range (url.Parse already validated it's numeric)
176+ portNum , _ := strconv .Atoi (port )
177+ if portNum < 1 || portNum > 65535 {
178+ return fmt .Errorf ("invalid %s value: port must be between 1 and 65535" , proxyType )
145179 }
146- if url .Scheme != "http" {
147- return errors .Errorf ("%s" , "Expected http-proxy to have an http:// scheme" )
180+ }
181+
182+ // Validate host is a valid hostname or IP address
183+ if host != "" {
184+ // Check if it's an IP address
185+ if ip := net .ParseIP (host ); ip == nil {
186+ // Not an IP, check if it's a valid hostname
187+ if strings .Contains (host , "/" ) {
188+ return fmt .Errorf ("invalid %s value: invalid host" , proxyType )
189+ }
148190 }
191+ }
192+
193+ return nil
194+ }
195+
196+ func ValidateHTTPProxy (val interface {}) error {
197+ httpProxy := val .(string )
198+ if httpProxy == "" {
149199 return nil
150200 }
151- return fmt .Errorf ("can only validate strings, got '%v'" , val )
201+ return validateProxyURL (httpProxy , "http-proxy" , "http" )
202+ }
203+
204+ func ValidateHTTPSProxy (val interface {}) error {
205+ httpsProxy := val .(string )
206+ if httpsProxy == "" {
207+ return nil
208+ }
209+ return validateProxyURL (httpsProxy , "https-proxy" , "https" )
152210}
153211
154212func ValidateRegistryAdditionalCa (input map [string ]string ) error {
@@ -174,9 +232,9 @@ func ValidateAllowedRegistriesForImport(input interface{}) error {
174232 registries = strings .Split (input .(string ), "," )
175233 for _ , registry := range registries {
176234 if ! idRE .MatchString (registry ) {
177- return fmt .Errorf ("invalid identifier '%s' for 'allowed registries for import.' " +
235+ return fmt .Errorf ("invalid identifier '%s' for 'allowed registries for import'. " +
178236 "Should be in a <registry>:<boolean> format. " +
179- "The boolean indicates whether the registry is secure or not. " , registry )
237+ "The boolean indicates whether the registry is secure or not" , registry )
180238 }
181239 }
182240 case reflect .Slice :
@@ -745,7 +803,7 @@ func ValidateSubnetsCount(multiAZ bool, privateLink bool, subnetsInputCount int)
745803 if multiAZ {
746804 azPrefix = "multi-AZ"
747805 }
748- return fmt .Errorf ("The number of subnets for a '%s' '%s' should be '%d', " +
806+ return fmt .Errorf ("the number of subnets for a '%s' '%s' should be '%d', " +
749807 "instead received: '%d'" , azPrefix , clusterPrefix , expected , subnetsInputCount )
750808 }
751809 return nil
@@ -755,10 +813,10 @@ func ValidateHostedClusterSubnets(awsClient aws.Client, isPrivate bool, subnetID
755813 privateIngress bool ) (int , error ) {
756814
757815 if isPrivate && len (subnetIDs ) < 1 {
758- return 0 , fmt .Errorf ("The number of subnets for a private hosted cluster should be at least one" )
816+ return 0 , fmt .Errorf ("the number of subnets for a private hosted cluster should be at least one" )
759817 }
760818 if ! isPrivate && len (subnetIDs ) < 2 {
761- return 0 , fmt .Errorf ("The number of subnets for a public hosted cluster should be at least two" )
819+ return 0 , fmt .Errorf ("the number of subnets for a public hosted cluster should be at least two" )
762820 }
763821 vpcSubnets , vpcSubnetsErr := awsClient .GetVPCSubnets (subnetIDs [0 ])
764822 if vpcSubnetsErr != nil {
@@ -785,11 +843,11 @@ func ValidateHostedClusterSubnets(awsClient aws.Client, isPrivate bool, subnetID
785843
786844 if isPrivate && privateIngress {
787845 if publicSubnetsCount > 0 {
788- return 0 , fmt .Errorf ("The number of public subnets for a private hosted cluster should be zero" )
846+ return 0 , fmt .Errorf ("the number of public subnets for a private hosted cluster should be zero" )
789847 }
790848 } else {
791849 if publicSubnetsCount == 0 {
792- return 0 , fmt .Errorf ("Must have at least one public subnet when not using both " +
850+ return 0 , fmt .Errorf ("must have at least one public subnet when not using both " +
793851 "'private API' and 'private ingress'" )
794852 }
795853 }
@@ -1106,8 +1164,8 @@ func ValidateClaimValidationRules(input interface{}) error {
11061164 inputRules = strings .Split (input .(string ), "," )
11071165 for _ , inputRule := range inputRules {
11081166 if ! idRE .MatchString (inputRule ) {
1109- return fmt .Errorf ("invalid identifier '%s' for 'claim validation rule. ' " +
1110- "Should be in a <claim>:<required_value> format. " , inputRule )
1167+ return fmt .Errorf ("invalid identifier '%s' for 'claim validation rule'. " +
1168+ "Should be in a <claim>:<required_value> format" , inputRule )
11111169 }
11121170 }
11131171 case reflect .Slice :
0 commit comments