Skip to content

Commit 6aba2fc

Browse files
Shidfar Hodizodaclaude
authored andcommitted
feat: add cross-service protocol linking (Phase 0-2)
- Add internal/linkutil/ package (shared helpers) - Add internal/servicelink/ package with 7 protocol linkers: - GraphQL: SDL/resolver discovery, GRAPHQL_CALLS edges - gRPC: .proto parsing, server/client discovery, GRPC_CALLS edges - Kafka: producer/consumer discovery, KAFKA_CALLS edges - SQS: send/receive discovery, SQS_CALLS edges - SNS: publish/subscribe discovery, SNS_CALLS edges - Pub/Sub: GCP publisher/subscriber, PUBSUB_CALLS edges - HTTP: stub for future httplink migration - Update pipeline: passServiceLinks() replaces passHTTPLinks() - Update Louvain to include all 9 edge types
1 parent c38853f commit 6aba2fc

18 files changed

Lines changed: 7055 additions & 0 deletions

internal/linkutil/config.go

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
package linkutil
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"strings"
7+
8+
"gopkg.in/yaml.v3"
9+
)
10+
11+
// LinkerConfig holds user-overridable service linker settings.
12+
// Loaded from .cgrconfig in the project root.
13+
// This is the unified config for all protocol linkers (HTTP, GraphQL, gRPC, Kafka, SQS, SNS, PubSub).
14+
type LinkerConfig struct {
15+
HTTPLinker HTTPLinkerConfig `yaml:"http_linker"`
16+
GraphQLLinker GraphQLLinkerConfig `yaml:"graphql_linker"`
17+
GRPCLinker GRPCLinkerConfig `yaml:"grpc_linker"`
18+
KafkaLinker KafkaLinkerConfig `yaml:"kafka_linker"`
19+
SQSLinker SQSLinkerConfig `yaml:"sqs_linker"`
20+
SNSLinker SNSLinkerConfig `yaml:"sns_linker"`
21+
PubSubLinker PubSubLinkerConfig `yaml:"pubsub_linker"`
22+
}
23+
24+
// HTTPLinkerConfig holds HTTP linker-specific settings.
25+
type HTTPLinkerConfig struct {
26+
// ExcludePaths are route paths to exclude from HTTP_CALLS matching.
27+
// These are added to (not replacing) the built-in defaultExcludePaths.
28+
ExcludePaths []string `yaml:"exclude_paths"`
29+
30+
// MinConfidence is the minimum confidence score for creating HTTP_CALLS edges.
31+
// Default: 0.25 (includes speculative matches).
32+
MinConfidence *float64 `yaml:"min_confidence"`
33+
34+
// FuzzyMatching enables/disables fuzzy URL matching.
35+
// Default: true.
36+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
37+
}
38+
39+
// KafkaLinkerConfig holds Kafka linker-specific settings.
40+
type KafkaLinkerConfig struct {
41+
// ExcludeTopics are topic names/patterns to exclude from PUBLISHES_TO/SUBSCRIBES_TO matching.
42+
ExcludeTopics []string `yaml:"exclude_topics"`
43+
44+
// MinConfidence is the minimum confidence score for creating Kafka edges.
45+
// Default: 0.25.
46+
MinConfidence *float64 `yaml:"min_confidence"`
47+
48+
// FuzzyMatching enables/disables fuzzy topic matching.
49+
// Default: true.
50+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
51+
}
52+
53+
// SQSLinkerConfig holds SQS linker-specific settings.
54+
type SQSLinkerConfig struct {
55+
// ExcludeQueues are queue names/patterns to exclude from SQS_SENDS_TO/SQS_RECEIVES_FROM matching.
56+
ExcludeQueues []string `yaml:"exclude_queues"`
57+
58+
// MinConfidence is the minimum confidence score for creating SQS edges.
59+
// Default: 0.25.
60+
MinConfidence *float64 `yaml:"min_confidence"`
61+
62+
// FuzzyMatching enables/disables fuzzy queue name matching.
63+
// Default: true.
64+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
65+
}
66+
67+
// SNSLinkerConfig holds SNS linker-specific settings.
68+
type SNSLinkerConfig struct {
69+
// ExcludeTopics are topic ARNs/patterns to exclude from SNS_PUBLISHES_TO/SNS_SUBSCRIBES_TO matching.
70+
ExcludeTopics []string `yaml:"exclude_topics"`
71+
72+
// MinConfidence is the minimum confidence score for creating SNS edges.
73+
// Default: 0.25.
74+
MinConfidence *float64 `yaml:"min_confidence"`
75+
76+
// FuzzyMatching enables/disables fuzzy topic matching.
77+
// Default: true.
78+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
79+
}
80+
81+
// PubSubLinkerConfig holds GCP Pub/Sub linker-specific settings.
82+
type PubSubLinkerConfig struct {
83+
// ExcludeTopics are topic names/patterns to exclude from PUBSUB_CALLS matching.
84+
ExcludeTopics []string `yaml:"exclude_topics"`
85+
86+
// MinConfidence is the minimum confidence score for creating PubSub edges.
87+
// Default: 0.25.
88+
MinConfidence *float64 `yaml:"min_confidence"`
89+
90+
// FuzzyMatching enables/disables fuzzy topic matching.
91+
// Default: true.
92+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
93+
}
94+
95+
// GraphQLLinkerConfig holds GraphQL linker-specific settings.
96+
type GraphQLLinkerConfig struct {
97+
// ExcludeOperations are operation names/patterns to exclude from GRAPHQL_CALLS matching.
98+
ExcludeOperations []string `yaml:"exclude_operations"`
99+
100+
// MinConfidence is the minimum confidence score for creating GraphQL edges.
101+
// Default: 0.25.
102+
MinConfidence *float64 `yaml:"min_confidence"`
103+
104+
// FuzzyMatching enables/disables fuzzy operation matching.
105+
// Default: true.
106+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
107+
}
108+
109+
// GRPCLinkerConfig holds gRPC linker-specific settings.
110+
type GRPCLinkerConfig struct {
111+
// ExcludeServices are service names/patterns to exclude from GRPC_CALLS matching.
112+
ExcludeServices []string `yaml:"exclude_services"`
113+
114+
// MinConfidence is the minimum confidence score for creating gRPC edges.
115+
// Default: 0.25.
116+
MinConfidence *float64 `yaml:"min_confidence"`
117+
118+
// FuzzyMatching enables/disables fuzzy service/method matching.
119+
// Default: true.
120+
FuzzyMatching *bool `yaml:"fuzzy_matching"`
121+
}
122+
123+
// DefaultConfig returns the default linker configuration.
124+
func DefaultConfig() *LinkerConfig {
125+
return &LinkerConfig{}
126+
}
127+
128+
// LoadConfig reads .cgrconfig from the given directory.
129+
// Returns default config if the file doesn't exist.
130+
func LoadConfig(dir string) *LinkerConfig {
131+
cfg := DefaultConfig()
132+
133+
path := filepath.Join(dir, ".cgrconfig")
134+
data, err := os.ReadFile(path)
135+
if err != nil {
136+
return cfg // file not found or unreadable — use defaults
137+
}
138+
139+
if err := yaml.Unmarshal(data, cfg); err != nil {
140+
return DefaultConfig() // invalid YAML — use defaults
141+
}
142+
143+
return cfg
144+
}
145+
146+
// EffectiveMinConfidence returns the configured minimum confidence for HTTP linker,
147+
// or the default (0.25) if not set.
148+
func (c *LinkerConfig) EffectiveMinConfidence() float64 {
149+
if c.HTTPLinker.MinConfidence != nil {
150+
return *c.HTTPLinker.MinConfidence
151+
}
152+
return 0.25
153+
}
154+
155+
// EffectiveFuzzyMatching returns the configured fuzzy matching setting for HTTP linker,
156+
// or the default (true) if not set.
157+
func (c *LinkerConfig) EffectiveFuzzyMatching() bool {
158+
if c.HTTPLinker.FuzzyMatching != nil {
159+
return *c.HTTPLinker.FuzzyMatching
160+
}
161+
return true
162+
}
163+
164+
// AllExcludePaths returns the combined list of default + user-configured exclude paths for HTTP.
165+
func (c *LinkerConfig) AllExcludePaths(defaultPaths []string) []string {
166+
combined := make([]string, 0, len(defaultPaths)+len(c.HTTPLinker.ExcludePaths))
167+
combined = append(combined, defaultPaths...)
168+
combined = append(combined, c.HTTPLinker.ExcludePaths...)
169+
return combined
170+
}
171+
172+
// KafkaEffectiveMinConfidence returns the configured minimum confidence for Kafka linker.
173+
func (c *LinkerConfig) KafkaEffectiveMinConfidence() float64 {
174+
if c.KafkaLinker.MinConfidence != nil {
175+
return *c.KafkaLinker.MinConfidence
176+
}
177+
return 0.25
178+
}
179+
180+
// KafkaEffectiveFuzzyMatching returns the configured fuzzy matching setting for Kafka linker.
181+
func (c *LinkerConfig) KafkaEffectiveFuzzyMatching() bool {
182+
if c.KafkaLinker.FuzzyMatching != nil {
183+
return *c.KafkaLinker.FuzzyMatching
184+
}
185+
return true
186+
}
187+
188+
// SQSEffectiveMinConfidence returns the configured minimum confidence for SQS linker.
189+
func (c *LinkerConfig) SQSEffectiveMinConfidence() float64 {
190+
if c.SQSLinker.MinConfidence != nil {
191+
return *c.SQSLinker.MinConfidence
192+
}
193+
return 0.25
194+
}
195+
196+
// SQSEffectiveFuzzyMatching returns the configured fuzzy matching setting for SQS linker.
197+
func (c *LinkerConfig) SQSEffectiveFuzzyMatching() bool {
198+
if c.SQSLinker.FuzzyMatching != nil {
199+
return *c.SQSLinker.FuzzyMatching
200+
}
201+
return true
202+
}
203+
204+
// SNSEffectiveMinConfidence returns the configured minimum confidence for SNS linker.
205+
func (c *LinkerConfig) SNSEffectiveMinConfidence() float64 {
206+
if c.SNSLinker.MinConfidence != nil {
207+
return *c.SNSLinker.MinConfidence
208+
}
209+
return 0.25
210+
}
211+
212+
// SNSEffectiveFuzzyMatching returns the configured fuzzy matching setting for SNS linker.
213+
func (c *LinkerConfig) SNSEffectiveFuzzyMatching() bool {
214+
if c.SNSLinker.FuzzyMatching != nil {
215+
return *c.SNSLinker.FuzzyMatching
216+
}
217+
return true
218+
}
219+
220+
// PubSubEffectiveMinConfidence returns the configured minimum confidence for PubSub linker.
221+
func (c *LinkerConfig) PubSubEffectiveMinConfidence() float64 {
222+
if c.PubSubLinker.MinConfidence != nil {
223+
return *c.PubSubLinker.MinConfidence
224+
}
225+
return 0.25
226+
}
227+
228+
// PubSubEffectiveFuzzyMatching returns the configured fuzzy matching setting for PubSub linker.
229+
func (c *LinkerConfig) PubSubEffectiveFuzzyMatching() bool {
230+
if c.PubSubLinker.FuzzyMatching != nil {
231+
return *c.PubSubLinker.FuzzyMatching
232+
}
233+
return true
234+
}
235+
236+
// GraphQLEffectiveMinConfidence returns the configured minimum confidence for GraphQL linker.
237+
func (c *LinkerConfig) GraphQLEffectiveMinConfidence() float64 {
238+
if c.GraphQLLinker.MinConfidence != nil {
239+
return *c.GraphQLLinker.MinConfidence
240+
}
241+
return 0.25
242+
}
243+
244+
// GraphQLEffectiveFuzzyMatching returns the configured fuzzy matching setting for GraphQL linker.
245+
func (c *LinkerConfig) GraphQLEffectiveFuzzyMatching() bool {
246+
if c.GraphQLLinker.FuzzyMatching != nil {
247+
return *c.GraphQLLinker.FuzzyMatching
248+
}
249+
return true
250+
}
251+
252+
// GRPCEffectiveMinConfidence returns the configured minimum confidence for gRPC linker.
253+
func (c *LinkerConfig) GRPCEffectiveMinConfidence() float64 {
254+
if c.GRPCLinker.MinConfidence != nil {
255+
return *c.GRPCLinker.MinConfidence
256+
}
257+
return 0.25
258+
}
259+
260+
// GRPCEffectiveFuzzyMatching returns the configured fuzzy matching setting for gRPC linker.
261+
func (c *LinkerConfig) GRPCEffectiveFuzzyMatching() bool {
262+
if c.GRPCLinker.FuzzyMatching != nil {
263+
return *c.GRPCLinker.FuzzyMatching
264+
}
265+
return true
266+
}
267+
268+
// IsPathExcluded checks if a route path matches any of the given exclusion paths.
269+
// This is a generic helper for path/topic/queue exclusion.
270+
func IsPathExcluded(path string, excludePaths []string) bool {
271+
normalized := strings.ToLower(strings.TrimRight(path, "/"))
272+
for _, excluded := range excludePaths {
273+
if strings.EqualFold(normalized, strings.TrimRight(excluded, "/")) {
274+
return true
275+
}
276+
}
277+
return false
278+
}

0 commit comments

Comments
 (0)