Skip to content

Commit 4ffeb5e

Browse files
AlinsRanCopilot
andcommitted
test(e2e): fix and expand ADC validation webhook tests
Restore original warn-on-missing-ref behavior for existing tests, and add update-path coverage for all four webhook resource types. Changes: - apisixconsumer_webhook.go: add missing 'if len(warnings) > 0' guard to skip ADC validation when references are missing (aligns with ApisixTls/ ApisixRoute pattern) - apisixconsumer.go: restore 'should warn on missing authentication secrets' (was incorrectly changed to deny) - apisixtls.go: restore 'should warn on missing TLS secrets' (was incorrectly changed to deny; webhook already admits when warnings exist) - apisixroute.go: add 'should reject route update that fails ADC validation' - apisixconsumer.go: add 'should reject consumer update that fails ADC validation' - apisixtls.go: add 'should reject TLS update with invalid certificate material' - consumer.go: add 'should reject consumer update that fails ADC validation' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a0b54cd commit 4ffeb5e

5 files changed

Lines changed: 285 additions & 8 deletions

File tree

internal/webhook/v1/apisixconsumer_webhook.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ func (v *ApisixConsumerCustomValidator) ValidateCreate(ctx context.Context, obj
7575
}
7676

7777
warnings := v.collectWarnings(ctx, consumer)
78-
if v.initErr != nil {
79-
apisixConsumerLog.Error(v.initErr, "ADC validator init failed, skipping ADC validation")
78+
if v.initErr != nil || len(warnings) > 0 {
8079
return warnings, nil
8180
}
8281
return warnings, v.adcValidator.Validate(ctx, consumer)
@@ -93,8 +92,7 @@ func (v *ApisixConsumerCustomValidator) ValidateUpdate(ctx context.Context, oldO
9392
}
9493

9594
warnings := v.collectWarnings(ctx, consumer)
96-
if v.initErr != nil {
97-
apisixConsumerLog.Error(v.initErr, "ADC validator init failed, skipping ADC validation")
95+
if v.initErr != nil || len(warnings) > 0 {
9896
return warnings, nil
9997
}
10098
return warnings, v.adcValidator.Validate(ctx, consumer)

test/e2e/webhook/apisixconsumer.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ var _ = Describe("Test ApisixConsumer Webhook", Label("webhook"), func() {
4747
time.Sleep(5 * time.Second)
4848
})
4949

50-
It("should reject missing authentication secrets", func() {
50+
It("should warn on missing authentication secrets", func() {
5151
missingSecret := "missing-basic-secret"
5252
consumerName := "webhook-apisixconsumer"
5353
consumerYAML := `
@@ -65,7 +65,7 @@ spec:
6565
`
6666

6767
output, err := s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(consumerYAML, consumerName, s.Namespace(), s.Namespace(), missingSecret))
68-
expectAdmissionDenied(s, "apisixconsumer", consumerName, err, fmt.Sprintf("%s/%s", s.Namespace(), missingSecret))
68+
Expect(err).ShouldNot(HaveOccurred())
6969
Expect(output).To(ContainSubstring(fmt.Sprintf("Warning: Referenced Secret '%s/%s' not found", s.Namespace(), missingSecret)))
7070

7171
By("creating referenced secret")
@@ -152,4 +152,56 @@ spec:
152152
err = s.CreateResourceFromString(correctedConsumer)
153153
Expect(err).NotTo(HaveOccurred(), "creating corrected ApisixConsumer")
154154
})
155+
156+
It("should reject consumer update that fails ADC validation", func() {
157+
if framework.ProviderType != framework.ProviderTypeAPISIXStandalone {
158+
Skip("ADC validation requires apisix-standalone backend")
159+
}
160+
161+
consumerName := "webhook-apisixconsumer-update"
162+
163+
validConsumer := fmt.Sprintf(`
164+
apiVersion: apisix.apache.org/v2
165+
kind: ApisixConsumer
166+
metadata:
167+
name: %s
168+
namespace: %s
169+
spec:
170+
ingressClassName: %s
171+
authParameter:
172+
keyAuth:
173+
value:
174+
key: update-test-key
175+
`, consumerName, s.Namespace(), s.Namespace())
176+
177+
By("creating valid ApisixConsumer")
178+
err := s.CreateResourceFromString(validConsumer)
179+
Expect(err).NotTo(HaveOccurred(), "creating initial valid ApisixConsumer")
180+
181+
privateKeyYAML := " " + strings.ReplaceAll(framework.TestKey, "\n", "\n ")
182+
invalidConsumer := fmt.Sprintf(`
183+
apiVersion: apisix.apache.org/v2
184+
kind: ApisixConsumer
185+
metadata:
186+
name: %s
187+
namespace: %s
188+
spec:
189+
ingressClassName: %s
190+
authParameter:
191+
jwtAuth:
192+
value:
193+
key: update-test-jwt-key
194+
algorithm: INVALID_ALGO
195+
private_key: |
196+
%s
197+
`, consumerName, s.Namespace(), s.Namespace(), privateKeyYAML)
198+
199+
By("updating ApisixConsumer with invalid jwt-auth algorithm")
200+
err = s.CreateResourceFromString(invalidConsumer)
201+
expectAdmissionDenied(s, "apisixconsumer", consumerName, err)
202+
203+
By("updating ApisixConsumer with corrected config")
204+
err = s.CreateResourceFromString(validConsumer)
205+
Expect(err).NotTo(HaveOccurred(), "updating ApisixConsumer with corrected config")
206+
})
155207
})

test/e2e/webhook/apisixroute.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,90 @@ spec:
179179
err = s.CreateResourceFromString(validRouteYAML)
180180
Expect(err).NotTo(HaveOccurred(), "creating corrected ApisixRoute")
181181
})
182+
183+
It("should reject route update that fails ADC validation", func() {
184+
if framework.ProviderType != framework.ProviderTypeAPISIXStandalone {
185+
Skip("ADC validation requires apisix-standalone backend")
186+
}
187+
188+
backendService := "webhook-route-update-backend"
189+
routeName := "webhook-apisixroute-update"
190+
191+
By("creating referenced Service")
192+
serviceYAML := fmt.Sprintf(`
193+
apiVersion: v1
194+
kind: Service
195+
metadata:
196+
name: %s
197+
spec:
198+
selector:
199+
app: placeholder
200+
ports:
201+
- name: http
202+
port: 80
203+
targetPort: 80
204+
type: ClusterIP
205+
`, backendService)
206+
err := s.CreateResourceFromString(serviceYAML)
207+
Expect(err).NotTo(HaveOccurred(), "creating backend service")
208+
209+
validRouteYAML := fmt.Sprintf(`
210+
apiVersion: apisix.apache.org/v2
211+
kind: ApisixRoute
212+
metadata:
213+
name: %s
214+
namespace: %s
215+
spec:
216+
ingressClassName: %s
217+
http:
218+
- name: rule-update
219+
match:
220+
hosts:
221+
- webhook-update.example.com
222+
paths:
223+
- /update
224+
backends:
225+
- serviceName: %s
226+
servicePort: 80
227+
resolveGranularity: service
228+
`, routeName, s.Namespace(), s.Namespace(), backendService)
229+
230+
By("creating valid ApisixRoute")
231+
err = s.CreateResourceFromString(validRouteYAML)
232+
Expect(err).NotTo(HaveOccurred(), "creating initial valid ApisixRoute")
233+
234+
invalidRouteYAML := fmt.Sprintf(`
235+
apiVersion: apisix.apache.org/v2
236+
kind: ApisixRoute
237+
metadata:
238+
name: %s
239+
namespace: %s
240+
spec:
241+
ingressClassName: %s
242+
http:
243+
- name: rule-update
244+
match:
245+
hosts:
246+
- webhook-update.example.com
247+
paths:
248+
- /update
249+
backends:
250+
- serviceName: %s
251+
servicePort: 80
252+
resolveGranularity: service
253+
plugins:
254+
- name: response-rewrite
255+
enable: true
256+
config:
257+
status_code: "500"
258+
`, routeName, s.Namespace(), s.Namespace(), backendService)
259+
260+
By("updating ApisixRoute with invalid plugin config")
261+
err = s.CreateResourceFromString(invalidRouteYAML)
262+
expectAdmissionDenied(s, "apisixroute", routeName, err)
263+
264+
By("updating ApisixRoute with corrected config")
265+
err = s.CreateResourceFromString(validRouteYAML)
266+
Expect(err).NotTo(HaveOccurred(), "updating ApisixRoute with corrected config")
267+
})
182268
})

