Skip to content

Commit f41736d

Browse files
committed
feat(server/depfinder): Simplify dependency matching
Remove complex substring matching and recursive JSON search logic from dependency finding. Previously, the depfinder attempted to find variable values within strings using substring checks and recursively parsing potential JSON strings. This was overly complex and prone to errors. This change simplifies the matching to primarily focus on exact matches for primitive types and relies on the AddJsonBytes method for processing structured data like JSON response bodies. Also adds handling for boolean values.
1 parent b36e06e commit f41736d

3 files changed

Lines changed: 30 additions & 141 deletions

File tree

packages/server/pkg/depfinder/depfinder.go

Lines changed: 7 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"fmt"
77
"reflect"
8-
"strings"
98
"the-dev-tools/server/pkg/idwrap"
109
)
1110

@@ -156,34 +155,6 @@ func (d DepFinder) TemplateJSON(jsonBytes []byte) TemplateJSONResult {
156155
return TemplateJSONResult{FindAny: findAny, Couples: couples, NewJson: jsonBytes, Err: err}
157156
}
158157

159-
// findTokenInJSON recursively searches for tokens in JSON structure
160-
func (d DepFinder) findTokenInJSON(value interface{}) (VarCouple, bool) {
161-
switch v := value.(type) {
162-
case map[string]interface{}:
163-
for _, val := range v {
164-
if couple, found := d.findTokenInJSON(val); found {
165-
return couple, true
166-
}
167-
}
168-
case []interface{}:
169-
for _, val := range v {
170-
if couple, found := d.findTokenInJSON(val); found {
171-
return couple, true
172-
}
173-
}
174-
case string:
175-
// Check if this string contains a token
176-
for storedValue, couple := range d.vars {
177-
if storedStr, ok := storedValue.(string); ok {
178-
if strings.Contains(v, storedStr) {
179-
return couple, true
180-
}
181-
}
182-
}
183-
}
184-
return VarCouple{}, false
185-
}
186-
187158
// replace value with path if the value in vars
188159
func (d DepFinder) ReplaceWithPaths(value any) (any, bool, []VarCouple) {
189160
var findAny bool
@@ -213,35 +184,6 @@ func (d DepFinder) ReplaceWithPaths(value any) (any, bool, []VarCouple) {
213184
return fmt.Sprintf("{{ %s }}", couple.Path), true, []VarCouple{couple}
214185
}
215186

216-
// Then try partial match
217-
for storedValue, couple := range d.vars {
218-
storedStr, ok := storedValue.(string)
219-
if !ok {
220-
continue
221-
}
222-
223-
// Special handling for Bearer tokens
224-
if strings.HasPrefix(v, "Bearer ") && strings.Contains(v, storedStr) {
225-
return fmt.Sprintf("Bearer {{ %s }}", couple.Path), true, []VarCouple{couple}
226-
}
227-
228-
// Special handling for query parameters
229-
if strings.Contains(v, "?token=") && strings.Contains(v, storedStr) {
230-
return strings.Replace(v, storedStr, fmt.Sprintf("{{ %s }}", couple.Path), 1), true, []VarCouple{couple}
231-
}
232-
233-
// Try to parse as JSON if it contains a token
234-
if strings.Contains(v, "token") {
235-
var jsonData interface{}
236-
if err := json.Unmarshal([]byte(v), &jsonData); err == nil {
237-
// If it's valid JSON, recursively search for tokens
238-
if couple, found := d.findTokenInJSON(jsonData); found {
239-
// Replace the token in the JSON string
240-
return strings.Replace(v, storedStr, fmt.Sprintf("{{ %s }}", couple.Path), 1), true, []VarCouple{couple}
241-
}
242-
}
243-
}
244-
}
245187
return v, false, nil
246188

247189
case int, int64, float64:
@@ -251,6 +193,13 @@ func (d DepFinder) ReplaceWithPaths(value any) (any, bool, []VarCouple) {
251193
}
252194
return v, false, nil
253195

196+
case bool:
197+
// Handle boolean values
198+
if couple, err := d.FindVar(v); err == nil {
199+
return fmt.Sprintf("{{ %s }}", couple.Path), true, []VarCouple{couple}
200+
}
201+
return v, false, nil
202+
254203
default:
255204
return v, false, nil
256205
}

packages/server/pkg/depfinder/depfinder_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ func TestTemplateJSON(t *testing.T) {
221221
}
222222

223223
if !bytes.Equal(result.NewJson, expectedJSON) {
224-
t.Errorf("Templated JSON doesn't match expected result.\nGot: %v\nExpected: %v", result, expectedJSON)
224+
t.Errorf("Templated JSON doesn't match expected result.\nGot: %s\nExpected: %s", result.NewJson, expectedJSON)
225225
}
226226
}
227227

