diff --git a/api/v1alpha1/l7api_types.go b/api/v1alpha1/l7api_types.go index ad2e3361..bef59dc5 100644 --- a/api/v1alpha1/l7api_types.go +++ b/api/v1alpha1/l7api_types.go @@ -1,4 +1,5 @@ -// Copyright (c) 2025 Broadcom Inc. and its subsidiaries. All Rights Reserved. +// Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved. +// AI assistance has been used to generate some or all contents of this file. That includes, but is not limited to, new code, modifying existing code, stylistic edits. package v1alpha1 @@ -74,6 +75,7 @@ type PortalMeta struct { CreateTs int `json:"createTs,omitempty"` ModifyTs int `json:"modifyTs,omitempty"` SsgServiceType string `json:"ssgServiceType,omitempty"` + HttpMethods []HttpMethod `json:"httpMethods,omitempty"` PolicyTemplates []PolicyTemplate `json:"policyEntities,omitempty"` CustomFields []CustomField `json:"customFieldValues,omitempty"` SecurePasswords []SecurePassword `json:"securePasswords,omitempty"` @@ -81,6 +83,19 @@ type PortalMeta struct { Checksum string `json:"checksum,omitempty"` } +type HttpMethod string + +const ( + HttpMethodGet HttpMethod = "GET" + HttpMethodPost HttpMethod = "POST" + HttpMethodPut HttpMethod = "PUT" + HttpMethodPatch HttpMethod = "PATCH" + HttpMethodDelete HttpMethod = "DELETE" + HttpMethodHead HttpMethod = "HEAD" + HttpMethodOptions HttpMethod = "OPTIONS" + HttpMethodOther HttpMethod = "OTHER" +) + type PolicyTemplate struct { Uuid string `json:"policyEntityUuid"` ApiPolicyTemplateArguments []PolicyTemplateArg `json:"policyTemplateArguments"` diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 499d29f1..93fe24b3 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -464,6 +464,11 @@ func (in *PortalAuth) DeepCopy() *PortalAuth { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PortalMeta) DeepCopyInto(out *PortalMeta) { *out = *in + if in.HttpMethods != nil { + in, out := &in.HttpMethods, &out.HttpMethods + *out = make([]HttpMethod, len(*in)) + copy(*out, *in) + } if in.PolicyTemplates != nil { in, out := &in.PolicyTemplates, &out.PolicyTemplates *out = make([]PolicyTemplate, len(*in)) diff --git a/bundle/manifests/security.brcmlabs.com_l7apis.yaml b/bundle/manifests/security.brcmlabs.com_l7apis.yaml index 8d69d0a3..0ac71802 100644 --- a/bundle/manifests/security.brcmlabs.com_l7apis.yaml +++ b/bundle/manifests/security.brcmlabs.com_l7apis.yaml @@ -76,6 +76,10 @@ spec: type: array enabled: type: boolean + httpMethods: + items: + type: string + type: array locationUrl: type: string modifyTs: diff --git a/charts/layer7-operator/crds/l7api-crd.yaml b/charts/layer7-operator/crds/l7api-crd.yaml index fb495ed7..4d050f92 100644 --- a/charts/layer7-operator/crds/l7api-crd.yaml +++ b/charts/layer7-operator/crds/l7api-crd.yaml @@ -75,6 +75,10 @@ spec: type: array enabled: type: boolean + httpMethods: + items: + type: string + type: array locationUrl: type: string modifyTs: diff --git a/config/crd/bases/security.brcmlabs.com_l7apis.yaml b/config/crd/bases/security.brcmlabs.com_l7apis.yaml index df8026a7..fcd42473 100644 --- a/config/crd/bases/security.brcmlabs.com_l7apis.yaml +++ b/config/crd/bases/security.brcmlabs.com_l7apis.yaml @@ -75,6 +75,10 @@ spec: type: array enabled: type: boolean + httpMethods: + items: + type: string + type: array locationUrl: type: string modifyTs: diff --git a/deploy/bundle.yaml b/deploy/bundle.yaml index 3b94dc9a..c981ed54 100644 --- a/deploy/bundle.yaml +++ b/deploy/bundle.yaml @@ -6713,6 +6713,10 @@ spec: type: array enabled: type: boolean + httpMethods: + items: + type: string + type: array locationUrl: type: string modifyTs: diff --git a/internal/templategen/portal-api-restman-template.qtpl b/internal/templategen/portal-api-restman-template.qtpl index a2cdb271..2775cca8 100644 --- a/internal/templategen/portal-api-restman-template.qtpl +++ b/internal/templategen/portal-api-restman-template.qtpl @@ -1,4 +1,6 @@ ---------------------------------------------- +Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved. +AI assistance has been used to generate some or all contents of this file. That includes, but is not limited to, new code, modifying existing code, stylistic edits. Variables Used: @@ -10,6 +12,7 @@ Variables Used: - portalApi.ApiEnabled - portalApi.ModifyTs - portalApi.CustomFields +- portalApi.HttpMethods - apiServiceXml - apiFragmentXml - isSoapAPI @@ -59,7 +62,11 @@ Variables Used: /{%s portalApi.SsgUrl %} - {% if isSoapApi == "true" %} + {% if len(portalApi.HttpMethods) > 0 %} + {% for _, verb := range portalApi.HttpMethods %} + {%s verb %} + {% endfor %} + {% elseif isSoapApi == "true" %} GET POST {% else %} diff --git a/internal/templategen/portal-api-restman-template.qtpl.go b/internal/templategen/portal-api-restman-template.qtpl.go index abf43260..e974f23c 100644 --- a/internal/templategen/portal-api-restman-template.qtpl.go +++ b/internal/templategen/portal-api-restman-template.qtpl.go @@ -2,6 +2,8 @@ // See https://github.com/valyala/quicktemplate for details. // ---------------------------------------------- +// Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved. +// AI assistance has been used to generate some or all contents of this file. That includes, but is not limited to, new code, modifying existing code, stylistic edits. // // // Variables Used: @@ -13,6 +15,7 @@ // - portalApi.ApiEnabled // - portalApi.ModifyTs // - portalApi.CustomFields +// - portalApi.HttpMethods // - apiServiceXml // - apiFragmentXml // - isSoapAPI @@ -21,63 +24,63 @@ // ------------------------------------------------- // -//line portal-api-restman-template.qtpl:20 +//line portal-api-restman-template.qtpl:23 package templategen -//line portal-api-restman-template.qtpl:20 +//line portal-api-restman-template.qtpl:23 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line portal-api-restman-template.qtpl:20 +//line portal-api-restman-template.qtpl:23 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line portal-api-restman-template.qtpl:20 +//line portal-api-restman-template.qtpl:23 func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, apiServiceXml string, apiFragmentXml string, isSoapApi string, wsdl string) { -//line portal-api-restman-template.qtpl:20 +//line portal-api-restman-template.qtpl:23 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:24 +//line portal-api-restman-template.qtpl:27 qw422016.E().S(portalApi.Name) -//line portal-api-restman-template.qtpl:24 +//line portal-api-restman-template.qtpl:27 qw422016.N().S(`-fragment `) -//line portal-api-restman-template.qtpl:25 +//line portal-api-restman-template.qtpl:28 qw422016.E().S(portalApi.UuidStripped) -//line portal-api-restman-template.qtpl:25 +//line portal-api-restman-template.qtpl:28 qw422016.N().S(` POLICY `) -//line portal-api-restman-template.qtpl:30 +//line portal-api-restman-template.qtpl:33 qw422016.E().S(portalApi.Name) -//line portal-api-restman-template.qtpl:30 +//line portal-api-restman-template.qtpl:33 qw422016.N().S(`-fragment Include @@ -86,9 +89,9 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:37 +//line portal-api-restman-template.qtpl:40 qw422016.E().S(isSoapApi) -//line portal-api-restman-template.qtpl:37 +//line portal-api-restman-template.qtpl:40 qw422016.N().S(` @@ -96,9 +99,9 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:43 +//line portal-api-restman-template.qtpl:46 qw422016.E().S(apiFragmentXml) -//line portal-api-restman-template.qtpl:43 +//line portal-api-restman-template.qtpl:46 qw422016.N().S(` @@ -107,52 +110,72 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:50 +//line portal-api-restman-template.qtpl:53 qw422016.E().S(portalApi.Name) -//line portal-api-restman-template.qtpl:50 +//line portal-api-restman-template.qtpl:53 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:51 +//line portal-api-restman-template.qtpl:54 qw422016.E().S(portalApi.ServiceId) -//line portal-api-restman-template.qtpl:51 +//line portal-api-restman-template.qtpl:54 qw422016.N().S(` SERVICE `) -//line portal-api-restman-template.qtpl:56 +//line portal-api-restman-template.qtpl:59 qw422016.E().S(portalApi.Name) -//line portal-api-restman-template.qtpl:56 +//line portal-api-restman-template.qtpl:59 qw422016.N().S(` true /`) -//line portal-api-restman-template.qtpl:60 +//line portal-api-restman-template.qtpl:63 qw422016.E().S(portalApi.SsgUrl) -//line portal-api-restman-template.qtpl:60 +//line portal-api-restman-template.qtpl:63 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:62 - if isSoapApi == "true" { -//line portal-api-restman-template.qtpl:62 +//line portal-api-restman-template.qtpl:65 + if len(portalApi.HttpMethods) > 0 { +//line portal-api-restman-template.qtpl:65 + qw422016.N().S(` + `) +//line portal-api-restman-template.qtpl:66 + for _, verb := range portalApi.HttpMethods { +//line portal-api-restman-template.qtpl:66 + qw422016.N().S(` + `) +//line portal-api-restman-template.qtpl:67 + qw422016.E().S(verb) +//line portal-api-restman-template.qtpl:67 + qw422016.N().S(` + `) +//line portal-api-restman-template.qtpl:68 + } +//line portal-api-restman-template.qtpl:68 + qw422016.N().S(` + `) +//line portal-api-restman-template.qtpl:69 + } else if isSoapApi == "true" { +//line portal-api-restman-template.qtpl:69 qw422016.N().S(` GET POST `) -//line portal-api-restman-template.qtpl:65 +//line portal-api-restman-template.qtpl:72 } else { -//line portal-api-restman-template.qtpl:65 +//line portal-api-restman-template.qtpl:72 qw422016.N().S(` GET POST @@ -162,9 +185,9 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a PATCH HEAD `) -//line portal-api-restman-template.qtpl:73 +//line portal-api-restman-template.qtpl:80 } -//line portal-api-restman-template.qtpl:73 +//line portal-api-restman-template.qtpl:80 qw422016.N().S(` @@ -175,9 +198,9 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:82 +//line portal-api-restman-template.qtpl:89 qw422016.E().S(isSoapApi) -//line portal-api-restman-template.qtpl:82 +//line portal-api-restman-template.qtpl:89 qw422016.N().S(` @@ -188,72 +211,72 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:91 +//line portal-api-restman-template.qtpl:98 qw422016.E().S(portalApi.Uuid) -//line portal-api-restman-template.qtpl:91 +//line portal-api-restman-template.qtpl:98 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:94 +//line portal-api-restman-template.qtpl:101 qw422016.E().V(portalApi.ApiEnabled) -//line portal-api-restman-template.qtpl:94 +//line portal-api-restman-template.qtpl:101 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:97 +//line portal-api-restman-template.qtpl:104 qw422016.N().D(portalApi.ModifyTs) -//line portal-api-restman-template.qtpl:97 +//line portal-api-restman-template.qtpl:104 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:99 +//line portal-api-restman-template.qtpl:106 for _, customField := range portalApi.CustomFields { -//line portal-api-restman-template.qtpl:99 +//line portal-api-restman-template.qtpl:106 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:101 +//line portal-api-restman-template.qtpl:108 qw422016.E().S(customField.Value) -//line portal-api-restman-template.qtpl:101 +//line portal-api-restman-template.qtpl:108 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:103 +//line portal-api-restman-template.qtpl:110 } -//line portal-api-restman-template.qtpl:103 +//line portal-api-restman-template.qtpl:110 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:108 +//line portal-api-restman-template.qtpl:115 qw422016.E().S(apiServiceXml) -//line portal-api-restman-template.qtpl:108 +//line portal-api-restman-template.qtpl:115 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:110 +//line portal-api-restman-template.qtpl:117 if isSoapApi == "true" { -//line portal-api-restman-template.qtpl:110 +//line portal-api-restman-template.qtpl:117 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:112 +//line portal-api-restman-template.qtpl:119 qw422016.E().S(wsdl) -//line portal-api-restman-template.qtpl:112 +//line portal-api-restman-template.qtpl:119 qw422016.N().S(` `) -//line portal-api-restman-template.qtpl:114 +//line portal-api-restman-template.qtpl:121 } -//line portal-api-restman-template.qtpl:114 +//line portal-api-restman-template.qtpl:121 qw422016.N().S(` @@ -262,43 +285,43 @@ func StreamFromRestmamTemplate(qw422016 *qt422016.Writer, portalApi PortalAPI, a `) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 } -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 func WriteFromRestmamTemplate(qq422016 qtio422016.Writer, portalApi PortalAPI, apiServiceXml string, apiFragmentXml string, isSoapApi string, wsdl string) { -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 qw422016 := qt422016.AcquireWriter(qq422016) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 StreamFromRestmamTemplate(qw422016, portalApi, apiServiceXml, apiFragmentXml, isSoapApi, wsdl) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 qt422016.ReleaseWriter(qw422016) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 } -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 func FromRestmamTemplate(portalApi PortalAPI, apiServiceXml string, apiFragmentXml string, isSoapApi string, wsdl string) string { -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 qb422016 := qt422016.AcquireByteBuffer() -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 WriteFromRestmamTemplate(qb422016, portalApi, apiServiceXml, apiFragmentXml, isSoapApi, wsdl) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 qs422016 := string(qb422016.B) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 qt422016.ReleaseByteBuffer(qb422016) -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 return qs422016 -//line portal-api-restman-template.qtpl:125 +//line portal-api-restman-template.qtpl:132 } diff --git a/internal/templategen/templategen.go b/internal/templategen/templategen.go index 7e7235f1..1c8c8afb 100644 --- a/internal/templategen/templategen.go +++ b/internal/templategen/templategen.go @@ -1,3 +1,6 @@ +// Copyright (c) 2026 Broadcom Inc. and its subsidiaries. All Rights Reserved. +// AI assistance has been used to generate some or all contents of this file. That includes, but is not limited to, new code, modifying existing code, stylistic edits. + package templategen type PortalAPI struct { @@ -16,10 +19,11 @@ type PortalAPI struct { LocationUrl string `json:"locationUrl"` // backend full URL //Version string `json:"version"` //ApiEulaUuid string `json:"apiEulaUuid"` - PublishedTs int `json:"publishedTs"` - CreateTs int `json:"createTs"` - ModifyTs int `json:"modifyTs"` - SsgServiceType string `json:"ssgServiceType"` + PublishedTs int `json:"publishedTs"` + CreateTs int `json:"createTs"` + ModifyTs int `json:"modifyTs"` + SsgServiceType string `json:"ssgServiceType"` + HttpMethods []string `json:"httpMethods,omitempty"` //ApplicationUsage int `json:"applicationUsage"` //Tags []string `json:"tags"` PolicyTemplates []PolicyTemplate `json:"policyEntities"` // required by qtpl templates diff --git a/internal/templategen/templategen_test.go b/internal/templategen/templategen_test.go index ff93b78b..db6b2879 100644 --- a/internal/templategen/templategen_test.go +++ b/internal/templategen/templategen_test.go @@ -2,6 +2,7 @@ package templategen import ( b64 "encoding/base64" + "strings" "testing" "time" ) @@ -47,6 +48,32 @@ func TestBuildTemplate(t *testing.T) { t.Errorf("perfTest(portalApi,iterations) = %v, want %v", duration, timeout) } }) + + t.Run("HttpMethods Test", func(t *testing.T) { + restrictedApi := portalApi + restrictedApi.HttpMethods = []string{"GET"} + + got := BuildTemplate(restrictedApi) + + if got == "" { + t.Errorf("BuildTemplate() = %v, want %v", got, "xml string") + } + + if strings.Count(got, "") != 1 { + t.Errorf("BuildTemplate() with HttpMethods=[GET] produced %d entries, want 1", + strings.Count(got, "")) + } + + if !strings.Contains(got, "GET") { + t.Errorf("BuildTemplate() with HttpMethods=[GET] did not contain GET") + } + + for _, verb := range []string{"POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD"} { + if strings.Contains(got, ""+verb+"") { + t.Errorf("BuildTemplate() with HttpMethods=[GET] unexpectedly contained %s", verb) + } + } + }) } func perfTest(portalApi PortalAPI, iterations int) time.Duration {