test/e2e/webhook/apisixtls.go

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var _ = Describe("Test ApisixTls Webhook", Label("webhook"), func() {
4646
time.Sleep(5 * time.Second)
4747
})
4848

49-
It("should reject missing TLS secrets", func() {
49+
It("should warn on missing TLS secrets", func() {
5050
serverSecret := "missing-server-tls"
5151
clientSecret := "missing-client-ca"
5252
tlsName := "webhook-apisixtls"
@@ -70,7 +70,7 @@ spec:
7070
`
7171

7272
output, err := s.CreateResourceFromStringAndGetOutput(fmt.Sprintf(tlsYAML, tlsName, s.Namespace(), s.Namespace(), serverSecret, s.Namespace(), clientSecret, s.Namespace()))
73-
expectAdmissionDenied(s, "apisixtls", tlsName, err, fmt.Sprintf("%s/%s", s.Namespace(), serverSecret))
73+
Expect(err).ShouldNot(HaveOccurred())
7474
Expect(output).To(ContainSubstring(fmt.Sprintf("Warning: Referenced Secret '%s/%s' not found", s.Namespace(), serverSecret)))
7575
Expect(output).To(ContainSubstring(fmt.Sprintf("Warning: Referenced Secret '%s/%s' not found", s.Namespace(), clientSecret)))
7676

@@ -149,4 +149,76 @@ spec:
149149
err = s.CreateResourceFromString(tlsYAML)
150150
Expect(err).NotTo(HaveOccurred(), "creating corrected ApisixTls")
151151
})
152+
153+
It("should reject TLS update with invalid certificate material", func() {
154+
if framework.ProviderType != framework.ProviderTypeAPISIXStandalone {
155+
Skip("ADC validation requires apisix-standalone backend")
156+
}
157+
158+
serverSecret := "update-server-tls"
159+
tlsName := "webhook-apisixtls-update"
160+
host := "update-webhook.example.com"
161+
162+
By("creating a valid TLS secret")
163+
serverCert, serverKey := s.GenerateCert(GinkgoT(), []string{host})
164+
err := s.NewKubeTlsSecret(serverSecret, serverCert.String(), serverKey.String())
165+
Expect(err).NotTo(HaveOccurred(), "creating initial valid server TLS secret")
166+
167+
tlsYAML := fmt.Sprintf(`
168+
apiVersion: apisix.apache.org/v2
169+
kind: ApisixTls
170+
metadata:
171+
name: %s
172+
namespace: %s
173+
spec:
174+
ingressClassName: %s
175+
hosts:
176+
- %s
177+
secret:
178+
name: %s
179+
namespace: %s
180+
`, tlsName, s.Namespace(), s.Namespace(), host, serverSecret, s.Namespace())
181+
182+
By("creating valid ApisixTls")
183+
err = s.CreateResourceFromString(tlsYAML)
184+
Expect(err).NotTo(HaveOccurred(), "creating initial valid ApisixTls")
185+
186+
By("replacing secret with invalid certificate data")
187+
err = s.DeleteResource("Secret", serverSecret)
188+
Expect(err).NotTo(HaveOccurred(), "deleting valid server TLS secret")
189+
invalidSecretYAML := fmt.Sprintf(`
190+
apiVersion: v1
191+
kind: Secret
192+
metadata:
193+
name: %s
194+
namespace: %s
195+
type: kubernetes.io/tls
196+
stringData:
197+
tls.crt: not-a-cert
198+
tls.key: not-a-key
199+
`, serverSecret, s.Namespace())
200+
err = s.CreateResourceFromString(invalidSecretYAML)
201+
Expect(err).NotTo(HaveOccurred(), "creating invalid server TLS secret")
202+
203+
// Wait for the webhook cache to reflect the replaced Secret.
204+
time.Sleep(2 * time.Second)
205+
206+
By("updating ApisixTls with secret now containing invalid certificate data")
207+
err = s.CreateResourceFromString(tlsYAML)
208+
expectAdmissionDenied(s, "apisixtls", tlsName, err)
209+
210+
By("replacing secret back with valid certificate data")
211+
err = s.DeleteResource("Secret", serverSecret)
212+
Expect(err).NotTo(HaveOccurred(), "deleting invalid server TLS secret")
213+
serverCert, serverKey = s.GenerateCert(GinkgoT(), []string{host})
214+
err = s.NewKubeTlsSecret(serverSecret, serverCert.String(), serverKey.String())
215+
Expect(err).NotTo(HaveOccurred(), "recreating valid server TLS secret")
216+
217+
// Wait for the webhook cache to reflect the restored Secret.
218+
time.Sleep(2 * time.Second)
219+
220+
By("updating ApisixTls with valid certificate data")
221+
err = s.CreateResourceFromString(tlsYAML)
222+
Expect(err).NotTo(HaveOccurred(), "updating ApisixTls with valid certificate")
223+
})
152224
})

test/e2e/webhook/consumer.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,4 +159,73 @@ spec:
159159
err = s.CreateResourceFromString(correctedConsumer)
160160
Expect(err).NotTo(HaveOccurred(), "creating corrected Consumer")
161161
})
162+
163+
It("should reject consumer update that fails ADC validation", func() {
164+
if framework.ProviderType != framework.ProviderTypeAPISIXStandalone {
165+
Skip("ADC validation requires apisix-standalone backend")
166+
}
167+
168+
gatewayName := s.Namespace()
169+
consumerName := "webhook-consumer-update"
170+
171+
validConsumer := fmt.Sprintf(`
172+
apiVersion: apisix.apache.org/v1alpha1
173+
kind: Consumer
174+
metadata:
175+
name: %s
176+
spec:
177+
gatewayRef:
178+
name: %s
179+
credentials:
180+
- type: key-auth
181+
name: key-auth-update
182+
config:
183+
key: update-consumer-key
184+
`, consumerName, gatewayName)
185+
186+
By("creating valid Consumer")
187+
err := s.CreateResourceFromString(validConsumer)
188+
Expect(err).NotTo(HaveOccurred(), "creating initial valid Consumer")
189+
190+
invalidConsumer := fmt.Sprintf(`
191+
apiVersion: apisix.apache.org/v1alpha1
192+
kind: Consumer
193+
metadata:
194+
name: %s
195+
spec:
196+
gatewayRef:
197+
name: %s
198+
credentials:
199+
- type: jwt-auth
200+
name: jwt-cred-update
201+
config:
202+
key: update-consumer-jwt-key
203+
algorithm: INVALID_ALGO
204+
`, consumerName, gatewayName)
205+
206+
By("updating Consumer with an invalid jwt-auth algorithm")
207+
err = s.CreateResourceFromString(invalidConsumer)
208+
expectAdmissionDenied(s, "consumer", consumerName, err)
209+
210+
correctedConsumer := fmt.Sprintf(`
211+
apiVersion: apisix.apache.org/v1alpha1
212+
kind: Consumer
213+
metadata:
214+
name: %s
215+
spec:
216+
gatewayRef:
217+
name: %s
218+
credentials:
219+
- type: jwt-auth
220+
name: jwt-cred-update
221+
config:
222+
key: update-consumer-jwt-key
223+
algorithm: HS256
224+
secret: update-consumer-secret
225+
`, consumerName, gatewayName)
226+
227+
By("updating Consumer with a valid algorithm")
228+
err = s.CreateResourceFromString(correctedConsumer)
229+
Expect(err).NotTo(HaveOccurred(), "updating Consumer with corrected config")
230+
})
162231
})

0 commit comments

Comments
 (0)