@@ -237,6 +237,11 @@ func TestTemplateJSONWithSubstringValues(t *testing.T) {
237237
"properties": {
238238
"id": "app-123-production-env"
239239
}
240+
},
241+
"exact": {
242+
"service": "service-name",
243+
"key": "secret-key",
244+
"env": "production"
240245
}
241246
}`)
242247

@@ -279,6 +284,18 @@ func TestTemplateJSONWithSubstringValues(t *testing.T) {
279284
if propertiesMap["id"] != "app-123-production-env" {
280285
t.Errorf("Expected 'id' to remain unchanged, got %v", propertiesMap["id"])
281286
}
287+
288+
// Verify that exact matches were replaced
289+
exactMap := resultMap["exact"].(map[string]any)
290+
if exactMap["service"] != "{{ app.name }}" {
291+
t.Errorf("Expected 'exact.service' to be templated, got %v", exactMap["service"])
292+
}
293+
if exactMap["key"] != "{{ app.credentials.key }}" {
294+
t.Errorf("Expected 'exact.key' to be templated, got %v", exactMap["key"])
295+
}
296+
if exactMap["env"] != "{{ app.environment }}" {
297+
t.Errorf("Expected 'exact.env' to be templated, got %v", exactMap["env"])
298+
}
282299
}
283300

284301
func TestDepFinderPartialTokenAndRecursiveJSON(t *testing.T) {

packages/server/pkg/translate/thar/thar.go

Lines changed: 5 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -372,14 +372,13 @@ func ConvertHARWithDepFinder(har *HAR, collectionID, workspaceID idwrap.IDWrap,
372372
example.BodyType = mitemapiexample.BodyTypeUrlencoded
373373

374374
} else {
375-
376375
bodyBytes := []byte(postData.Text)
377-
378376
if json.Valid(bodyBytes) {
379-
resultDep := (*depFinder).TemplateJSON(bodyBytes)
377+
resultDep := depFinder.TemplateJSON(bodyBytes)
380378
if resultDep.Err != nil {
381379
fmt.Println("Error 4: ", resultDep.Err, postData.Text)
382380
} else {
381+
fmt.Println("find any: ", resultDep.FindAny)
383382
if resultDep.FindAny {
384383
connected = true
385384
for _, couple := range resultDep.Couples {
@@ -410,7 +409,7 @@ func ConvertHARWithDepFinder(har *HAR, collectionID, workspaceID idwrap.IDWrap,
410409
// For non-JSON bodies, try to replace tokens in the string
411410
val := postData.Text
412411
var replaced bool
413-
var jsonObj interface{}
412+
var jsonObj any
414413
if err := json.Unmarshal([]byte(val), &jsonObj); err == nil {
415414
// Recursively process JSON structure
416415
processedObj := processJSONForTokens(jsonObj, *depFinder)
@@ -460,85 +459,9 @@ func ConvertHARWithDepFinder(har *HAR, collectionID, workspaceID idwrap.IDWrap,
460459
path := fmt.Sprintf("%s.%s.%s", requestName, "response", "body")
461460
nodeID := flowNodeID
462461
couple := depfinder.VarCouple{Path: path, NodeID: nodeID}
463-
var bodyObj interface{}
464-
if err := json.Unmarshal(repsonseBodyBytes, &bodyObj); err == nil {
465-
// Process the response body to find IDs and other values
466-
switch v := bodyObj.(type) {
467-
case map[string]interface{}:
468-
// Handle single object response
469-
for k, val := range v {
470-
// Special handling for ID fields
471-
if strings.HasSuffix(strings.ToLower(k), "id") {
472-
if id, ok := val.(float64); ok {
473-
(*depFinder).AddVar(int(id), depfinder.VarCouple{Path: path + "." + k, NodeID: nodeID})
474-
// Create an edge from this node to any node that uses this ID
475-
for _, node := range result.Nodes {
476-
if node.ID != nodeID {
477-
// Check if this node's request body uses the ID
478-
for _, body := range result.RawBodies {
479-
if body.ExampleID == node.ID {
480-
bodyStr := string(body.Data)
481-
if strings.Contains(bodyStr, fmt.Sprintf("%d", int(id))) {
482-
result.Edges = append(result.Edges, edge.Edge{
483-
SourceID: nodeID,
484-
TargetID: node.ID,
485-
})
486-
}
487-
}
488-
}
489-
}
490-
}
491-
}
492-
}
493-
// Handle other string values
494-
if strVal, ok := val.(string); ok {
495-
if _, err := (*depFinder).FindVar(strVal); err == depfinder.ErrNotFound {
496-
(*depFinder).AddVar(strVal, depfinder.VarCouple{Path: path + "." + k, NodeID: nodeID})
497-
}
498-
}
499-
}
500-
case []interface{}:
501-
// Handle array response
502-
for i, item := range v {
503-
if itemMap, ok := item.(map[string]interface{}); ok {
504-
for k, val := range itemMap {
505-
// Special handling for ID fields
506-
if strings.HasSuffix(strings.ToLower(k), "id") {
507-
if id, ok := val.(float64); ok {
508-
(*depFinder).AddVar(int(id), depfinder.VarCouple{Path: fmt.Sprintf("%s[%d].%s", path, i, k), NodeID: nodeID})
509-
// Create an edge from this node to any node that uses this ID
510-
for _, node := range result.Nodes {
511-
if node.ID != nodeID {
512-
// Check if this node's request body uses the ID
513-
for _, body := range result.RawBodies {
514-
if body.ExampleID == node.ID {
515-
bodyStr := string(body.Data)
516-
if strings.Contains(bodyStr, fmt.Sprintf("%d", int(id))) {
517-
result.Edges = append(result.Edges, edge.Edge{
518-
SourceID: nodeID,
519-
TargetID: node.ID,
520-
})
521-
}
522-
}
523-
}
524-
}
525-
}
526-
}
527-
}
528-
// Handle other string values
529-
if strVal, ok := val.(string); ok {
530-
if _, err := (*depFinder).FindVar(strVal); err == depfinder.ErrNotFound {
531-
(*depFinder).AddVar(strVal, depfinder.VarCouple{Path: fmt.Sprintf("%s[%d].%s", path, i, k), NodeID: nodeID})
532-
}
533-
}
534-
}
535-
}
536-
}
537-
}
538-
}
539-
err := (*depFinder).AddJsonBytes(repsonseBodyBytes, couple)
462+
err := depFinder.AddJsonBytes(repsonseBodyBytes, couple)
540463
if err != nil {
541-
fmt.Println("Error 3: ", err, entry.Response.Content.Text)
464+
fmt.Println(err)
542465
}
543466
}
544467
}

0 commit comments

Comments
 (0)