From 011501df130380897b82f8aa045201e295d5f6c9 Mon Sep 17 00:00:00 2001 From: sangkenlee Date: Thu, 28 Mar 2024 01:39:31 +0900 Subject: [PATCH] =?UTF-8?q?Organization=20Template=20API=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- internal/delivery/api/endpoint.go | 26 +- .../delivery/api/generated_endpoints.go.go | 156 ++-- internal/delivery/http/policy-template.go | 813 ++++++++++++++++-- internal/delivery/http/policy.go | 3 +- internal/delivery/http/role.go | 2 +- internal/model/permission.go | 26 +- internal/model/policy-template.go | 29 +- internal/repository/policy-template.go | 94 +- internal/route/route.go | 13 + internal/usecase/policy-template.go | 266 ++++-- internal/usecase/policy.go | 26 +- pkg/domain/admin/policy-template.go | 179 ++++ pkg/domain/policy-template.go | 143 +-- pkg/domain/policy.go | 1 - pkg/httpErrors/errorCode.go | 23 +- 16 files changed, 1425 insertions(+), 377 deletions(-) create mode 100644 pkg/domain/admin/policy-template.go diff --git a/go.mod b/go.mod index 92db160f..92a6c021 100644 --- a/go.mod +++ b/go.mod @@ -48,6 +48,7 @@ require ( gorm.io/gorm v1.25.7 goyave.dev/goyave/v4 v4.4.11 k8s.io/api v0.26.1 + k8s.io/apiextensions-apiserver v0.26.1 k8s.io/apimachinery v0.26.4 k8s.io/client-go v0.26.1 k8s.io/utils v0.0.0-20221128185143-99ec85e7a448 @@ -138,7 +139,6 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gorm.io/driver/mysql v1.5.0 // indirect - k8s.io/apiextensions-apiserver v0.26.1 // indirect k8s.io/component-base v0.26.1 // indirect k8s.io/klog/v2 v2.80.1 // indirect k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect diff --git a/internal/delivery/api/endpoint.go b/internal/delivery/api/endpoint.go index b69a561d..6c04b1f9 100644 --- a/internal/delivery/api/endpoint.go +++ b/internal/delivery/api/endpoint.go @@ -243,19 +243,19 @@ const ( ExistsPolicyName // OrganizationPolicyTemplate - ListOrganizationPolicyTemplate - CreateOrganizationPolicyTemplate - DeleteOrganizationPolicyTemplate - GetOrganizationPolicyTemplate - UpdateOrganizationPolicyTemplate - GetOrganizationPolicyTemplateDeploy - ListOrganizationPolicyTemplateStatistics - ListOrganizationPolicyTemplateVersions - CreateOrganizationPolicyTemplateVersion - DeleteOrganizationPolicyTemplateVersion - GetOrganizationPolicyTemplateVersion - ExistsOrganizationPolicyTemplateKind - ExistsOrganizationPolicyTemplateName + ListPolicyTemplate + CreatePolicyTemplate + DeletePolicyTemplate + GetPolicyTemplate + UpdatePolicyTemplate + GetPolicyTemplateDeploy + ListPolicyTemplateStatistics + ListPolicyTemplateVersions + CreatePolicyTemplateVersion + DeletePolicyTemplateVersion + GetPolicyTemplateVersion + ExistsPolicyTemplateKind + ExistsPolicyTemplateName // PolicyTemplateExample ListPolicyTemplateExample diff --git a/internal/delivery/api/generated_endpoints.go.go b/internal/delivery/api/generated_endpoints.go.go index 1af52d51..03298848 100644 --- a/internal/delivery/api/generated_endpoints.go.go +++ b/internal/delivery/api/generated_endpoints.go.go @@ -739,56 +739,56 @@ var ApiMap = map[Endpoint]EndpointInfo{ Name: "ExistsPolicyName", Group: "Policy", }, - ListOrganizationPolicyTemplate: { - Name: "ListOrganizationPolicyTemplate", + ListPolicyTemplate: { + Name: "ListPolicyTemplate", Group: "OrganizationPolicyTemplate", }, - CreateOrganizationPolicyTemplate: { - Name: "CreateOrganizationPolicyTemplate", + CreatePolicyTemplate: { + Name: "CreatePolicyTemplate", Group: "OrganizationPolicyTemplate", }, - DeleteOrganizationPolicyTemplate: { - Name: "DeleteOrganizationPolicyTemplate", + DeletePolicyTemplate: { + Name: "DeletePolicyTemplate", Group: "OrganizationPolicyTemplate", }, - GetOrganizationPolicyTemplate: { - Name: "GetOrganizationPolicyTemplate", + GetPolicyTemplate: { + Name: "GetPolicyTemplate", Group: "OrganizationPolicyTemplate", }, - UpdateOrganizationPolicyTemplate: { - Name: "UpdateOrganizationPolicyTemplate", + UpdatePolicyTemplate: { + Name: "UpdatePolicyTemplate", Group: "OrganizationPolicyTemplate", }, - GetOrganizationPolicyTemplateDeploy: { - Name: "GetOrganizationPolicyTemplateDeploy", + GetPolicyTemplateDeploy: { + Name: "GetPolicyTemplateDeploy", Group: "OrganizationPolicyTemplate", }, - ListOrganizationPolicyTemplateStatistics: { - Name: "ListOrganizationPolicyTemplateStatistics", + ListPolicyTemplateStatistics: { + Name: "ListPolicyTemplateStatistics", Group: "OrganizationPolicyTemplate", }, - ListOrganizationPolicyTemplateVersions: { - Name: "ListOrganizationPolicyTemplateVersions", + ListPolicyTemplateVersions: { + Name: "ListPolicyTemplateVersions", Group: "OrganizationPolicyTemplate", }, - CreateOrganizationPolicyTemplateVersion: { - Name: "CreateOrganizationPolicyTemplateVersion", + CreatePolicyTemplateVersion: { + Name: "CreatePolicyTemplateVersion", Group: "OrganizationPolicyTemplate", }, - DeleteOrganizationPolicyTemplateVersion: { - Name: "DeleteOrganizationPolicyTemplateVersion", + DeletePolicyTemplateVersion: { + Name: "DeletePolicyTemplateVersion", Group: "OrganizationPolicyTemplate", }, - GetOrganizationPolicyTemplateVersion: { - Name: "GetOrganizationPolicyTemplateVersion", + GetPolicyTemplateVersion: { + Name: "GetPolicyTemplateVersion", Group: "OrganizationPolicyTemplate", }, - ExistsOrganizationPolicyTemplateKind: { - Name: "ExistsOrganizationPolicyTemplateKind", + ExistsPolicyTemplateKind: { + Name: "ExistsPolicyTemplateKind", Group: "OrganizationPolicyTemplate", }, - ExistsOrganizationPolicyTemplateName: { - Name: "ExistsOrganizationPolicyTemplateName", + ExistsPolicyTemplateName: { + Name: "ExistsPolicyTemplateName", Group: "OrganizationPolicyTemplate", }, ListPolicyTemplateExample: { @@ -1182,32 +1182,32 @@ func (e Endpoint) String() string { return "UpdatePolicyTargetClusters" case ExistsPolicyName: return "ExistsPolicyName" - case ListOrganizationPolicyTemplate: - return "ListOrganizationPolicyTemplate" - case CreateOrganizationPolicyTemplate: - return "CreateOrganizationPolicyTemplate" - case DeleteOrganizationPolicyTemplate: - return "DeleteOrganizationPolicyTemplate" - case GetOrganizationPolicyTemplate: - return "GetOrganizationPolicyTemplate" - case UpdateOrganizationPolicyTemplate: - return "UpdateOrganizationPolicyTemplate" - case GetOrganizationPolicyTemplateDeploy: - return "GetOrganizationPolicyTemplateDeploy" - case ListOrganizationPolicyTemplateStatistics: - return "ListOrganizationPolicyTemplateStatistics" - case ListOrganizationPolicyTemplateVersions: - return "ListOrganizationPolicyTemplateVersions" - case CreateOrganizationPolicyTemplateVersion: - return "CreateOrganizationPolicyTemplateVersion" - case DeleteOrganizationPolicyTemplateVersion: - return "DeleteOrganizationPolicyTemplateVersion" - case GetOrganizationPolicyTemplateVersion: - return "GetOrganizationPolicyTemplateVersion" - case ExistsOrganizationPolicyTemplateKind: - return "ExistsOrganizationPolicyTemplateKind" - case ExistsOrganizationPolicyTemplateName: - return "ExistsOrganizationPolicyTemplateName" + case ListPolicyTemplate: + return "ListPolicyTemplate" + case CreatePolicyTemplate: + return "CreatePolicyTemplate" + case DeletePolicyTemplate: + return "DeletePolicyTemplate" + case GetPolicyTemplate: + return "GetPolicyTemplate" + case UpdatePolicyTemplate: + return "UpdatePolicyTemplate" + case GetPolicyTemplateDeploy: + return "GetPolicyTemplateDeploy" + case ListPolicyTemplateStatistics: + return "ListPolicyTemplateStatistics" + case ListPolicyTemplateVersions: + return "ListPolicyTemplateVersions" + case CreatePolicyTemplateVersion: + return "CreatePolicyTemplateVersion" + case DeletePolicyTemplateVersion: + return "DeletePolicyTemplateVersion" + case GetPolicyTemplateVersion: + return "GetPolicyTemplateVersion" + case ExistsPolicyTemplateKind: + return "ExistsPolicyTemplateKind" + case ExistsPolicyTemplateName: + return "ExistsPolicyTemplateName" case ListPolicyTemplateExample: return "ListPolicyTemplateExample" case GetPolicyTemplateExample: @@ -1592,32 +1592,32 @@ func GetEndpoint(name string) Endpoint { return UpdatePolicyTargetClusters case "ExistsPolicyName": return ExistsPolicyName - case "ListOrganizationPolicyTemplate": - return ListOrganizationPolicyTemplate - case "CreateOrganizationPolicyTemplate": - return CreateOrganizationPolicyTemplate - case "DeleteOrganizationPolicyTemplate": - return DeleteOrganizationPolicyTemplate - case "GetOrganizationPolicyTemplate": - return GetOrganizationPolicyTemplate - case "UpdateOrganizationPolicyTemplate": - return UpdateOrganizationPolicyTemplate - case "GetOrganizationPolicyTemplateDeploy": - return GetOrganizationPolicyTemplateDeploy - case "ListOrganizationPolicyTemplateStatistics": - return ListOrganizationPolicyTemplateStatistics - case "ListOrganizationPolicyTemplateVersions": - return ListOrganizationPolicyTemplateVersions - case "CreateOrganizationPolicyTemplateVersion": - return CreateOrganizationPolicyTemplateVersion - case "DeleteOrganizationPolicyTemplateVersion": - return DeleteOrganizationPolicyTemplateVersion - case "GetOrganizationPolicyTemplateVersion": - return GetOrganizationPolicyTemplateVersion - case "ExistsOrganizationPolicyTemplateKind": - return ExistsOrganizationPolicyTemplateKind - case "ExistsOrganizationPolicyTemplateName": - return ExistsOrganizationPolicyTemplateName + case "ListPolicyTemplate": + return ListPolicyTemplate + case "CreatePolicyTemplate": + return CreatePolicyTemplate + case "DeletePolicyTemplate": + return DeletePolicyTemplate + case "GetPolicyTemplate": + return GetPolicyTemplate + case "UpdatePolicyTemplate": + return UpdatePolicyTemplate + case "GetPolicyTemplateDeploy": + return GetPolicyTemplateDeploy + case "ListPolicyTemplateStatistics": + return ListPolicyTemplateStatistics + case "ListPolicyTemplateVersions": + return ListPolicyTemplateVersions + case "CreatePolicyTemplateVersion": + return CreatePolicyTemplateVersion + case "DeletePolicyTemplateVersion": + return DeletePolicyTemplateVersion + case "GetPolicyTemplateVersion": + return GetPolicyTemplateVersion + case "ExistsPolicyTemplateKind": + return ExistsPolicyTemplateKind + case "ExistsPolicyTemplateName": + return ExistsPolicyTemplateName case "ListPolicyTemplateExample": return ListPolicyTemplateExample case "GetPolicyTemplateExample": diff --git a/internal/delivery/http/policy-template.go b/internal/delivery/http/policy-template.go index bc66d83b..c2ad3479 100644 --- a/internal/delivery/http/policy-template.go +++ b/internal/delivery/http/policy-template.go @@ -6,13 +6,15 @@ import ( "strconv" "strings" + "github.com/openinfradev/tks-api/pkg/domain" + admin_domain "github.com/openinfradev/tks-api/pkg/domain/admin" + "github.com/google/uuid" "github.com/gorilla/mux" "github.com/openinfradev/tks-api/internal/model" "github.com/openinfradev/tks-api/internal/pagination" "github.com/openinfradev/tks-api/internal/serializer" "github.com/openinfradev/tks-api/internal/usecase" - "github.com/openinfradev/tks-api/pkg/domain" "github.com/openinfradev/tks-api/pkg/httpErrors" "github.com/openinfradev/tks-api/pkg/log" @@ -37,6 +39,21 @@ type IPolicyTemplateHandler interface { Admin_GetPolicyTemplateVersion(w http.ResponseWriter, r *http.Request) Admin_DeletePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) Admin_ListPolicyTemplateVersions(w http.ResponseWriter, r *http.Request) + + CreatePolicyTemplate(w http.ResponseWriter, r *http.Request) + UpdatePolicyTemplate(w http.ResponseWriter, r *http.Request) + DeletePolicyTemplate(w http.ResponseWriter, r *http.Request) + GetPolicyTemplate(w http.ResponseWriter, r *http.Request) + ListPolicyTemplate(w http.ResponseWriter, r *http.Request) + ExistsPolicyTemplateName(w http.ResponseWriter, r *http.Request) + ExistsPolicyTemplateKind(w http.ResponseWriter, r *http.Request) + ListPolicyTemplateStatistics(w http.ResponseWriter, r *http.Request) + GetPolicyTemplateDeploy(w http.ResponseWriter, r *http.Request) + CreatePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) + GetPolicyTemplateVersion(w http.ResponseWriter, r *http.Request) + DeletePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) + ListPolicyTemplateVersions(w http.ResponseWriter, r *http.Request) + RegoCompile(w http.ResponseWriter, r *http.Request) } @@ -49,16 +66,16 @@ func NewPolicyTemplateHandler(u usecase.Usecase) IPolicyTemplateHandler { // Admin_CreatePolicyTemplate godoc // // @Tags PolicyTemplate -// @Summary [CreatePolicyTemplate] 정책 템플릿 신규 생성 +// @Summary [Admin_CreatePolicyTemplate] 정책 템플릿 신규 생성 // @Description 정책 템플릿을 신규 생성(v1.0.0을 생성)한다. // @Accept json // @Produce json -// @Param body body domain.CreatePolicyTemplateRequest true "create policy template request" -// @Success 200 {object} domain.CreatePolicyTemplateReponse +// @Param body body admin_domain.CreatePolicyTemplateRequest true "create policy template request" +// @Success 200 {object} admin_domain.CreatePolicyTemplateReponse // @Router /admin/policy-templates [post] // @Security JWT func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplate(w http.ResponseWriter, r *http.Request) { - input := domain.CreatePolicyTemplateRequest{} + input := admin_domain.CreatePolicyTemplateRequest{} err := UnmarshalRequestInput(r, &input) @@ -72,13 +89,15 @@ func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplate(w http.ResponseWriter log.Info(r.Context(), err) } + dto.Type = "tks" + policyTemplateId, err := h.usecase.Create(r.Context(), dto) if err != nil { ErrorJSON(w, r, err) return } - var out domain.CreatePolicyTemplateReponse + var out admin_domain.CreatePolicyTemplateReponse out.ID = policyTemplateId.String() ResponseJSON(w, r, http.StatusOK, out) @@ -87,12 +106,12 @@ func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplate(w http.ResponseWriter // Admin_UpdatePolicyTemplate godoc // // @Tags PolicyTemplate -// @Summary [UpdatePolicyTemplate] 정책 템플릿 업데이트 +// @Summary [Admin_UpdatePolicyTemplate] 정책 템플릿 업데이트 // @Description 정책 템플릿의 업데이트 가능한 필드들을 업데이트한다. // @Accept json // @Produce json -// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Param body body domain.UpdatePolicyTemplateRequest true "update policy template request" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param body body admin_domain.UpdatePolicyTemplateRequest true "update policy template request" // @Success 200 {object} nil // @Router /admin/policy-templates/{policyTemplateId} [patch] // @Security JWT @@ -111,7 +130,7 @@ func (h *PolicyTemplateHandler) Admin_UpdatePolicyTemplate(w http.ResponseWriter return } - input := domain.UpdatePolicyTemplateRequest{} + input := admin_domain.UpdatePolicyTemplateRequest{} err = UnmarshalRequestInput(r, &input) @@ -121,7 +140,7 @@ func (h *PolicyTemplateHandler) Admin_UpdatePolicyTemplate(w http.ResponseWriter return } - err = h.usecase.Update(r.Context(), id, input.TemplateName, input.Description, input.Severity, input.Deprecated, input.PermittedOrganizationIds) + err = h.usecase.Update(r.Context(), nil, id, input.TemplateName, input.Description, input.Severity, input.Deprecated, input.PermittedOrganizationIds) if err != nil { log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) @@ -140,7 +159,7 @@ func (h *PolicyTemplateHandler) Admin_UpdatePolicyTemplate(w http.ResponseWriter // Admin_DeletePolicyTemplate godoc // // @Tags PolicyTemplate -// @Summary [DeletePolicyTemplate] 정책 템플릿 삭제 +// @Summary [Admin_DeletePolicyTemplate] 정책 템플릿 삭제 // @Description 정책 템플릿을 삭제한다. // @Accept json // @Produce json @@ -168,7 +187,7 @@ func (h *PolicyTemplateHandler) Admin_DeletePolicyTemplate(w http.ResponseWriter return } - err = h.usecase.Delete(r.Context(), id) + err = h.usecase.Delete(r.Context(), nil, id) if err != nil { log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) @@ -187,12 +206,12 @@ func (h *PolicyTemplateHandler) Admin_DeletePolicyTemplate(w http.ResponseWriter // Admin_GetPolicyTemplate godoc // // @Tags PolicyTemplate -// @Summary [GetPolicyTemplate] 정책 템플릿 조회(최신 버전) +// @Summary [Admin_GetPolicyTemplate] 정책 템플릿 조회(최신 버전) // @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. // @Accept json // @Produce json // @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Success 200 {object} domain.GetPolicyTemplateResponse +// @Success 200 {object} admin_domain.GetPolicyTemplateResponse // @Router /admin/policy-templates/{policyTemplateId} [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_GetPolicyTemplate(w http.ResponseWriter, r *http.Request) { @@ -215,7 +234,7 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplate(w http.ResponseWriter, r return } - policyTemplate, err := h.usecase.Get(r.Context(), id) + policyTemplate, err := h.usecase.Get(r.Context(), nil, id) if err != nil { log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { @@ -232,7 +251,7 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplate(w http.ResponseWriter, r return } - var out domain.GetPolicyTemplateResponse + var out admin_domain.GetPolicyTemplateResponse if err = serializer.Map(r.Context(), *policyTemplate, &out.PolicyTemplate); err != nil { log.Error(r.Context(), err) } @@ -247,16 +266,16 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplate(w http.ResponseWriter, r // Admin_ListPolicyTemplate godoc // // @Tags PolicyTemplate -// @Summary [ListPolicyTemplate] 정책 템플릿 목록 조회 +// @Summary [Admin_ListPolicyTemplate] 정책 템플릿 목록 조회 // @Description 정책 템플릿 목록을 조회한다. 정책 템플릿 목록 조회 결과는 최신 템플릿 버전 목록만 조회된다. // @Accept json // @Produce json // @Param limit query string false "pageSize" // @Param page query string false "pageNumber" -// @Param soertColumn query string false "sortColumn" +// @Param sortColumn query string false "sortColumn" // @Param sortOrder query string false "sortOrder" // @Param filters query []string false "filters" -// @Success 200 {object} domain.ListPolicyTemplateResponse +// @Success 200 {object} admin_domain.ListPolicyTemplateResponse // @Router /admin/policy-templates [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_ListPolicyTemplate(w http.ResponseWriter, r *http.Request) { @@ -264,14 +283,14 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplate(w http.ResponseWriter, pg := pagination.NewPagination(&urlParams) - policyTemplates, err := h.usecase.Fetch(r.Context(), pg) + policyTemplates, err := h.usecase.Fetch(r.Context(), nil, pg) if err != nil { ErrorJSON(w, r, err) return } - var out domain.ListPolicyTemplateResponse - out.PolicyTemplates = make([]domain.PolicyTemplateResponse, len(policyTemplates)) + var out admin_domain.ListPolicyTemplateResponse + out.PolicyTemplates = make([]admin_domain.PolicyTemplateResponse, len(policyTemplates)) for i, policyTemplate := range policyTemplates { if err := serializer.Map(r.Context(), policyTemplate, &out.PolicyTemplates[i]); err != nil { log.Info(r.Context(), err) @@ -293,12 +312,12 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplate(w http.ResponseWriter, // Admin_ListPolicyTemplateVersions godoc // // @Tags PolicyTemplate -// @Summary [ListPolicyTemplateVersions] 정책 템플릿 버전목록 조회 +// @Summary [Admin_ListPolicyTemplateVersions] 정책 템플릿 버전목록 조회 // @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. // @Accept json // @Produce json // @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Success 200 {object} domain.ListPolicyTemplateVersionsResponse +// @Success 200 {object} admin_domain.ListPolicyTemplateVersionsResponse // @Router /admin/policy-templates/{policyTemplateId}/versions [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateVersions(w http.ResponseWriter, r *http.Request) { @@ -317,7 +336,7 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateVersions(w http.Response return } - policyTemplateVersions, err := h.usecase.ListPolicyTemplateVersions(r.Context(), id) + policyTemplateVersions, err := h.usecase.ListPolicyTemplateVersions(r.Context(), nil, id) if err != nil { log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) @@ -330,7 +349,7 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateVersions(w http.Response return } - var out domain.ListPolicyTemplateVersionsResponse + var out admin_domain.ListPolicyTemplateVersionsResponse if err = serializer.Map(r.Context(), *policyTemplateVersions, &out); err != nil { log.Error(r.Context(), err) } @@ -341,17 +360,17 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateVersions(w http.Response // Admin_ListPolicyTemplateStatistics godoc // // @Tags PolicyTemplate -// @Summary [ListPolicyTemplateStatistics] 정책 템플릿 사용 카운트 조회 +// @Summary [Admin_ListPolicyTemplateStatistics] 정책 템플릿 사용 카운트 조회 // @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. 전체 조직의 통계를 조회하려면 organizationId를 tks로 설정한다. // @Accept json // @Produce json // @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Success 200 {object} domain.ListPolicyTemplateStatisticsResponse +// @Success 200 {object} admin_domain.ListPolicyTemplateStatisticsResponse // @Router /admin/policy-templates/{policyTemplateId}/statistics [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateStatistics(w http.ResponseWriter, r *http.Request) { - // result := domain.ListPolicyTemplateStatisticsResponse{ - // PolicyTemplateStatistics: []domain.PolicyTemplateStatistics{ + // result := admin_domain.ListPolicyTemplateStatisticsResponse{ + // PolicyTemplateStatistics: []admin_domain.PolicyTemplateStatistics{ // { // OrganizationId: util.UUIDGen(), // OrganizationName: "개발팀", @@ -370,12 +389,12 @@ func (h *PolicyTemplateHandler) Admin_ListPolicyTemplateStatistics(w http.Respon // Admin_GetPolicyTemplateDeploy godoc // // @Tags PolicyTemplate -// @Summary [GetPolicyTemplateDeploy] 정책 템플릿 클러스터 별 설치 버전 조회 +// @Summary [Admin_GetPolicyTemplateDeploy] 정책 템플릿 클러스터 별 설치 버전 조회 // @Description 해당 식별자를 가진 정책 템플릿의 정책 템플릿 클러스터 별 설치 버전을 조회한다. // @Accept json // @Produce json // @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Success 200 {object} domain.GetPolicyTemplateDeployResponse +// @Success 200 {object} admin_domain.GetPolicyTemplateDeployResponse // @Router /admin/policy-templates/{policyTemplateId}/deploy [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateDeploy(w http.ResponseWriter, r *http.Request) { @@ -383,7 +402,7 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateDeploy(w http.ResponseWri // c2 := util.UUIDGen() // c3 := util.UUIDGen() - // result := domain.GetPolicyTemplateDeployResponse{ + // result := admin_domain.GetPolicyTemplateDeployResponse{ // DeployVersion: map[string]string{ // c1: "v1.0.1", // c2: "v1.1.0", @@ -396,17 +415,24 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateDeploy(w http.ResponseWri // Admin_GetPolicyTemplateVersion godoc // // @Tags PolicyTemplate -// @Summary [GetPolicyTemplateVersion] 정책 템플릿 특정 버전 조회 +// @Summary [Admin_GetPolicyTemplateVersion] 정책 템플릿 특정 버전 조회 // @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 조회한다. // @Accept json // @Produce json // @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" // @Param version path string true "조회할 버전(v0.0.0 형식)" -// @Success 200 {object} domain.GetPolicyTemplateVersionResponse +// @Success 200 {object} admin_domain.GetPolicyTemplateVersionResponse // @Router /admin/policy-templates/{policyTemplateId}/versions/{version} [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateVersion(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + policyTemplateId, ok := vars["policyTemplateId"] if !ok { ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) @@ -425,7 +451,7 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateVersion(w http.ResponseWr return } - policyTemplate, err := h.usecase.GetPolicyTemplateVersion(r.Context(), id, version) + policyTemplate, err := h.usecase.GetPolicyTemplateVersion(r.Context(), &organizationId, id, version) if err != nil { if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION", "")) @@ -438,7 +464,7 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateVersion(w http.ResponseWr return } - var out domain.GetPolicyTemplateVersionResponse + var out admin_domain.GetPolicyTemplateVersionResponse if err = serializer.Map(r.Context(), *policyTemplate, &out.PolicyTemplate); err != nil { log.Error(r.Context(), err) } @@ -453,13 +479,13 @@ func (h *PolicyTemplateHandler) Admin_GetPolicyTemplateVersion(w http.ResponseWr // Admin_CreatePolicyTemplateVersion godoc // // @Tags PolicyTemplate -// @Summary [CreatePolicyTemplateVersion] 정책 템플릿 특정 버전 저장 +// @Summary [Admin_CreatePolicyTemplateVersion] 정책 템플릿 특정 버전 저장 // @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 저장한다. // @Accept json // @Produce json -// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" -// @Param body body domain.CreatePolicyTemplateVersionRequest true "create policy template version request" -// @Success 200 {object} domain.CreatePolicyTemplateVersionResponse +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param body body admin_domain.CreatePolicyTemplateVersionRequest true "create policy template version request" +// @Success 200 {object} admin_domain.CreatePolicyTemplateVersionResponse // @Router /admin/policy-templates/{policyTemplateId}/versions [post] // @Security JWT func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) { @@ -476,7 +502,7 @@ func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplateVersion(w http.Respons return } - input := domain.CreatePolicyTemplateVersionRequest{} + input := admin_domain.CreatePolicyTemplateVersionRequest{} err = UnmarshalRequestInput(r, &input) @@ -513,14 +539,14 @@ func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplateVersion(w http.Respons input.ExpectedVersion, expectedVersion))) } - createdVersion, err := h.usecase.CreatePolicyTemplateVersion(r.Context(), id, expectedVersion, input.ParametersSchema, input.Rego, input.Libs) + createdVersion, err := h.usecase.CreatePolicyTemplateVersion(r.Context(), nil, id, expectedVersion, input.ParametersSchema, input.Rego, input.Libs) if err != nil { ErrorJSON(w, r, err) return } - var out domain.CreatePolicyTemplateVersionResponse + var out admin_domain.CreatePolicyTemplateVersionResponse out.Version = createdVersion ResponseJSON(w, r, http.StatusOK, out) @@ -529,7 +555,7 @@ func (h *PolicyTemplateHandler) Admin_CreatePolicyTemplateVersion(w http.Respons // Admin_DeletePolicyTemplateVersion godoc // // @Tags PolicyTemplate -// @Summary [DeletePolicyTemplateVersion] 정책 템플릿 특정 버전 삭제 +// @Summary [Admin_DeletePolicyTemplateVersion] 정책 템플릿 특정 버전 삭제 // @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 삭제한다. // @Accept json // @Produce json @@ -559,7 +585,7 @@ func (h *PolicyTemplateHandler) Admin_DeletePolicyTemplateVersion(w http.Respons return } - err = h.usecase.DeletePolicyTemplateVersion(r.Context(), id, version) + err = h.usecase.DeletePolicyTemplateVersion(r.Context(), nil, id, version) if err != nil { log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) @@ -578,12 +604,12 @@ func (h *PolicyTemplateHandler) Admin_DeletePolicyTemplateVersion(w http.Respons // Admin_ExistsPolicyTemplateName godoc // // @Tags PolicyTemplate -// @Summary [ExistsPolicyTemplateName] 정책 템플릿 아름 존재 여부 확인 +// @Summary [Admin_ExistsPolicyTemplateName] 정책 템플릿 아름 존재 여부 확인 // @Description 해당 이름을 가진 정책 템플릿이 이미 존재하는지 확인한다. // @Accept json // @Produce json // @Param policyTemplateName path string true "정책 템플릿 이름" -// @Success 200 {object} domain.CheckExistedResponse +// @Success 200 {object} admin_domain.ExistsPolicyTemplateNameResponse // @Router /admin/policy-templates/name/{policyTemplateName}/existence [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_ExistsPolicyTemplateName(w http.ResponseWriter, r *http.Request) { @@ -595,13 +621,13 @@ func (h *PolicyTemplateHandler) Admin_ExistsPolicyTemplateName(w http.ResponseWr return } - exist, err := h.usecase.IsPolicyTemplateNameExist(r.Context(), policyTemplateName) + exist, err := h.usecase.IsPolicyTemplateNameExist(r.Context(), nil, policyTemplateName) if err != nil { ErrorJSON(w, r, err) return } - var out domain.CheckExistedResponse + var out admin_domain.ExistsPolicyTemplateNameResponse out.Existed = exist ResponseJSON(w, r, http.StatusOK, out) @@ -610,12 +636,12 @@ func (h *PolicyTemplateHandler) Admin_ExistsPolicyTemplateName(w http.ResponseWr // Admin_ExistsPolicyTemplateKind godoc // // @Tags PolicyTemplate -// @Summary [ExistsPolicyTemplateKind] 정책 템플릿 유형 존재 여부 확인 +// @Summary [Admin_ExistsPolicyTemplateKind] 정책 템플릿 유형 존재 여부 확인 // @Description 해당 유형을 가진 정책 템플릿이 이미 존재하는지 확인한다. // @Accept json // @Produce json // @Param policyTemplateKind path string true "정책 템플릿 이름" -// @Success 200 {object} domain.CheckExistedResponse +// @Success 200 {object} admin_domain.ExistsPolicyTemplateKindResponse // @Router /admin/policy-templates/kind/{policyTemplateKind}/existence [get] // @Security JWT func (h *PolicyTemplateHandler) Admin_ExistsPolicyTemplateKind(w http.ResponseWriter, r *http.Request) { @@ -627,13 +653,13 @@ func (h *PolicyTemplateHandler) Admin_ExistsPolicyTemplateKind(w http.ResponseWr return } - exist, err := h.usecase.IsPolicyTemplateKindExist(r.Context(), policyTemplateKind) + exist, err := h.usecase.IsPolicyTemplateKindExist(r.Context(), nil, policyTemplateKind) if err != nil { ErrorJSON(w, r, err) return } - var out domain.CheckExistedResponse + var out admin_domain.ExistsPolicyTemplateKindResponse out.Existed = exist ResponseJSON(w, r, http.StatusOK, out) @@ -685,3 +711,680 @@ func (h *PolicyTemplateHandler) RegoCompile(w http.ResponseWriter, r *http.Reque ResponseJSON(w, r, http.StatusCreated, response) } + +// CreatePolicyTemplate godoc +// +// @Tags PolicyTemplate +// @Summary [CreatePolicyTemplate] 정책 템플릿 신규 생성 +// @Description 정책 템플릿을 신규 생성(v1.0.0을 생성)한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param body body domain.CreatePolicyTemplateRequest true "create policy template request" +// @Success 200 {object} domain.CreatePolicyTemplateReponse +// @Router /organizations/{organizationId}/policy-templates [post] +// @Security JWT +func (h *PolicyTemplateHandler) CreatePolicyTemplate(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + input := domain.CreatePolicyTemplateRequest{} + + err := UnmarshalRequestInput(r, &input) + + if err != nil { + ErrorJSON(w, r, err) + return + } + + var dto model.PolicyTemplate + if err = serializer.Map(r.Context(), input, &dto); err != nil { + log.Info(r.Context(), err) + } + + dto.Type = "organization" + dto.OrganizationId = &organizationId + + policyTemplateId, err := h.usecase.Create(r.Context(), dto) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.CreatePolicyTemplateReponse + out.ID = policyTemplateId.String() + + ResponseJSON(w, r, http.StatusOK, out) +} + +// UpdatePolicyTemplate godoc +// +// @Tags PolicyTemplate +// @Summary [UpdatePolicyTemplate] 정책 템플릿 업데이트 +// @Description 정책 템플릿의 업데이트 가능한 필드들을 업데이트한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param body body domain.UpdatePolicyTemplateRequest true "update policy template request" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId} [patch] +// @Security JWT +func (h *PolicyTemplateHandler) UpdatePolicyTemplate(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + input := domain.UpdatePolicyTemplateRequest{} + + err = UnmarshalRequestInput(r, &input) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, err) + return + } + + // Organization 템플릿은 PermittedOrganizations가 없음 + err = h.usecase.Update(r.Context(), &organizationId, id, input.TemplateName, input.Description, input.Severity, input.Deprecated, nil) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, nil) +} + +// DeletePolicyTemplate godoc +// +// @Tags PolicyTemplate +// @Summary [DeletePolicyTemplate] 정책 템플릿 삭제 +// @Description 정책 템플릿을 삭제한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId} [delete] +// @Security JWT +func (h *PolicyTemplateHandler) DeletePolicyTemplate(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + err = h.usecase.Delete(r.Context(), &organizationId, id) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, "") +} + +// GetPolicyTemplate godoc +// +// @Tags PolicyTemplate +// @Summary [GetPolicyTemplate] 정책 템플릿 조회(최신 버전) +// @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Success 200 {object} domain.GetPolicyTemplateResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId} [get] +// @Security JWT +func (h *PolicyTemplateHandler) GetPolicyTemplate(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + policyTemplate, err := h.usecase.Get(r.Context(), &organizationId, id) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_NOT_FOUND_POLICY_TEMPLATE", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + if policyTemplate == nil { + ResponseJSON(w, r, http.StatusNotFound, nil) + return + } + + var out domain.GetPolicyTemplateResponse + if err = serializer.Map(r.Context(), *policyTemplate, &out.PolicyTemplate); err != nil { + log.Error(r.Context(), err) + } + + ResponseJSON(w, r, http.StatusOK, out) +} + +// ListPolicyTemplate godoc +// +// @Tags PolicyTemplate +// @Summary [ListPolicyTemplate] 정책 템플릿 목록 조회 +// @Description 정책 템플릿 목록을 조회한다. 정책 템플릿 목록 조회 결과는 최신 템플릿 버전 목록만 조회된다. +// @Accept json +// @Produce json +// @Param limit query string false "pageSize" +// @Param page query string false "pageNumber" +// @Param sortColumn query string false "sortColumn" +// @Param sortOrder query string false "sortOrder" +// @Param filters query []string false "filters" +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Success 200 {object} domain.ListPolicyTemplateResponse +// @Router /organizations/{organizationId}/policy-templates [get] +// @Security JWT +func (h *PolicyTemplateHandler) ListPolicyTemplate(w http.ResponseWriter, r *http.Request) { + urlParams := r.URL.Query() + + pg := pagination.NewPagination(&urlParams) + + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplates, err := h.usecase.Fetch(r.Context(), &organizationId, pg) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.ListPolicyTemplateResponse + out.PolicyTemplates = make([]domain.PolicyTemplateResponse, len(policyTemplates)) + for i, policyTemplate := range policyTemplates { + if err := serializer.Map(r.Context(), policyTemplate, &out.PolicyTemplates[i]); err != nil { + log.Info(r.Context(), err) + continue + } + } + + if out.Pagination, err = pg.Response(r.Context()); err != nil { + log.Info(r.Context(), err) + } + + ResponseJSON(w, r, http.StatusOK, out) +} + +// ListPolicyTemplateVersions godoc +// +// @Tags PolicyTemplate +// @Summary [ListPolicyTemplateVersions] 정책 템플릿 버전목록 조회 +// @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Success 200 {object} domain.ListPolicyTemplateVersionsResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/versions [get] +// @Security JWT +func (h *PolicyTemplateHandler) ListPolicyTemplateVersions(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + policyTemplateVersions, err := h.usecase.ListPolicyTemplateVersions(r.Context(), &organizationId, id) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + var out domain.ListPolicyTemplateVersionsResponse + if err = serializer.Map(r.Context(), *policyTemplateVersions, &out); err != nil { + log.Error(r.Context(), err) + } + + ResponseJSON(w, r, http.StatusOK, out) +} + +// ListPolicyTemplateStatistics godoc +// +// @Tags PolicyTemplate +// @Summary [ListPolicyTemplateStatistics] 정책 템플릿 사용 카운트 조회 +// @Description 해당 식별자를 가진 정책 템플릿의 최신 버전을 조회한다. 전체 조직의 통계를 조회하려면 organizationId를 tks로 설정한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Success 200 {object} domain.ListPolicyTemplateStatisticsResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/statistics [get] +// @Security JWT +func (h *PolicyTemplateHandler) ListPolicyTemplateStatistics(w http.ResponseWriter, r *http.Request) { + // result := domain.ListPolicyTemplateStatisticsResponse{ + // PolicyTemplateStatistics: []domain.PolicyTemplateStatistics{ + // { + // OrganizationId: util.UUIDGen(), + // OrganizationName: "개발팀", + // UsageCount: 10, + // }, + // { + // OrganizationId: util.UUIDGen(), + // OrganizationName: "운영팀", + // UsageCount: 5, + // }, + // }, + // } + // util.JsonResponse(w, result) +} + +// GetPolicyTemplateDeploy godoc +// +// @Tags PolicyTemplate +// @Summary [GetPolicyTemplateDeploy] 정책 템플릿 클러스터 별 설치 버전 조회 +// @Description 해당 식별자를 가진 정책 템플릿의 정책 템플릿 클러스터 별 설치 버전을 조회한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Success 200 {object} domain.GetPolicyTemplateDeployResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/deploy [get] +// @Security JWT +func (h *PolicyTemplateHandler) GetPolicyTemplateDeploy(w http.ResponseWriter, r *http.Request) { + // c1 := util.UUIDGen() + // c2 := util.UUIDGen() + // c3 := util.UUIDGen() + + // result := domain.GetPolicyTemplateDeployResponse{ + // DeployVersion: map[string]string{ + // c1: "v1.0.1", + // c2: "v1.1.0", + // c3: "v1.1.0", + // }, + // } + // util.JsonResponse(w, result) +} + +// GetPolicyTemplateVersion godoc +// +// @Tags PolicyTemplate +// @Summary [GetPolicyTemplateVersion] 정책 템플릿 특정 버전 조회 +// @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 조회한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param version path string true "조회할 버전(v0.0.0 형식)" +// @Success 200 {object} domain.GetPolicyTemplateVersionResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/versions/{version} [get] +// @Security JWT +func (h *PolicyTemplateHandler) GetPolicyTemplateVersion(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + version, ok := vars["version"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid version"), "PT_INVALID_POLICY_TEMPLATE_VERSION", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + policyTemplate, err := h.usecase.GetPolicyTemplateVersion(r.Context(), &organizationId, id, version) + if err != nil { + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION", "")) + return + } + } + + if policyTemplate == nil { + ResponseJSON(w, r, http.StatusNotFound, nil) + return + } + + var out domain.GetPolicyTemplateVersionResponse + if err = serializer.Map(r.Context(), *policyTemplate, &out.PolicyTemplate); err != nil { + log.Error(r.Context(), err) + } + + ResponseJSON(w, r, http.StatusOK, out) +} + +// CreatePolicyTemplateVersion godoc +// +// @Tags PolicyTemplate +// @Summary [CreatePolicyTemplateVersion] 정책 템플릿 특정 버전 저장 +// @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 저장한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param body body domain.CreatePolicyTemplateVersionRequest true "create policy template version request" +// @Success 200 {object} domain.CreatePolicyTemplateVersionResponse +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/versions [post] +// @Security JWT +func (h *PolicyTemplateHandler) CreatePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + input := domain.CreatePolicyTemplateVersionRequest{} + + err = UnmarshalRequestInput(r, &input) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, err) + return + } + + currentVer, err := semver.NewVersion(input.CurrentVersion) + if err != nil { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid currentVersion"), "PT_INVALID_POLICY_TEMPLATE_VERSION", fmt.Sprintf("invalid version format '%s'", input.CurrentVersion))) + return + } + + versionUpType := strings.ToLower(input.VersionUpType) + + var expectedVersion string + + switch versionUpType { + case "major": + newVersion := currentVer.IncMajor() + expectedVersion = newVersion.Original() + case "minor": + newVersion := currentVer.IncMinor() + expectedVersion = newVersion.Original() + case "patch": + newVersion := currentVer.IncPatch() + expectedVersion = newVersion.Original() + } + + if expectedVersion != input.ExpectedVersion { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid expectedVersion"), "PT_INVALID_POLICY_TEMPLATE_VERSION", fmt.Sprintf("expected version mismatch '%s' != '%s'", + input.ExpectedVersion, expectedVersion))) + } + + createdVersion, err := h.usecase.CreatePolicyTemplateVersion(r.Context(), &organizationId, id, expectedVersion, input.ParametersSchema, input.Rego, input.Libs) + + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.CreatePolicyTemplateVersionResponse + out.Version = createdVersion + + ResponseJSON(w, r, http.StatusOK, out) +} + +// DeletePolicyTemplateVersion godoc +// +// @Tags PolicyTemplate +// @Summary [DeletePolicyTemplateVersion] 정책 템플릿 특정 버전 삭제 +// @Description 해당 식별자를 가진 정책 템플릿의 특정 버전을 삭제한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateId path string true "정책 템플릿 식별자(uuid)" +// @Param version path string true "삭제할 버전(v0.0.0 형식)" +// @Success 200 {object} nil +// @Router /organizations/{organizationId}/policy-templates/{policyTemplateId}/versions/{version} [delete] +// @Security JWT +func (h *PolicyTemplateHandler) DeletePolicyTemplateVersion(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateId, ok := vars["policyTemplateId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid policyTemplateId"), "C_INVALID_POLICY_TEMPLATE_ID", "")) + return + } + + version, ok := vars["version"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid version"), "PT_INVALID_POLICY_TEMPLATE_VERSION", "")) + return + } + + id, err := uuid.Parse(policyTemplateId) + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_INVALID_POLICY_TEMPLATE_VERSION", "")) + return + } + + err = h.usecase.DeletePolicyTemplateVersion(r.Context(), &organizationId, id, version) + + if err != nil { + log.Errorf(r.Context(), "error is :%s(%T)", err.Error(), err) + if _, status := httpErrors.ErrorResponse(err); status == http.StatusNotFound { + ErrorJSON(w, r, httpErrors.NewBadRequestError(err, "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION", "")) + return + } + + ErrorJSON(w, r, err) + return + } + + ResponseJSON(w, r, http.StatusOK, "") +} + +// ExistsPolicyTemplateName godoc +// +// @Tags PolicyTemplate +// @Summary [ExistsPolicyTemplateName] 정책 템플릿 아름 존재 여부 확인 +// @Description 해당 이름을 가진 정책 템플릿이 이미 존재하는지 확인한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateName path string true "정책 템플릿 이름" +// @Success 200 {object} domain.ExistsPolicyTemplateNameResponse +// @Router /organizations/{organizationId}/policy-templates/name/{policyTemplateName}/existence [get] +// @Security JWT +func (h *PolicyTemplateHandler) ExistsPolicyTemplateName(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateName, ok := vars["policyTemplateName"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("policyTemplateName not found in path"), + "PT_INVALID_POLICY_TEMPLATE_NAME", "")) + return + } + + exist, err := h.usecase.IsPolicyTemplateNameExist(r.Context(), &organizationId, policyTemplateName) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.ExistsPolicyTemplateNameResponse + out.Existed = exist + + ResponseJSON(w, r, http.StatusOK, out) +} + +// ExistsPolicyTemplateKind godoc +// +// @Tags PolicyTemplate +// @Summary [ExistsPolicyTemplateKind] 정책 템플릿 유형 존재 여부 확인 +// @Description 해당 유형을 가진 정책 템플릿이 이미 존재하는지 확인한다. +// @Accept json +// @Produce json +// @Param organizationId path string true "조직 식별자(o로 시작)" +// @Param policyTemplateKind path string true "정책 템플릿 이름" +// @Success 200 {object} domain.ExistsPolicyTemplateKindResponse +// @Router /organizations/{organizationId}/policy-templates/kind/{policyTemplateKind}/existence [get] +// @Security JWT +func (h *PolicyTemplateHandler) ExistsPolicyTemplateKind(w http.ResponseWriter, r *http.Request) { + vars := mux.Vars(r) + organizationId, ok := vars["organizationId"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), + "C_INVALID_ORGANIZATION_ID", "")) + return + } + + policyTemplateKind, ok := vars["policyTemplateKind"] + if !ok { + ErrorJSON(w, r, httpErrors.NewBadRequestError(fmt.Errorf("policyTemplateKind not found in path"), + "PT_INVALID_POLICY_TEMPLATE_KIND", "")) + return + } + + exist, err := h.usecase.IsPolicyTemplateKindExist(r.Context(), &organizationId, policyTemplateKind) + if err != nil { + ErrorJSON(w, r, err) + return + } + + var out domain.ExistsPolicyTemplateKindResponse + out.Existed = exist + + ResponseJSON(w, r, http.StatusOK, out) +} diff --git a/internal/delivery/http/policy.go b/internal/delivery/http/policy.go index 972648c8..24b7e59c 100644 --- a/internal/delivery/http/policy.go +++ b/internal/delivery/http/policy.go @@ -139,7 +139,6 @@ func (h *PolicyHandler) UpdatePolicy(w http.ResponseWriter, r *http.Request) { return } templateId = &tuuid - } err = h.usecase.Update(r.Context(), organizationId, id, @@ -284,7 +283,7 @@ func (h *PolicyHandler) GetPolicy(w http.ResponseWriter, r *http.Request) { // @Param organizationId path string true "조직 식별자(o로 시작)" // @Param limit query string false "pageSize" // @Param page query string false "pageNumber" -// @Param soertColumn query string false "sortColumn" +// @Param sortColumn query string false "sortColumn" // @Param sortOrder query string false "sortOrder" // @Param filters query []string false "filters" // @Success 200 {object} domain.ListPolicyResponse diff --git a/internal/delivery/http/role.go b/internal/delivery/http/role.go index 21658fd9..5ac474f3 100644 --- a/internal/delivery/http/role.go +++ b/internal/delivery/http/role.go @@ -341,7 +341,7 @@ func convertModelToPermissionResponse(ctx context.Context, permission *model.Per return &permissionResponse } -func convertModelToEndpointResponse(ctx context.Context, endpoint *model.Endpoint) *domain.EndpointResponse { +func convertModelToEndpointResponse(_ context.Context, endpoint *model.Endpoint) *domain.EndpointResponse { var endpointResponse domain.EndpointResponse endpointResponse.Name = endpoint.Name diff --git a/internal/model/permission.go b/internal/model/permission.go index 7fafc931..b81ec8a4 100644 --- a/internal/model/permission.go +++ b/internal/model/permission.go @@ -296,14 +296,14 @@ func newPolicy() *Permission { api.ExistsPolicyName, // OrganizationPolicyTemplate - api.ListOrganizationPolicyTemplate, - api.GetOrganizationPolicyTemplate, - api.GetOrganizationPolicyTemplateDeploy, - api.ListOrganizationPolicyTemplateStatistics, - api.ListOrganizationPolicyTemplateVersions, - api.GetOrganizationPolicyTemplateVersion, - api.ExistsOrganizationPolicyTemplateKind, - api.ExistsOrganizationPolicyTemplateName, + api.ListPolicyTemplate, + api.GetPolicyTemplate, + api.GetPolicyTemplateDeploy, + api.ListPolicyTemplateStatistics, + api.ListPolicyTemplateVersions, + api.GetPolicyTemplateVersion, + api.ExistsPolicyTemplateKind, + api.ExistsPolicyTemplateName, // PolicyTemplateExample api.ListPolicyTemplateExample, @@ -325,8 +325,8 @@ func newPolicy() *Permission { api.CreatePolicy, // OrganizationPolicyTemplate - api.CreateOrganizationPolicyTemplate, - api.CreateOrganizationPolicyTemplateVersion, + api.CreatePolicyTemplate, + api.CreatePolicyTemplateVersion, ), }, { @@ -346,7 +346,7 @@ func newPolicy() *Permission { api.UpdatePolicyTargetClusters, // OrganizationPolicyTemplate - api.UpdateOrganizationPolicyTemplate, + api.UpdatePolicyTemplate, // PolicyTemplateExample api.UpdatePolicyTemplateExample, @@ -366,8 +366,8 @@ func newPolicy() *Permission { api.DeletePolicy, // OrganizationPolicyTemplate - api.DeleteOrganizationPolicyTemplate, - api.DeleteOrganizationPolicyTemplateVersion, + api.DeletePolicyTemplate, + api.DeletePolicyTemplateVersion, // PolicyTemplateExample api.DeletePolicyTemplateExample, diff --git a/internal/model/policy-template.go b/internal/model/policy-template.go index c5e2f433..2a197376 100644 --- a/internal/model/policy-template.go +++ b/internal/model/policy-template.go @@ -2,6 +2,7 @@ package model import ( "encoding/json" + "slices" "strings" "github.com/google/uuid" @@ -32,12 +33,14 @@ type PolicyTemplate struct { Type string // Org or Tks Version string `gorm:"-:all"` // 삭제 예정 SupportedVersions []PolicyTemplateSupportedVersion `gorm:"foreignKey:PolicyTemplateId"` + OrganizationId *string // Org 인 경우에만 설정 + Organization Organization `gorm:"foreignKey:OrganizationId"` Description string Kind string Deprecated bool Mandatory bool // Tks 인 경우에는 무시 Severity string - PermittedOrganizations []Organization `gorm:"many2many:policy_template_permitted_organiations"` + PermittedOrganizations []Organization `gorm:"many2many:policy_template_permitted_organizations"` ParametersSchema []domain.ParameterDef `gorm:"-:all"` Rego string `gorm:"-:all"` Libs []string `gorm:"-:all"` @@ -48,6 +51,28 @@ type PolicyTemplate struct { Updator User `gorm:"foreignKey:UpdatorId"` } +func (pt *PolicyTemplate) IsTksTemplate() bool { + return strings.ToLower(pt.Type) == "tks" +} + +func (pt *PolicyTemplate) IsOrganizationTemplate() bool { + return !pt.IsTksTemplate() +} + +func (pt *PolicyTemplate) IsPermittedToOrganization(organizationId *string) bool { + // tks Admin은 organizationId가 nil + if organizationId == nil { + return true + } + + if pt.IsTksTemplate() { + return len(pt.PermittedOrganizationIds) == 0 || + slices.Contains(pt.PermittedOrganizationIds, *organizationId) + } + + return pt.OrganizationId != nil && *organizationId == *pt.OrganizationId +} + func (pt *PolicyTemplate) BeforeCreate(tx *gorm.DB) (err error) { pt.ID = uuid.New() @@ -79,7 +104,7 @@ func (pt *PolicyTemplate) AfterFind(tx *gorm.DB) (err error) { supportedVersion := pt.SupportedVersions[0] pt.Version = supportedVersion.Version pt.Rego = supportedVersion.Rego - pt.Libs = strings.Split(supportedVersion.ParameterSchema, FILE_DELIMETER) + pt.Libs = strings.Split(supportedVersion.Libs, FILE_DELIMETER) // 마찬가지로 에러 무시 _ = json.Unmarshal([]byte(supportedVersion.ParameterSchema), &pt.ParametersSchema) diff --git a/internal/repository/policy-template.go b/internal/repository/policy-template.go index 18cf0841..a7ecac85 100644 --- a/internal/repository/policy-template.go +++ b/internal/repository/policy-template.go @@ -19,12 +19,15 @@ type IPolicyTemplateRepository interface { Create(ctx context.Context, policyTemplate model.PolicyTemplate) (policyTemplateId uuid.UUID, err error) Update(ctx context.Context, policyTemplateId uuid.UUID, updateMap map[string]interface{}, permittedOrganizations *[]model.Organization) (err error) Fetch(ctx context.Context, pg *pagination.Pagination) (out []model.PolicyTemplate, err error) + FetchForOrganization(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []model.PolicyTemplate, err error) GetByName(ctx context.Context, policyTemplateName string) (out *model.PolicyTemplate, err error) GetByKind(ctx context.Context, policyTemplateKind string) (out *model.PolicyTemplate, err error) GetByID(ctx context.Context, policyTemplateId uuid.UUID) (out *model.PolicyTemplate, err error) Delete(ctx context.Context, policyTemplateId uuid.UUID) (err error) ExistByName(ctx context.Context, policyTemplateName string) (exist bool, err error) ExistByKind(ctx context.Context, policyTemplateKind string) (exist bool, err error) + ExistByNameInOrganization(ctx context.Context, organizationId string, policyTemplateName string) (exist bool, err error) + ExistByKindInOrganization(ctx context.Context, organizationId string, policyTemplateKind string) (exist bool, err error) ExistByID(ctx context.Context, policyTemplateId uuid.UUID) (exist bool, err error) ListPolicyTemplateVersions(ctx context.Context, policyTemplateId uuid.UUID) (policyTemplateVersionsReponse *domain.ListPolicyTemplateVersionsResponse, err error) GetPolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, version string) (policyTemplateVersionsReponse *model.PolicyTemplate, err error) @@ -70,7 +73,7 @@ func (r *PolicyTemplateRepository) Update(ctx context.Context, policyTemplateId if len(updateMap) > 0 { err = r.db.WithContext(ctx).Model(&policyTemplate).Limit(1). - Where("id = ? and type = 'tks'", policyTemplateId). + Where("id = ?", policyTemplateId).Where("type = ?", "tks"). Updates(updateMap).Error if err != nil { @@ -104,6 +107,58 @@ func (r *PolicyTemplateRepository) Fetch(ctx context.Context, pg *pagination.Pag return policyTemplates, nil } +func (r *PolicyTemplateRepository) FetchForOrganization(ctx context.Context, organizationId string, pg *pagination.Pagination) (out []model.PolicyTemplate, err error) { + var policyTemplates []model.PolicyTemplate + if pg == nil { + pg = pagination.NewPagination(nil) + } + + // 다음과 같은 쿼리를 생성해서 tks 템플릿에 대해선 PermittedOrganizations가 비거나, PermittedOrganizations에 해당 organizations이 속하는 템플릿을 찾음 + // organization 템플릿은 organizationId가 매칭되는 것을 찾음, 이를 통해 해당 사용자가 사용할 수 있는 모든 템플릿을 fetch + // select id from policy_templates where + // ( + // type = 'tks' + // and ( + // id not in (select policy_template_id from policy_template_permitted_organizations) -- PermitedOrganizations이 빈 경우, 모두에게 허용 + // or id in (select policy_template_id from policy_template_permitted_organizations organization where organization_id = 'orgid') -- PermitedOrganizations 허용된 경우 + // ) + // ) + // or (type = 'organization' and organization_id='orgid') + subQueryAloowedAll := r.db.Table("policy_template_permitted_organizations").Select("policy_template_id") + subQueryMatchId := r.db.Table("policy_template_permitted_organizations").Select("policy_template_id"). + Where("organization_id = ?", organizationId) + + _, res := pg.Fetch(r.db.WithContext(ctx). + Preload("SupportedVersions", func(db *gorm.DB) *gorm.DB { + // 최신 버전만 + return db.Order("policy_template_supported_versions.version DESC") + }). + Preload("Creator").Preload("Updator"). // organization을 기준으로 조회할 때에는 PermittedOrganizations는 로딩하지 않아도 됨 + Model(&model.PolicyTemplate{}). + Where( + // tks 템플릿인 경우 + r.db.Where("type = ?", "tks"). + Where( + // permitted_organizations이 비어있거나 + r.db.Where("id not in (?)", subQueryAloowedAll). + Or("id in (?)", subQueryMatchId), + // permitted_organization에 매칭되는 템플릿 아이디가 있거나 + ), + ). + Or( + // organization 타입 템플릿이면서 organization_id가 매칭 + r.db.Where("type = ?", "organization"). + Where("organization_id = ?", organizationId), + ), + &policyTemplates) + + if res.Error != nil { + return nil, res.Error + } + + return policyTemplates, nil +} + func (r *PolicyTemplateRepository) ExistsBy(ctx context.Context, key string, value interface{}) (exists bool, err error) { query := fmt.Sprintf("%s = ?", key) @@ -132,6 +187,39 @@ func (r *PolicyTemplateRepository) ExistByKind(ctx context.Context, policyTempla return r.ExistsBy(ctx, "kind", policyTemplateKind) } +func (r *PolicyTemplateRepository) ExistsByInOrganization(ctx context.Context, organizationId string, key string, value interface{}) (exists bool, err error) { + + var policyTemplate model.PolicyTemplate + // query := fmt.Sprintf("%s = ? and (type = 'tks' or organization_id = ?)", key) + // res := r.db.WithContext(ctx).Where(query, value, organizationId). + // First(&policyTemplate) + + res := r.db.WithContext(ctx).Where(fmt.Sprintf("%s = ?", key), value). + Where( + r.db.Where("type = ?", "tks").Or("organization_id = ?", organizationId), + ).First(&policyTemplate) + + if res.Error != nil { + if errors.Is(res.Error, gorm.ErrRecordNotFound) { + log.Infof(ctx, "Not found policyTemplate %s='%v'", key, value) + return false, nil + } else { + log.Error(ctx, res.Error) + return false, res.Error + } + } + + return true, nil +} + +func (r *PolicyTemplateRepository) ExistByNameInOrganization(ctx context.Context, organizationId string, policyTemplateName string) (exist bool, err error) { + return r.ExistsByInOrganization(ctx, organizationId, "template_name", policyTemplateName) +} + +func (r *PolicyTemplateRepository) ExistByKindInOrganization(ctx context.Context, organizationId string, policyTemplateKind string) (exist bool, err error) { + return r.ExistsByInOrganization(ctx, organizationId, "kind", policyTemplateKind) +} + func (r *PolicyTemplateRepository) ExistByID(ctx context.Context, policyTemplateId uuid.UUID) (exist bool, err error) { return r.ExistsBy(ctx, "id", policyTemplateId) } @@ -268,7 +356,7 @@ func (r *PolicyTemplateRepository) DeletePolicyTemplateVersion(ctx context.Conte } // relaton을 unscoped로 삭제하지 않으면 동일한 키로 다시 생성할 때 키가 같은 레코드가 deleted 상태로 존재하므로 unscoped delete - res = r.db.WithContext(ctx).Unscoped().Where("policy_template_id = ? and version = ?", policyTemplateId, version). + res = r.db.WithContext(ctx).Unscoped().Where("policy_template_id = ?", policyTemplateId).Where("version = ?", version). Delete(&policyTemplateVersion) if res.Error != nil { if errors.Is(res.Error, gorm.ErrRecordNotFound) { @@ -287,7 +375,7 @@ func (r *PolicyTemplateRepository) DeletePolicyTemplateVersion(ctx context.Conte func (r *PolicyTemplateRepository) CreatePolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, newVersion string, schema []domain.ParameterDef, rego string, libs []string) (version string, err error) { var policyTemplateVersion model.PolicyTemplateSupportedVersion res := r.db.WithContext(ctx).Limit(1). - Where("policy_template_id = ? and version = ?", policyTemplateId, version). + Where("policy_template_id = ?", policyTemplateId).Where("version = ?", version). First(&policyTemplateVersion) if res.Error == nil { diff --git a/internal/route/route.go b/internal/route/route.go index a209a15f..e1199f5d 100644 --- a/internal/route/route.go +++ b/internal/route/route.go @@ -313,6 +313,19 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa r.Handle(API_PREFIX+API_VERSION+ADMINAPI_PREFIX+"/policy-templates/kind/{policyTemplateKind}/existence", customMiddleware.Handle(internalApi.Admin_ExistsPolicyTemplateKind, http.HandlerFunc(policyTemplateHandler.Admin_ExistsPolicyTemplateKind))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+ADMINAPI_PREFIX+"/policy-templates/name/{policyTemplateName}/existence", customMiddleware.Handle(internalApi.Admin_ExistsPolicyTemplateName, http.HandlerFunc(policyTemplateHandler.Admin_ExistsPolicyTemplateName))).Methods(http.MethodGet) r.Handle(API_PREFIX+API_VERSION+"/policy-templates/rego-compile", customMiddleware.Handle(internalApi.CompileRego, http.HandlerFunc(policyTemplateHandler.RegoCompile))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates", customMiddleware.Handle(internalApi.ListPolicyTemplate, http.HandlerFunc(policyTemplateHandler.ListPolicyTemplate))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates", customMiddleware.Handle(internalApi.CreatePolicyTemplate, http.HandlerFunc(policyTemplateHandler.CreatePolicyTemplate))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}", customMiddleware.Handle(internalApi.DeletePolicyTemplate, http.HandlerFunc(policyTemplateHandler.DeletePolicyTemplate))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}", customMiddleware.Handle(internalApi.GetPolicyTemplate, http.HandlerFunc(policyTemplateHandler.GetPolicyTemplate))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}", customMiddleware.Handle(internalApi.UpdatePolicyTemplate, http.HandlerFunc(policyTemplateHandler.UpdatePolicyTemplate))).Methods(http.MethodPatch) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/deploy ", customMiddleware.Handle(internalApi.GetPolicyTemplateDeploy, http.HandlerFunc(policyTemplateHandler.GetPolicyTemplateDeploy))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/statistics", customMiddleware.Handle(internalApi.ListPolicyTemplateStatistics, http.HandlerFunc(policyTemplateHandler.ListPolicyTemplateStatistics))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/versions", customMiddleware.Handle(internalApi.ListPolicyTemplateVersions, http.HandlerFunc(policyTemplateHandler.ListPolicyTemplateVersions))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/versions", customMiddleware.Handle(internalApi.CreatePolicyTemplateVersion, http.HandlerFunc(policyTemplateHandler.CreatePolicyTemplateVersion))).Methods(http.MethodPost) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/versions/{version}", customMiddleware.Handle(internalApi.DeletePolicyTemplateVersion, http.HandlerFunc(policyTemplateHandler.DeletePolicyTemplateVersion))).Methods(http.MethodDelete) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/{policyTemplateId}/versions/{version}", customMiddleware.Handle(internalApi.GetPolicyTemplateVersion, http.HandlerFunc(policyTemplateHandler.GetPolicyTemplateVersion))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/kind/{policyTemplateKind}/existence", customMiddleware.Handle(internalApi.ExistsPolicyTemplateKind, http.HandlerFunc(policyTemplateHandler.ExistsPolicyTemplateKind))).Methods(http.MethodGet) + r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/policy-templates/name/{policyTemplateName}/existence", customMiddleware.Handle(internalApi.ExistsPolicyTemplateName, http.HandlerFunc(policyTemplateHandler.ExistsPolicyTemplateName))).Methods(http.MethodGet) policyHandler := delivery.NewPolicyHandler(usecaseFactory) r.Handle(API_PREFIX+API_VERSION+"/organizations/{organizationId}/mandatory-policies", customMiddleware.Handle(internalApi.GetMandatoryPolicies, http.HandlerFunc(policyHandler.GetMandatoryPolicies))).Methods(http.MethodGet) diff --git a/internal/usecase/policy-template.go b/internal/usecase/policy-template.go index 1294f157..1bf59fef 100644 --- a/internal/usecase/policy-template.go +++ b/internal/usecase/policy-template.go @@ -4,6 +4,8 @@ import ( "context" "fmt" + admin_domain "github.com/openinfradev/tks-api/pkg/domain/admin" + mapset "github.com/deckarep/golang-set/v2" "github.com/google/uuid" "github.com/open-policy-agent/opa/ast" @@ -18,24 +20,24 @@ import ( type IPolicyTemplateUsecase interface { Create(ctx context.Context, policyTemplate model.PolicyTemplate) (policyTemplateId uuid.UUID, err error) - Fetch(ctx context.Context, pg *pagination.Pagination) (policyTemplates []model.PolicyTemplate, err error) - Update(ctx context.Context, policyTemplateId uuid.UUID, templateName *string, description *string, + Fetch(ctx context.Context, organizationId *string, pg *pagination.Pagination) (policyTemplates []model.PolicyTemplate, err error) + Update(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, templateName *string, description *string, severity *string, deorecated *bool, permittedOrganizationIds *[]string) (err error) - Get(ctx context.Context, policyTemplateId uuid.UUID) (policyTemplates *model.PolicyTemplate, err error) - Delete(ctx context.Context, policyTemplateId uuid.UUID) (err error) - IsPolicyTemplateNameExist(ctx context.Context, policyTemplateName string) (bool, error) - IsPolicyTemplateKindExist(ctx context.Context, policyTemplateKind string) (bool, error) - GetPolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, version string) (policyTemplateVersionsReponse *model.PolicyTemplate, err error) - ListPolicyTemplateVersions(ctx context.Context, policyTemplateId uuid.UUID) (policyTemplateVersionsReponse *domain.ListPolicyTemplateVersionsResponse, err error) - DeletePolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, version string) (err error) - CreatePolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, newVersion string, schema []domain.ParameterDef, rego string, libs []string) (version string, err error) + Get(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (policyTemplates *model.PolicyTemplate, err error) + Delete(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (err error) + IsPolicyTemplateNameExist(ctx context.Context, organizationId *string, policyTemplateName string) (bool, error) + IsPolicyTemplateKindExist(ctx context.Context, organizationId *string, policyTemplateKind string) (bool, error) + GetPolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, version string) (policyTemplateVersionsReponse *model.PolicyTemplate, err error) + ListPolicyTemplateVersions(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (policyTemplateVersionsReponse *domain.ListPolicyTemplateVersionsResponse, err error) + DeletePolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, version string) (err error) + CreatePolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, newVersion string, schema []domain.ParameterDef, rego string, libs []string) (version string, err error) RegoCompile(request *domain.RegoCompileRequest, parseParameter bool) (response *domain.RegoCompileResponse, err error) FillPermittedOrganizations(ctx context.Context, - policyTemplate *model.PolicyTemplate, out *domain.PolicyTemplateResponse) error + policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error FillPermittedOrganizationsForList(ctx context.Context, - policyTemplates *[]model.PolicyTemplate, outs *[]domain.PolicyTemplateResponse) error + policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error } type PolicyTemplateUsecase struct { @@ -58,33 +60,49 @@ func (u *PolicyTemplateUsecase) Create(ctx context.Context, dto model.PolicyTemp return uuid.Nil, httpErrors.NewUnauthorizedError(fmt.Errorf("invalid token"), "A_INVALID_TOKEN", "") } - exists, err := u.repo.ExistByName(ctx, dto.TemplateName) - if err == nil && exists { - return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_NAME", "policy template name already exists") - } + if dto.IsTksTemplate() { + exists, err := u.repo.ExistByName(ctx, dto.TemplateName) + if err == nil && exists { + return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_NAME", "policy template name already exists") + } + + exists, err = u.repo.ExistByKind(ctx, dto.Kind) + if err == nil && exists { + return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_KIND", "policy template kind already exists") + } + } else { + exists, err := u.repo.ExistByNameInOrganization(ctx, *dto.OrganizationId, dto.TemplateName) + if err == nil && exists { + return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_NAME", "policy template name already exists") + } - exists, err = u.repo.ExistByKind(ctx, dto.Kind) - if err == nil && exists { - return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_KIND", "policy template kind already exists") + exists, err = u.repo.ExistByKindInOrganization(ctx, *dto.OrganizationId, dto.Kind) + if err == nil && exists { + return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_KIND", "policy template kind already exists") + } } - dto.PermittedOrganizations = make([]model.Organization, len(dto.PermittedOrganizationIds)) - for i, organizationId := range dto.PermittedOrganizationIds { + if dto.IsTksTemplate() { + // TKS 템블릿이면 + dto.Mandatory = false + dto.OrganizationId = nil + + dto.PermittedOrganizations = make([]model.Organization, len(dto.PermittedOrganizationIds)) + for i, organizationId := range dto.PermittedOrganizationIds { - organization, err := u.organizationRepo.Get(ctx, organizationId) - if err != nil { - return uuid.Nil, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "") + organization, err := u.organizationRepo.Get(ctx, organizationId) + if err != nil { + return uuid.Nil, httpErrors.NewBadRequestError(fmt.Errorf("invalid organizationId"), "C_INVALID_ORGANIZATION_ID", "") + } + dto.PermittedOrganizations[i] = organization } - dto.PermittedOrganizations[i] = organization + } else { + dto.PermittedOrganizations = make([]model.Organization, 0) } userId := user.GetUserId() dto.CreatorId = &userId - // 시스템 템플릿 속성 설정 - dto.Type = "tks" - dto.Mandatory = false - id, err := u.repo.Create(ctx, dto) if err != nil { @@ -94,31 +112,29 @@ func (u *PolicyTemplateUsecase) Create(ctx context.Context, dto model.PolicyTemp return id, nil } -func (u *PolicyTemplateUsecase) Fetch(ctx context.Context, pg *pagination.Pagination) (policyTemplates []model.PolicyTemplate, err error) { - policyTemplates, err = u.repo.Fetch(ctx, pg) - - if err != nil { - return nil, err +func (u *PolicyTemplateUsecase) Fetch(ctx context.Context, organizationId *string, pg *pagination.Pagination) (policyTemplates []model.PolicyTemplate, err error) { + if organizationId == nil { + return u.repo.Fetch(ctx, pg) } - return policyTemplates, nil + return u.repo.FetchForOrganization(ctx, *organizationId, pg) } func (u *PolicyTemplateUsecase) FillPermittedOrganizations(ctx context.Context, - policyTemplate *model.PolicyTemplate, out *domain.PolicyTemplateResponse) error { + policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) error { organizations, err := u.organizationRepo.Fetch(ctx, nil) if err != nil { return err } - u.updatePermittedOrganizations(ctx, organizations, policyTemplate, out) + u.fillPermittedOrganizations(ctx, organizations, policyTemplate, out) return nil } func (u *PolicyTemplateUsecase) FillPermittedOrganizationsForList(ctx context.Context, - policyTemplates *[]model.PolicyTemplate, outs *[]domain.PolicyTemplateResponse) error { + policyTemplates *[]model.PolicyTemplate, outs *[]admin_domain.PolicyTemplateResponse) error { organizations, err := u.organizationRepo.Fetch(ctx, nil) @@ -129,14 +145,14 @@ func (u *PolicyTemplateUsecase) FillPermittedOrganizationsForList(ctx context.Co results := *outs for i, policyTemplate := range *policyTemplates { - u.updatePermittedOrganizations(ctx, organizations, &policyTemplate, &results[i]) + u.fillPermittedOrganizations(ctx, organizations, &policyTemplate, &results[i]) } return nil } // 모든 조직 목록에 대해 허용 여부 업데이트 -func (u *PolicyTemplateUsecase) updatePermittedOrganizations(ctx context.Context, organizations *[]model.Organization, policyTemplate *model.PolicyTemplate, out *domain.PolicyTemplateResponse) { +func (u *PolicyTemplateUsecase) fillPermittedOrganizations(_ context.Context, organizations *[]model.Organization, policyTemplate *model.PolicyTemplate, out *admin_domain.PolicyTemplateResponse) { if policyTemplate == nil || organizations == nil || out == nil { return } @@ -147,12 +163,12 @@ func (u *PolicyTemplateUsecase) updatePermittedOrganizations(ctx context.Context // 허용된 조직 포함 여부를 효율적으로 처리하기 위해 ID 리스트를 셋으로 변환 permittedOrganizationIdSet := mapset.NewSet(policyTemplate.PermittedOrganizationIds...) - out.PermittedOrganizations = make([]domain.PermittedOrganization, len(*organizations)) + out.PermittedOrganizations = make([]admin_domain.PermittedOrganization, len(*organizations)) for i, organization := range *organizations { permitted := allPermitted || permittedOrganizationIdSet.ContainsOne(organization.ID) - out.PermittedOrganizations[i] = domain.PermittedOrganization{ + out.PermittedOrganizations[i] = admin_domain.PermittedOrganization{ OrganizationId: organization.ID, OrganizationName: organization.Name, Permitted: permitted, @@ -160,35 +176,68 @@ func (u *PolicyTemplateUsecase) updatePermittedOrganizations(ctx context.Context } } -func (u *PolicyTemplateUsecase) Get(ctx context.Context, policyTemplateID uuid.UUID) (policyTemplates *model.PolicyTemplate, err error) { +func (u *PolicyTemplateUsecase) Get(ctx context.Context, organizationId *string, policyTemplateID uuid.UUID) (policyTemplates *model.PolicyTemplate, err error) { policyTemplate, err := u.repo.GetByID(ctx, policyTemplateID) if err != nil { return nil, err } + if !policyTemplate.IsPermittedToOrganization(organizationId) { + return nil, httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + return policyTemplate, nil } -func (u *PolicyTemplateUsecase) Update(ctx context.Context, policyTemplateId uuid.UUID, templateName *string, description *string, severity *string, deprecated *bool, permittedOrganizationIds *[]string) (err error) { +func (u *PolicyTemplateUsecase) Update(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, templateName *string, description *string, severity *string, deprecated *bool, permittedOrganizationIds *[]string) (err error) { user, ok := request.UserFrom(ctx) if !ok { return httpErrors.NewBadRequestError(fmt.Errorf("invalid token"), "A_INVALID_TOKEN", "") } - _, err = u.repo.GetByID(ctx, policyTemplateId) + policyTemplate, err := u.repo.GetByID(ctx, policyTemplateId) if err != nil { return httpErrors.NewNotFoundError(err, "PT_FAILED_FETCH_POLICY_TEMPLATE", "") } + if policyTemplate == nil { + return httpErrors.NewBadRequestError(fmt.Errorf( + "failed to fetch policy template"), + "PT_FAILED_FETCH_POLICY_TEMPLATE", "") + } + + if !policyTemplate.IsPermittedToOrganization(organizationId) { + // 다른 Organization의 템플릿을 조작하려고 함, 보안을 위해서 해당 식별자 존재 자체를 알려주면 안되므로 not found + if *organizationId != *policyTemplate.OrganizationId { + return httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + + return httpErrors.NewForbiddenError(fmt.Errorf( + "cannot update policy template"), + "PT_NOT_PERMITTED_ON_TKS_POLICY_TEMPLATE", "") + } + updateMap := make(map[string]interface{}) if templateName != nil { - exists, err := u.repo.ExistByName(ctx, *templateName) - if err == nil && exists { - return httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "P_INVALID_POLICY_TEMPLATE_NAME", "policy template name already exists") + if policyTemplate.IsTksTemplate() { + exists, err := u.repo.ExistByName(ctx, *templateName) + if err == nil && exists { + return httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "P_INVALID_POLICY_TEMPLATE_NAME", "policy template name already exists") + } + } else { + exists, err := u.repo.ExistByNameInOrganization(ctx, *organizationId, *templateName) + if err == nil && exists { + return httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "P_INVALID_POLICY_TEMPLATE_NAME", "policy template name already exists") + } } - updateMap["name"] = templateName + + updateMap["template_name"] = templateName } if description != nil { @@ -233,37 +282,138 @@ func (u *PolicyTemplateUsecase) Update(ctx context.Context, policyTemplateId uui return nil } -func (u *PolicyTemplateUsecase) Delete(ctx context.Context, policyTemplateId uuid.UUID) (err error) { +func (u *PolicyTemplateUsecase) Delete(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (err error) { + policyTemplate, err := u.repo.GetByID(ctx, policyTemplateId) + + if err != nil { + return err + } + + if policyTemplate == nil { + return httpErrors.NewBadRequestError(fmt.Errorf( + "failed to fetch policy template"), + "PT_FAILED_FETCH_POLICY_TEMPLATE", "") + } + + if !policyTemplate.IsPermittedToOrganization(organizationId) { + // 다른 Organization의 템플릿을 조작하려고 함, 보안을 위해서 해당 식별자 존재 자체를 알려주면 안되므로 not found + if *organizationId != *policyTemplate.OrganizationId { + return httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + + return httpErrors.NewForbiddenError(fmt.Errorf( + "cannot delete tks policy template"), + "PT_NOT_PERMITTED_ON_TKS_POLICY_TEMPLATE", "") + } + return u.repo.Delete(ctx, policyTemplateId) } -func (u *PolicyTemplateUsecase) IsPolicyTemplateNameExist(ctx context.Context, policyTemplateName string) (bool, error) { - return u.repo.ExistByName(ctx, policyTemplateName) +func (u *PolicyTemplateUsecase) IsPolicyTemplateNameExist(ctx context.Context, organizationId *string, policyTemplateName string) (bool, error) { + if organizationId == nil { + return u.repo.ExistByName(ctx, policyTemplateName) + } + + return u.repo.ExistByNameInOrganization(ctx, *organizationId, policyTemplateName) } -func (u *PolicyTemplateUsecase) IsPolicyTemplateKindExist(ctx context.Context, policyTemplateKind string) (bool, error) { - return u.repo.ExistByKind(ctx, policyTemplateKind) +func (u *PolicyTemplateUsecase) IsPolicyTemplateKindExist(ctx context.Context, organizationId *string, policyTemplateKind string) (bool, error) { + if organizationId == nil { + return u.repo.ExistByKind(ctx, policyTemplateKind) + } + + return u.repo.ExistByKindInOrganization(ctx, *organizationId, policyTemplateKind) } -func (u *PolicyTemplateUsecase) GetPolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, version string) (policyTemplateVersionsReponse *model.PolicyTemplate, err error) { +func (u *PolicyTemplateUsecase) GetPolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, version string) (policyTemplateVersionsReponse *model.PolicyTemplate, err error) { policyTemplate, err := u.repo.GetPolicyTemplateVersion(ctx, policyTemplateId, version) if err != nil { return nil, err } + if !policyTemplate.IsPermittedToOrganization(organizationId) { + return nil, httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + return policyTemplate, nil } -func (u *PolicyTemplateUsecase) ListPolicyTemplateVersions(ctx context.Context, policyTemplateId uuid.UUID) (policyTemplateVersionsReponse *domain.ListPolicyTemplateVersionsResponse, err error) { +func (u *PolicyTemplateUsecase) ListPolicyTemplateVersions(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID) (policyTemplateVersionsReponse *domain.ListPolicyTemplateVersionsResponse, err error) { + policyTemplate, err := u.repo.GetByID(ctx, policyTemplateId) + + if err != nil { + return nil, err + } + + if !policyTemplate.IsPermittedToOrganization(organizationId) { + return nil, httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + return u.repo.ListPolicyTemplateVersions(ctx, policyTemplateId) } -func (u *PolicyTemplateUsecase) DeletePolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, version string) (err error) { +func (u *PolicyTemplateUsecase) DeletePolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, version string) (err error) { + policyTemplate, err := u.repo.GetPolicyTemplateVersion(ctx, policyTemplateId, version) + + if err != nil { + return err + } + + if policyTemplate == nil { + return httpErrors.NewBadRequestError(fmt.Errorf( + "failed to fetch policy template"), + "PT_FAILED_FETCH_POLICY_TEMPLATE", "") + } + + if !policyTemplate.IsPermittedToOrganization(organizationId) { + // 다른 Organization의 템플릿을 조작하려고 함, 보안을 위해서 해당 식별자 존재 자체를 알려주면 안되므로 not found + if *organizationId != *policyTemplate.OrganizationId { + return httpErrors.NewNotFoundError(fmt.Errorf( + "policy template version not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + + return httpErrors.NewForbiddenError(fmt.Errorf( + "cannot delete tks policy template version"), + "PT_NOT_PERMITTED_ON_TKS_POLICY_TEMPLATE", "") + } + return u.repo.DeletePolicyTemplateVersion(ctx, policyTemplateId, version) } -func (u *PolicyTemplateUsecase) CreatePolicyTemplateVersion(ctx context.Context, policyTemplateId uuid.UUID, newVersion string, schema []domain.ParameterDef, rego string, libs []string) (version string, err error) { +func (u *PolicyTemplateUsecase) CreatePolicyTemplateVersion(ctx context.Context, organizationId *string, policyTemplateId uuid.UUID, newVersion string, schema []domain.ParameterDef, rego string, libs []string) (version string, err error) { + policyTemplate, err := u.repo.GetByID(ctx, policyTemplateId) + + if err != nil { + return "", err + } + + if policyTemplate == nil { + return "", httpErrors.NewBadRequestError(fmt.Errorf( + "failed to fetch policy template"), + "PT_FAILED_FETCH_POLICY_TEMPLATE", "") + } + + if !policyTemplate.IsPermittedToOrganization(organizationId) { + // 다른 Organization의 템플릿을 조작하려고 함, 보안을 위해서 해당 식별자 존재 자체를 알려주면 안되므로 not found + if *organizationId != *policyTemplate.OrganizationId { + return "", httpErrors.NewNotFoundError(fmt.Errorf( + "policy template version not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + + return "", httpErrors.NewForbiddenError(fmt.Errorf( + "cannot crate tks policy template version"), + "PT_NOT_PERMITTED_ON_TKS_POLICY_TEMPLATE", "") + } + return u.repo.CreatePolicyTemplateVersion(ctx, policyTemplateId, newVersion, schema, rego, libs) } diff --git a/internal/usecase/policy.go b/internal/usecase/policy.go index 4f7da889..aac394e3 100644 --- a/internal/usecase/policy.go +++ b/internal/usecase/policy.go @@ -59,7 +59,7 @@ func (u *PolicyUsecase) Create(ctx context.Context, organizationId string, dto m } if exists { - return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "PT_CREATE_ALREADY_EXISTED_NAME", "policy template name already exists") + return uuid.Nil, httpErrors.NewBadRequestError(httpErrors.DuplicateResource, "P_CREATE_ALREADY_EXISTED_NAME", "policy name already exists") } dto.TargetClusters = make([]model.Cluster, len(dto.TargetClusterIds)) @@ -72,6 +72,18 @@ func (u *PolicyUsecase) Create(ctx context.Context, organizationId string, dto m dto.TargetClusters[i] = cluster } + policyTemplate, err := u.templateRepo.GetByID(ctx, dto.TemplateId) + + if err != nil { + return uuid.Nil, err + } + + if !policyTemplate.IsPermittedToOrganization(&organizationId) { + return uuid.Nil, httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + userId := user.GetUserId() dto.CreatorId = &userId @@ -117,6 +129,18 @@ func (u *PolicyUsecase) Update(ctx context.Context, organizationId string, polic } if templateId != nil { + policyTemplate, err := u.templateRepo.GetByID(ctx, *templateId) + + if err != nil { + return err + } + + if !policyTemplate.IsPermittedToOrganization(&organizationId) { + return httpErrors.NewNotFoundError(fmt.Errorf( + "policy template not found"), + "PT_NOT_FOUND_POLICY_TEMPLATE", "") + } + updateMap["template_id"] = templateId } diff --git a/pkg/domain/admin/policy-template.go b/pkg/domain/admin/policy-template.go new file mode 100644 index 00000000..9c56af9c --- /dev/null +++ b/pkg/domain/admin/policy-template.go @@ -0,0 +1,179 @@ +package admin + +import ( + "time" + + "github.com/google/uuid" + "github.com/openinfradev/tks-api/pkg/domain" +) + +type PermittedOrganization struct { + OrganizationId string `json:"organizationId"` + OrganizationName string `json:"organizationName"` + Permitted bool `json:"permitted"` +} + +type PolicyTemplateResponse struct { + ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` + Type string `json:"type" enums:"tks,organization" example:"tks"` + Creator domain.SimpleUserResponse `json:"creator"` + Updator domain.SimpleUserResponse `json:"updator"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + + TemplateName string `json:"templateName" example:"필수 Label 검사"` + Kind string `json:"kind" example:"K8sRequiredLabels"` + Severity string `json:"severity" enums:"low,medium,high" example:"medium"` + Deprecated bool `json:"deprecated" example:"false"` + Version string `json:"version,omitempty" example:"v1.0.1"` + Description string `json:"description,omitempty" example:"이 정책은 ..."` + ParametersSchema []domain.ParameterDef `json:"parametersSchema,omitempty"` + Rego string `json:"rego" example:"rego 코드"` + Libs []string `json:"libs" example:"rego 코드"` + + PermittedOrganizations []PermittedOrganization `json:"permittedOrganizations"` +} + +type SimplePolicyTemplateResponse struct { + ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` + Type string `json:"type" enums:"tks,organization" example:"tks"` + Name string `json:"templateName" example:"필수 Label 검사"` + Version string `json:"version,omitempty" example:"v1.0.1"` + Description string `json:"description,omitempty" example:"이 정책은 ..."` +} + +type CreatePolicyTemplateRequest struct { + TemplateName string `json:"templateName" example:"필수 Label 검사" validate:"name"` + Kind string `json:"kind" example:"K8sRequiredLabels" validate:"required"` + Severity string `json:"severity" enums:"low,medium,high" example:"medium"` + Deprecated bool `json:"deprecated" example:"false"` + Description string `json:"description,omitempty" example:"이 정책은 ..."` + ParametersSchema []domain.ParameterDef `json:"parametersSchema,omitempty"` + // "type: object\nproperties: message:\n type: string\n labels:\n type: array\n items:\n type: object\n properties:\n key:\n type: string\n allowedRegex:\n type: string" + + Rego string `json:"rego" example:"rego 코드" validate:"required"` + Libs []string `json:"libs" example:"rego 코드"` + + PermittedOrganizationIds []string `json:"permittedOrganizationIds"` +} + +type CreatePolicyTemplateReponse struct { + ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` +} + +type CreateOrganizationPolicyTemplateReponse struct { + ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` +} + +type UpdateCommmonPolicyTemplateRequest struct { + TemplateName string `json:"templateName" example:"필수 Label 검사"` + Description string `json:"description,omitempty"` + Severity string `json:"severity" enums:"low,medium,high" example:"medium"` + Deprecated bool `json:"deprecated" example:"false"` + // Tags []string `json:"tags,omitempty"` +} + +type UpdatePolicyTemplateUpdate struct { + ID uuid.UUID + Type string + UpdatorId uuid.UUID + TemplateName *string + Description *string + Severity *string + Deprecated *bool + PermittedOrganizationIds *[]string +} + +func (dto *UpdatePolicyTemplateUpdate) IsNothingToUpdate() bool { + return dto.TemplateName == nil && + dto.Description == nil && + dto.Severity == nil && + dto.Deprecated == nil && + dto.PermittedOrganizationIds == nil +} + +type UpdatePolicyTemplateRequest struct { + TemplateName *string `json:"templateName,omitempty" example:"필수 Label 검사"` + Description *string `json:"description,omitempty"` + Severity *string `json:"severity,omitempty" enums:"low,medium,high" example:"medium"` + Deprecated *bool `json:"deprecated,omitempty" example:"false"` + PermittedOrganizationIds *[]string `json:"permittedOrganizationIds,omitempty"` +} + +type UpdateOrganizationPolicyTemplateRequest struct { + UpdateCommmonPolicyTemplateRequest + Mandatory bool `json:"mandatory"` +} + +type GetPolicyTemplateDeployResponse struct { + DeployVersion map[string]string `json:"deployVersion"` +} + +type GetOrganizationPolicyTemplateDeployResponse struct { + DeployVersion map[string]string `json:"deployVersion"` +} + +type ListPolicyTemplateVersionsResponse struct { + Versions []string `json:"versions" example:"v1.1.0,v1.0.1,v1.0.0"` +} + +type ListOrganizationPolicyTemplateVersionsResponse struct { + Versions []string `json:"versions" example:"v1.1.0,v1.0.1,v1.0.0"` +} + +type GetPolicyTemplateVersionResponse struct { + PolicyTemplate PolicyTemplateResponse `json:"policyTemplate"` +} + +type CreatePolicyTemplateVersionRequest struct { + VersionUpType string `json:"versionUpType" enums:"major,minor,patch" example:"minor" validate:"required"` + CurrentVersion string `json:"currentVersion" example:"v1.0.0" validate:"required"` + ExpectedVersion string `json:"expectedVersion" example:"v1.1.0" validate:"required"` + + ParametersSchema []domain.ParameterDef `json:"parametersSchema,omitempty"` + // "type: object\nproperties: message:\n type: string\n labels:\n type: array\n items:\n type: object\n properties:\n key:\n type: string\n allowedRegex:\n type: string" + + Rego string `json:"rego" example:"rego 코드" validate:"required"` + Libs []string `json:"libs" example:"rego 코드"` +} + +type CreatePolicyTemplateVersionResponse struct { + Version string `json:"version" example:"v1.1.1"` +} + +type GetPolicyTemplateResponse struct { + PolicyTemplate PolicyTemplateResponse `json:"policyTemplate"` +} + +type ListPolicyTemplateResponse struct { + PolicyTemplates []PolicyTemplateResponse `json:"policyTemplates"` + Pagination domain.PaginationResponse `json:"pagination"` +} + +type PolicyTemplateStatistics struct { + OrganizationId string `json:"organizationId"` + OrganizationName string `json:"organizationName"` + UsageCount int `json:"usageCount"` +} + +type ListPolicyTemplateStatisticsResponse struct { + PolicyTemplateStatistics []PolicyTemplateStatistics `json:"policyTemplateStatistics"` +} + +type ExistsPolicyTemplateNameResponse struct { + Existed bool `json:"existed"` +} + +type ExistsPolicyTemplateKindResponse struct { + Existed bool `json:"existed"` +} + +type RegoCompileRequest struct { + Rego string `json:"rego" example:"Rego 코드" validate:"required"` + Libs []string `json:"libs,omitempty"` +} + +type RegoCompileResponse struct { + ParametersSchema []*domain.ParameterDef `json:"parametersSchema,omitempty"` + Errors []domain.RegoCompieError `json:"errors,omitempty"` +} diff --git a/pkg/domain/policy-template.go b/pkg/domain/policy-template.go index ea9998ba..e57fd772 100644 --- a/pkg/domain/policy-template.go +++ b/pkg/domain/policy-template.go @@ -6,41 +6,6 @@ import ( "github.com/google/uuid" ) -type CommonPolicyTemplate struct { - ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` - Type string `json:"type" enums:"tks,organization" example:"tks"` - Creator SimpleUserResponse `json:"creator,omitempty"` - Updator SimpleUserResponse `json:"updator,omitempty"` - CreatedAt time.Time `json:"createdAt" format:"date-time"` - UpdatedAt time.Time `json:"updatedAt" format:"date-time"` - - TemplateName string `json:"templateName" example:"필수 Label 검사"` - Kind string `json:"kind" example:"K8sRequiredLabels"` - Severity string `json:"severity" enums:"low,medium,high" example:"medium"` - Deprecated bool `json:"deprecated" example:"false"` - Version string `json:"version,omitempty" example:"v1.0.1"` - Description string `json:"description,omitempty" example:"이 정책은 ..."` - ParametersSchema []ParameterDef `json:"parametersSchema,omitempty"` - // Target string `json:"target,omitempty" example:"admission.k8s.gatekeeper.sh"` - // "type: object\nproperties: message:\n type: string\n labels:\n type: array\n items:\n type: object\n properties:\n key:\n type: string\n allowedRegex:\n type: string" - - Rego string `json:"rego" example:"rego 코드"` - Libs []string `json:"libs" example:"rego 코드"` - - // Tags []string `json:"tags,omitempty" example:"k8s,label"` -} - -type OrganizationPolicyTemplate struct { - Mandatory bool `json:"mandatory"` - CommonPolicyTemplate -} - -type PermittedOrganization struct { - OrganizationId string `json:"organizationId"` - OrganizationName string `json:"organizationName"` - Permitted bool `json:"permitted"` -} - type PolicyTemplateResponse struct { ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` Type string `json:"type" enums:"tks,organization" example:"tks"` @@ -58,8 +23,6 @@ type PolicyTemplateResponse struct { ParametersSchema []ParameterDef `json:"parametersSchema,omitempty"` Rego string `json:"rego" example:"rego 코드"` Libs []string `json:"libs" example:"rego 코드"` - - PermittedOrganizations []PermittedOrganization `json:"permittedOrganizations"` } type SimplePolicyTemplateResponse struct { @@ -70,48 +33,6 @@ type SimplePolicyTemplateResponse struct { Description string `json:"description,omitempty" example:"이 정책은 ..."` } -/* -type PolicyTemplate struct { - ID PolicyTemplateId - Type string - CreatorId *uuid.UUID - Creator User - UpdatorId *uuid.UUID - Updator User - CreatedAt time.Time - UpdatedAt time.Time - - TemplateName string - Kind string - Severity string - Deprecated bool - Version string - Description string - ParametersSchema []ParameterDef - - Rego string - Libs []string - - PermittedOrganizationIds []string // 생성 시에만 사용 - PermittedOrganizations []PermittedOrganization -} -*/ - -type CreateCommonPolicyTemplateRequest struct { - TemplateName string `json:"templateName" example:"필수 Label 검사" validate:"name"` - Kind string `json:"kind" example:"K8sRequiredLabels" validate:"required"` - Severity string `json:"severity" enums:"low,medium,high" example:"medium"` - Deprecated bool `json:"deprecated" example:"false"` - Description string `json:"description,omitempty" example:"이 정책은 ..."` - ParametersSchema []ParameterDef `json:"parametersSchema,omitempty"` - // "type: object\nproperties: message:\n type: string\n labels:\n type: array\n items:\n type: object\n properties:\n key:\n type: string\n allowedRegex:\n type: string" - - Rego string `json:"rego" example:"rego 코드" validate:"required"` - Libs []string `json:"libs" example:"rego 코드"` - - // Tags []string `json:"tags,omitempty" example:"k8s,label"` -} - type CreatePolicyTemplateRequest struct { TemplateName string `json:"templateName" example:"필수 Label 검사" validate:"name"` Kind string `json:"kind" example:"K8sRequiredLabels" validate:"required"` @@ -127,19 +48,10 @@ type CreatePolicyTemplateRequest struct { PermittedOrganizationIds []string `json:"permittedOrganizationIds"` } -type CreateOrganizationPolicyTemplateRequest struct { - CreateCommonPolicyTemplateRequest - Mandatory bool `json:"mandatory"` -} - type CreatePolicyTemplateReponse struct { ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` } -type CreateOrganizationPolicyTemplateReponse struct { - ID string `json:"id" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` -} - type UpdateCommmonPolicyTemplateRequest struct { TemplateName string `json:"templateName" example:"필수 Label 검사"` Description string `json:"description,omitempty"` @@ -175,38 +87,18 @@ type UpdatePolicyTemplateRequest struct { PermittedOrganizationIds *[]string `json:"permittedOrganizationIds,omitempty"` } -type UpdateOrganizationPolicyTemplateRequest struct { - UpdateCommmonPolicyTemplateRequest - Mandatory bool `json:"mandatory"` -} - -// type GetPolicyTemplateVersionResponse struct { -// PolicyTemplate PolicyTemplate `json:"policyTemplate"` -// } type GetPolicyTemplateDeployResponse struct { DeployVersion map[string]string `json:"deployVersion"` } -type GetOrganizationPolicyTemplateDeployResponse struct { - DeployVersion map[string]string `json:"deployVersion"` -} - type ListPolicyTemplateVersionsResponse struct { Versions []string `json:"versions" example:"v1.1.0,v1.0.1,v1.0.0"` } -type ListOrganizationPolicyTemplateVersionsResponse struct { - Versions []string `json:"versions" example:"v1.1.0,v1.0.1,v1.0.0"` -} - type GetPolicyTemplateVersionResponse struct { PolicyTemplate PolicyTemplateResponse `json:"policyTemplate"` } -type GetOrganizationPolicyTemplateVersionResponse struct { - PolicyTemplate OrganizationPolicyTemplate `json:"policyTemplate"` -} - type CreatePolicyTemplateVersionRequest struct { VersionUpType string `json:"versionUpType" enums:"major,minor,patch" example:"minor" validate:"required"` CurrentVersion string `json:"currentVersion" example:"v1.0.0" validate:"required"` @@ -219,68 +111,43 @@ type CreatePolicyTemplateVersionRequest struct { Libs []string `json:"libs" example:"rego 코드"` } -type CreateOrganizationPolicyTemplateVersionRequest struct { - CreatePolicyTemplateVersionRequest -} - type CreatePolicyTemplateVersionResponse struct { Version string `json:"version" example:"v1.1.1"` } -type CreateOrganizationPolicyTemplateVersionResponse struct { - Version string `json:"version" example:"v1.1.1"` -} - type GetPolicyTemplateResponse struct { PolicyTemplate PolicyTemplateResponse `json:"policyTemplate"` } -type GetOrganizationPolicyTemplateResponse struct { - PolicyTemplate OrganizationPolicyTemplate `json:"policyTemplate"` -} - type ListPolicyTemplateResponse struct { PolicyTemplates []PolicyTemplateResponse `json:"policyTemplates"` Pagination PaginationResponse `json:"pagination"` } -type ListOrganizationPolicyTemplateResponse struct { - PolicyTemplates []OrganizationPolicyTemplate `json:"policyTemplates"` - Pagination PaginationResponse `json:"pagination"` -} - type PolicyTemplateStatistics struct { OrganizationId string `json:"organizationId"` OrganizationName string `json:"organizationName"` UsageCount int `json:"usageCount"` } -type OrganizationPolicyTemplateStatistics struct { - OrganizationId string `json:"organizationId"` - OrganizationName string `json:"organizationName"` - UsageCount int `json:"usageCount"` -} - type ListPolicyTemplateStatisticsResponse struct { PolicyTemplateStatistics []PolicyTemplateStatistics `json:"policyTemplateStatistics"` } -type ListOrganizationPolicyTemplateStatisticsResponse struct { - PolicyTemplateStatistics []OrganizationPolicyTemplateStatistics `json:"policyTemplateStatistics"` -} - type ExistsPolicyTemplateNameResponse struct { + Existed bool `json:"existed"` } type ExistsPolicyTemplateKindResponse struct { + Existed bool `json:"existed"` } type ParameterDef struct { - Key string `json:"key"` - Type string `json:"type"` + Key string `json:"key" exmaples:"repos"` + Type string `json:"type" examples:"string[]"` DefaultValue string `json:"defaultValue"` Children []*ParameterDef `json:"children"` - IsArray bool `json:"isArray"` + IsArray bool `json:"isArray" examples:"true"` } type RegoCompileRequest struct { diff --git a/pkg/domain/policy.go b/pkg/domain/policy.go index e2ccf0e0..ddb45490 100644 --- a/pkg/domain/policy.go +++ b/pkg/domain/policy.go @@ -53,7 +53,6 @@ type CreatePolicyRequest struct { PolicyName string `json:"policyName" example:"label 정책"` Description string `json:"description"` TemplateId string `json:"templateId" example:"d98ef5f1-4a68-4047-a446-2207787ce3ff"` - TemplateName string `json:"templateName" example:"필수 Label 검사"` EnforcementAction string `json:"enforcementAction" enum:"warn,deny,dryrun"` Parameters string `json:"parameters" example:"\"labels\":{\"key\":\"owner\",\"allowedRegex:^[a-zA-Z]+.agilebank.demo$}\""` Match *Match `json:"match,omitempty" swaggertype:"object,string" example:"refer:match.Match"` diff --git a/pkg/httpErrors/errorCode.go b/pkg/httpErrors/errorCode.go index 9f0e39f0..06444f8d 100644 --- a/pkg/httpErrors/errorCode.go +++ b/pkg/httpErrors/errorCode.go @@ -115,17 +115,18 @@ var errorMap = map[ErrorCode]string{ "ST_FAILED_DELETE_EXIST_CLUSTERS": "스택템플릿을 사용하고 있는 스택이 있습니다. 스택을 삭제하세요.", // PolicyTemplate - "PT_CREATE_ALREADY_EXISTED_NAME": "정첵 템플릿에 이미 존재하는 이름입니다.", - "PT_CREATE_ALREADY_EXISTED_KIND": "정책 템플릿에 이미 존재하는 유형입니다.", - "PT_NOT_FOUND_POLICY_TEMPLATE": "정책 템플릿이 존재하지 않습니다.", - "PT_INVALID_KIND": "유효하지 않은 정책 템플릿 유형입니다. 정책 템플릿 유형을 확인하세요.", - "PT_FAILED_FETCH_POLICY_TEMPLATE": "정책 템플릿 ID에 해당하는 정책 템플릿을 가져오는데 실패했습니다.", - "PT_INVALID_REGO_SYNTAX": "Rego 문법 오류입니다.", - "PT_INVALID_POLICY_TEMPLATE_VERSION": "유효하지 않은 정책 템플릿 버전닙니다. 정책 템플릿 버전을 확인하세요.", - "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION": "정책 템플릿 버전이 존재하지 않습니다.", - "PT_INVALID_POLICY_TEMPLATE_NAME": "유효하지 않은 정책 템플릿 이름입니다. 정책 템플릿 이름을 확인하세요.", - "PT_INVALID_POLICY_TEMPLATE_KIND": "유효하지 않은 정책 템플릿 유형입니다. 정책 템플릿 유형을 확인하세요.", - "PT_INVALID_REGO_PARSEPARAMETER": "유효하지 않은 Rego 파싱 설정입니다. Rego 파싱 설정을 확인하세요.", + "PT_CREATE_ALREADY_EXISTED_NAME": "정첵 템플릿에 이미 존재하는 이름입니다.", + "PT_CREATE_ALREADY_EXISTED_KIND": "정책 템플릿에 이미 존재하는 유형입니다.", + "PT_NOT_FOUND_POLICY_TEMPLATE": "정책 템플릿이 존재하지 않습니다.", + "PT_INVALID_KIND": "유효하지 않은 정책 템플릿 유형입니다. 정책 템플릿 유형을 확인하세요.", + "PT_FAILED_FETCH_POLICY_TEMPLATE": "정책 템플릿 ID에 해당하는 정책 템플릿을 가져오는데 실패했습니다.", + "PT_INVALID_REGO_SYNTAX": "Rego 문법 오류입니다.", + "PT_INVALID_POLICY_TEMPLATE_VERSION": "유효하지 않은 정책 템플릿 버전닙니다. 정책 템플릿 버전을 확인하세요.", + "PT_NOT_FOUND_POLICY_TEMPLATE_VERSION": "정책 템플릿 버전이 존재하지 않습니다.", + "PT_INVALID_POLICY_TEMPLATE_NAME": "유효하지 않은 정책 템플릿 이름입니다. 정책 템플릿 이름을 확인하세요.", + "PT_INVALID_POLICY_TEMPLATE_KIND": "유효하지 않은 정책 템플릿 유형입니다. 정책 템플릿 유형을 확인하세요.", + "PT_INVALID_REGO_PARSEPARAMETER": "유효하지 않은 Rego 파싱 설정입니다. Rego 파싱 설정을 확인하세요.", + "PT_NOT_PERMITTED_ON_TKS_POLICY_TEMPLATE": "tks 템플릿에 대해 해당 동작을 수행할 수 없습니다.", // Policy "P_CREATE_ALREADY_EXISTED_NAME": "정첵에 이미 존재하는 이름입니다.",