diff --git a/agent/main.go b/agent/main.go index e9444a790f19a2deb28ca349a7c7a6131db9d288..804f53f9fc1a2e412508b9acb2fe905847eb3be6 100644 --- a/agent/main.go +++ b/agent/main.go @@ -118,7 +118,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin api.WebSocketRoutes(ginApp, &eventHandlers) - if config.Config.OAS { + if config.Config.OAS.Enable { routes.OASRoutes(ginApp) } @@ -200,7 +200,7 @@ func runInHarReaderMode() { } func enableExpFeatureIfNeeded() { - if config.Config.OAS { + if config.Config.OAS.Enable { oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator) oasGenerator.Start() } @@ -227,7 +227,7 @@ func setUIFlags(uiIndexPath string) error { return err } - replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS), 1) + replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS.Enable), 1) replacedContent = strings.Replace(replacedContent, "__IS_SERVICE_MAP_ENABLED__", strconv.FormatBool(config.Config.ServiceMap), 1) err = ioutil.WriteFile(uiIndexPath, []byte(replacedContent), 0) @@ -363,7 +363,7 @@ func handleIncomingMessageAsTapper(socketConnection *websocket.Conn) { func initializeDependencies() { dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() }) - dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance() }) + dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance(config.Config.OAS.MaxExampleLen) }) dependency.RegisterGenerator(dependency.EntriesInserter, func() interface{} { return api.GetBasenineEntryInserterInstance() }) dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} }) dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} }) diff --git a/agent/pkg/controllers/oas_controller_test.go b/agent/pkg/controllers/oas_controller_test.go index 0a588c567e5bd76f97813cdb3b90fa00982169be..d86a633aa97767756eb5455c79ba7d653d84d877 100644 --- a/agent/pkg/controllers/oas_controller_test.go +++ b/agent/pkg/controllers/oas_controller_test.go @@ -34,12 +34,12 @@ func TestGetOASSpec(t *testing.T) { func getRecorderAndContext() (*httptest.ResponseRecorder, *gin.Context) { dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { - return oas.GetDefaultOasGeneratorInstance() + return oas.GetDefaultOasGeneratorInstance(-1) }) recorder := httptest.NewRecorder() c, _ := gin.CreateTestContext(recorder) - oas.GetDefaultOasGeneratorInstance().Start() - oas.GetDefaultOasGeneratorInstance().GetServiceSpecs().Store("some", oas.NewGen("some")) + oas.GetDefaultOasGeneratorInstance(-1).Start() + oas.GetDefaultOasGeneratorInstance(-1).GetServiceSpecs().Store("some", oas.NewGen("some")) return recorder, c } diff --git a/agent/pkg/oas/ignores.go b/agent/pkg/oas/ignores.go index ae3be924f28b6105a33a17066e09e45b50d139a0..fd3195688366c27a36438d854bceef5464969604 100644 --- a/agent/pkg/oas/ignores.go +++ b/agent/pkg/oas/ignores.go @@ -9,7 +9,7 @@ var ignoredCtypes = []string{"application/javascript", "application/x-javascript var ignoredHeaders = []string{ "a-im", "accept", - "authorization", "cache-control", "connection", "content-encoding", "content-length", "content-type", "cookie", + "authorization", "cache-control", "connection", "content-encoding", "content-length", "content-range", "content-type", "cookie", "date", "dnt", "expect", "forwarded", "from", "front-end-https", "host", "http2-settings", "max-forwards", "origin", "pragma", "proxy-authorization", "proxy-connection", "range", "referer", "save-data", "te", "trailer", "transfer-encoding", "upgrade", "upgrade-insecure-requests", "x-download-options", diff --git a/agent/pkg/oas/oas_generator.go b/agent/pkg/oas/oas_generator.go index 39bf2f0bcb1f0c513cf2f2614562b5d2df0ccc8f..b16ab3e7a216bde4568838cc7494aba9141e9084 100644 --- a/agent/pkg/oas/oas_generator.go +++ b/agent/pkg/oas/oas_generator.go @@ -28,13 +28,14 @@ type OasGenerator interface { } type defaultOasGenerator struct { - started bool - serviceSpecs *sync.Map + started bool + serviceSpecs *sync.Map + maxExampleLen int } -func GetDefaultOasGeneratorInstance() *defaultOasGenerator { +func GetDefaultOasGeneratorInstance(maxExampleLen int) *defaultOasGenerator { syncOnce.Do(func() { - instance = NewDefaultOasGenerator() + instance = NewDefaultOasGenerator(maxExampleLen) logger.Log.Debug("OAS Generator Initialized") }) return instance @@ -117,6 +118,7 @@ func (g *defaultOasGenerator) getGen(dest string, urlStr string) *SpecGen { var gen *SpecGen if !found { gen = NewGen(u.Scheme + "://" + dest) + gen.MaxExampleLen = g.maxExampleLen g.serviceSpecs.Store(dest, gen) } else { gen = val.(*SpecGen) @@ -132,9 +134,10 @@ func (g *defaultOasGenerator) GetServiceSpecs() *sync.Map { return g.serviceSpecs } -func NewDefaultOasGenerator() *defaultOasGenerator { +func NewDefaultOasGenerator(maxExampleLen int) *defaultOasGenerator { return &defaultOasGenerator{ - started: false, - serviceSpecs: &sync.Map{}, + started: false, + serviceSpecs: &sync.Map{}, + maxExampleLen: maxExampleLen, } } diff --git a/agent/pkg/oas/oas_generator_test.go b/agent/pkg/oas/oas_generator_test.go index b364b4d57784a1729ce0afc045ea4be50da17933..e7e748e9a00abcb8578d40bca2ba100bc4192957 100644 --- a/agent/pkg/oas/oas_generator_test.go +++ b/agent/pkg/oas/oas_generator_test.go @@ -8,7 +8,7 @@ import ( ) func TestOASGen(t *testing.T) { - gen := GetDefaultOasGeneratorInstance() + gen := GetDefaultOasGeneratorInstance(-1) e := new(har.Entry) err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e) diff --git a/agent/pkg/oas/specgen.go b/agent/pkg/oas/specgen.go index 2b39e2b032bac03ff8a198c86fbd773f711c3508..d4528f454162b46b4d884aae1909a9638009f1c3 100644 --- a/agent/pkg/oas/specgen.go +++ b/agent/pkg/oas/specgen.go @@ -42,6 +42,8 @@ type reqResp struct { // hello, generics in Go } type SpecGen struct { + MaxExampleLen int // -1 unlimited, 0 and above sets limit + oas *openapi.OpenAPI tree *Node lock sync.Mutex @@ -59,7 +61,11 @@ func NewGen(server string) *SpecGen { spec.Servers = make([]*openapi.Server, 0) spec.Servers = append(spec.Servers, &openapi.Server{URL: server}) - gen := SpecGen{oas: spec, tree: new(Node)} + gen := SpecGen{ + oas: spec, + tree: new(Node), + MaxExampleLen: -1, + } return &gen } @@ -228,7 +234,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error split = strings.Split(urlParsed.Path, "/") } node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id) - opObj, err := handleOpObj(entryWithSource, node.pathObj) + opObj, err := handleOpObj(entryWithSource, node.pathObj, g.MaxExampleLen) if opObj != nil { return opObj.OperationID, err @@ -237,7 +243,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error return "", err } -func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*openapi.Operation, error) { +func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj, limit int) (*openapi.Operation, error) { entry := entryWithSource.Entry isSuccess := 100 <= entry.Response.Status && entry.Response.Status < 400 opObj, wasMissing, err := getOpObj(pathObj, entry.Request.Method, isSuccess) @@ -250,12 +256,12 @@ func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*o return nil, nil } - err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id) + err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id, limit) if err != nil { return nil, err } - err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id) + err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id, limit) if err != nil { return nil, err } @@ -342,7 +348,7 @@ func handleCounters(opObj *openapi.Operation, success bool, entryWithSource *Ent return nil } -func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string) error { +func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error { // TODO: we don't handle the situation when header/qstr param can be defined on pathObj level. Also the path param defined on opObj urlParsed, err := url.Parse(req.URL) if err != nil { @@ -390,7 +396,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s } else { reqCtype, _ := getReqCtype(req) - reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId) + reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId, limit) if err != nil { return err } @@ -402,7 +408,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s return nil } -func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string) error { +func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error { // TODO: we don't support "default" response respObj, err := getResponseObj(resp, opObj, isSuccess) if err != nil { @@ -415,7 +421,7 @@ func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool respCtype := getRespCtype(resp) respContent := respObj.Content - respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId) + respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId, limit) if err != nil { return err } @@ -467,7 +473,7 @@ func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj, sa } } -func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string) (*openapi.MediaType, error) { +func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string, limit int) (*openapi.MediaType, error) { content, found := respContent[ctype] if !found { respContent[ctype] = &openapi.MediaType{} @@ -510,7 +516,7 @@ func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sam handleFormDataMultipart(text, content, params) } - if content.Example == nil && len(exampleMsg) > len(content.Example) { + if len(exampleMsg) > len(content.Example) && (limit < 0 || len(exampleMsg) <= limit) { content.Example = exampleMsg } } diff --git a/agent/pkg/oas/specgen_test.go b/agent/pkg/oas/specgen_test.go index f9f501b98f595a47e9fbc5dbbe012c350085c7e8..eaba63eeccc760b633153af43c1dc2c1a6427b59 100644 --- a/agent/pkg/oas/specgen_test.go +++ b/agent/pkg/oas/specgen_test.go @@ -48,7 +48,7 @@ func TestEntries(t *testing.T) { t.FailNow() } - gen := NewDefaultOasGenerator() + gen := NewDefaultOasGenerator(-1) gen.serviceSpecs = new(sync.Map) loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs) loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs) @@ -122,7 +122,7 @@ func TestEntries(t *testing.T) { } func TestFileSingle(t *testing.T) { - gen := NewDefaultOasGenerator() + gen := NewDefaultOasGenerator(-1) gen.serviceSpecs = new(sync.Map) // loadStartingOAS() file := "test_artifacts/params.har" @@ -212,7 +212,7 @@ func loadStartingOAS(file string, label string, specs *sync.Map) { } func TestEntriesNegative(t *testing.T) { - gen := NewDefaultOasGenerator() + gen := NewDefaultOasGenerator(-1) gen.serviceSpecs = new(sync.Map) files := []string{"invalid"} _, err := feedEntries(files, false, gen) @@ -223,7 +223,7 @@ func TestEntriesNegative(t *testing.T) { } func TestEntriesPositive(t *testing.T) { - gen := NewDefaultOasGenerator() + gen := NewDefaultOasGenerator(-1) gen.serviceSpecs = new(sync.Map) files := []string{"test_artifacts/params.har"} _, err := feedEntries(files, false, gen) diff --git a/agent/pkg/oas/test_artifacts/params.har.spec.json b/agent/pkg/oas/test_artifacts/params.har.spec.json index 4b5dcfd6e16ea41e61a04f7c8d0721f2b8bed53e..dddf4a20552278ac61d8a370dff9d972c05a4e91 100644 --- a/agent/pkg/oas/test_artifacts/params.har.spec.json +++ b/agent/pkg/oas/test_artifacts/params.har.spec.json @@ -333,7 +333,7 @@ } } }, - "example": "agent-id=ade\u0026callback-url=\u0026token=sometoken", + "example": "agent-id=ade\u0026callback-url=\u0026token=sometoken-second-val\u0026optional=another", "x-sample-entry": "000000000000000000000008" } }, diff --git a/cli/config/configStruct.go b/cli/config/configStruct.go index 3606a3071772278c822e688ea8a350ff724c88c9..07b8f4a8223839203fef30f2b7043340a36996b3 100644 --- a/cli/config/configStruct.go +++ b/cli/config/configStruct.go @@ -39,7 +39,7 @@ type ConfigStruct struct { HeadlessMode bool `yaml:"headless" default:"false"` LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""` ServiceMap bool `yaml:"service-map" default:"true"` - OAS bool `yaml:"oas" default:"true"` + OAS shared.OASConfig `yaml:"oas"` } func (config *ConfigStruct) validate() error { diff --git a/shared/models.go b/shared/models.go index 5d6c28ae4e8ec201cb1471ef83b63f32aa9664a2..6ec0fbec656a6ef8d56e15c9273b19f4ce6b8288 100644 --- a/shared/models.go +++ b/shared/models.go @@ -32,6 +32,11 @@ type Resources struct { MemoryRequests string `yaml:"memory-requests" default:"50Mi"` } +type OASConfig struct { + Enable bool `yaml:"enabled" default:"true"` + MaxExampleLen int `yaml:"max-example-len" default:"10240"` +} + type MizuAgentConfig struct { MaxDBSizeBytes int64 `json:"maxDBSizeBytes"` InsertionFilter string `json:"insertionFilter"` @@ -42,7 +47,7 @@ type MizuAgentConfig struct { MizuResourcesNamespace string `json:"mizuResourceNamespace"` AgentDatabasePath string `json:"agentDatabasePath"` ServiceMap bool `json:"serviceMap"` - OAS bool `json:"oas"` + OAS OASConfig `json:"oas"` Telemetry bool `json:"telemetry"` }