diff --git a/server/src/main/java/com/rocketmq/studio/cluster/k8s/CreateCertDTO.java b/server/src/main/java/com/rocketmq/studio/cluster/k8s/CreateCertDTO.java index 75044b84..4daf96aa 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/k8s/CreateCertDTO.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/k8s/CreateCertDTO.java @@ -16,6 +16,8 @@ */ package com.rocketmq.studio.cluster.k8s; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -28,10 +30,16 @@ @NoArgsConstructor @AllArgsConstructor public class CreateCertDTO { + @NotBlank(message = "name is required") private String name; + @NotBlank(message = "namespace is required") private String namespace; + @NotBlank(message = "cluster is required") private String cluster; + @NotBlank(message = "type is required") + @Pattern(regexp = "TLS|mTLS|ServiceAccount", message = "type must be one of TLS, mTLS, ServiceAccount") private String type; + @NotBlank(message = "issuer is required") private String issuer; private List san; } diff --git a/server/src/main/java/com/rocketmq/studio/cluster/k8s/DeleteCertDTO.java b/server/src/main/java/com/rocketmq/studio/cluster/k8s/DeleteCertDTO.java index e6790771..ae3f490f 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/k8s/DeleteCertDTO.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/k8s/DeleteCertDTO.java @@ -16,6 +16,7 @@ */ package com.rocketmq.studio.cluster.k8s; +import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -26,5 +27,6 @@ @NoArgsConstructor @AllArgsConstructor public class DeleteCertDTO { + @NotBlank(message = "id is required") private String id; } diff --git a/server/src/main/java/com/rocketmq/studio/cluster/k8s/K8sCertController.java b/server/src/main/java/com/rocketmq/studio/cluster/k8s/K8sCertController.java index 43bc0f8c..6aa5ae49 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/k8s/K8sCertController.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/k8s/K8sCertController.java @@ -17,6 +17,7 @@ package com.rocketmq.studio.cluster.k8s; import com.rocketmq.studio.common.domain.Result; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -39,22 +40,22 @@ public Result> listCerts() { } @PostMapping("/create") - public Result createCert(@RequestBody CreateCertDTO command) { + public Result createCert(@Valid @RequestBody CreateCertDTO command) { return Result.ok(k8sCertService.createCert(command)); } @PostMapping("/update") - public Result updateCert(@RequestBody UpdateCertDTO command) { + public Result updateCert(@Valid @RequestBody UpdateCertDTO command) { return Result.ok(k8sCertService.updateCert(command)); } @PostMapping("/renew") - public Result renewCert(@RequestBody RenewCertDTO command) { + public Result renewCert(@Valid @RequestBody RenewCertDTO command) { return Result.ok(k8sCertService.renewCert(command)); } @PostMapping("/delete") - public Result deleteCert(@RequestBody DeleteCertDTO command) { + public Result deleteCert(@Valid @RequestBody DeleteCertDTO command) { k8sCertService.deleteCert(command); return Result.ok(); } diff --git a/server/src/main/java/com/rocketmq/studio/cluster/k8s/RenewCertDTO.java b/server/src/main/java/com/rocketmq/studio/cluster/k8s/RenewCertDTO.java index d0877113..9a30924a 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/k8s/RenewCertDTO.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/k8s/RenewCertDTO.java @@ -16,6 +16,7 @@ */ package com.rocketmq.studio.cluster.k8s; +import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -26,5 +27,6 @@ @NoArgsConstructor @AllArgsConstructor public class RenewCertDTO { + @NotBlank(message = "id is required") private String id; } diff --git a/server/src/main/java/com/rocketmq/studio/cluster/k8s/UpdateCertDTO.java b/server/src/main/java/com/rocketmq/studio/cluster/k8s/UpdateCertDTO.java index f46b0a0d..c5a0dca3 100644 --- a/server/src/main/java/com/rocketmq/studio/cluster/k8s/UpdateCertDTO.java +++ b/server/src/main/java/com/rocketmq/studio/cluster/k8s/UpdateCertDTO.java @@ -16,6 +16,8 @@ */ package com.rocketmq.studio.cluster.k8s; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -28,10 +30,12 @@ @NoArgsConstructor @AllArgsConstructor public class UpdateCertDTO { + @NotBlank(message = "id is required") private String id; private String name; private String namespace; private String cluster; + @Pattern(regexp = "TLS|mTLS|ServiceAccount", message = "type must be one of TLS, mTLS, ServiceAccount") private String type; private String issuer; private List san; diff --git a/server/src/test/java/com/rocketmq/studio/cluster/k8s/K8sCertControllerTest.java b/server/src/test/java/com/rocketmq/studio/cluster/k8s/K8sCertControllerTest.java index 69cca770..ac49a161 100644 --- a/server/src/test/java/com/rocketmq/studio/cluster/k8s/K8sCertControllerTest.java +++ b/server/src/test/java/com/rocketmq/studio/cluster/k8s/K8sCertControllerTest.java @@ -33,6 +33,7 @@ import java.util.List; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; @@ -138,6 +139,89 @@ void createCertShouldAcceptMinimalCommand() throws Exception { .andExpect(jsonPath("$.data.id").value("cert-min")); } + @Test + void createCertShouldRejectMissingName() throws Exception { + mockMvc.perform(post("/api/k8s-certs/create") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "namespace": "default", + "cluster": "test-cluster", + "type": "TLS", + "issuer": "vault" + } + """)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(400)) + .andExpect(jsonPath("$.message").value("name is required")); + + verifyNoInteractions(k8sCertService); + } + + @Test + void createCertShouldRejectUnsupportedType() throws Exception { + mockMvc.perform(post("/api/k8s-certs/create") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "name": "new-cert", + "namespace": "default", + "cluster": "test-cluster", + "type": "PEM", + "issuer": "vault" + } + """)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(400)) + .andExpect(jsonPath("$.message").value("type must be one of TLS, mTLS, ServiceAccount")); + + verifyNoInteractions(k8sCertService); + } + + @Test + void updateCertShouldRejectMissingId() throws Exception { + mockMvc.perform(post("/api/k8s-certs/update") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "name": "updated-cert" + } + """)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(400)) + .andExpect(jsonPath("$.message").value("id is required")); + + verifyNoInteractions(k8sCertService); + } + + @Test + void renewCertShouldRejectBlankId() throws Exception { + mockMvc.perform(post("/api/k8s-certs/renew") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "id": " " + } + """)) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(400)) + .andExpect(jsonPath("$.message").value("id is required")); + + verifyNoInteractions(k8sCertService); + } + + @Test + void deleteCertShouldRejectMissingId() throws Exception { + mockMvc.perform(post("/api/k8s-certs/delete") + .contentType(MediaType.APPLICATION_JSON) + .content("{}")) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(400)) + .andExpect(jsonPath("$.message").value("id is required")); + + verifyNoInteractions(k8sCertService); + } + private K8sCertVO buildCert(String id, String name, CertType type, CertStatus status) { K8sCertVO cert = K8sCertVO.builder() .name(name)