Skip to content

Commit 8becc18

Browse files
committed
make kafka optional
1 parent 411bbaa commit 8becc18

File tree

9 files changed

+120
-96
lines changed

9 files changed

+120
-96
lines changed

README.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ graph TB
143143
```
144144

145145
**SLA Targets:**
146+
146147
| Severity | Standard | Mission-Critical |
147148
|----------|----------|------------------|
148149
| Critical | 15 days | 7 days |
@@ -313,12 +314,12 @@ stateDiagram-v2
313314

314315
## 📈 Performance
315316

316-
| Metric | Target | Actual |
317-
|--------|--------|--------|
318-
| API Response | <3s | <1s (p95) |
319-
| CVE Ingestion | 50K/hour | ✅ |
320-
| Concurrent Users | 100+ | ✅ |
321-
| Database Scale | 1M+ releases | ✅ |
317+
| Metric | Target | Actual |
318+
|------------------|--------------|-----------|
319+
| API Response | <3s | <1s (p95) |
320+
| CVE Ingestion | 50K/hour | ✅ |
321+
| Concurrent Users | 100+ | ✅ |
322+
| Database Scale | 1M+ releases | ✅ |
322323

323324
## 🛠️ Technology Stack
324325

chart/pdvd-backend/values.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ github:
1818

1919
# SMTP Configuration - Leave empty to disable email (invitations will print to console)
2020
smtp:
21-
enabled: false # Set to true to enable email sending
21+
enabled: false # Set to true to enable email sending
2222
host: ""
2323
port: ""
2424
username: ""
2525
password: ""
2626
fromEmail: ""
27-
fromName: ""
27+
fromName: ""

design.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -88,17 +88,17 @@ graph TB
8888

8989
### Technology Stack
9090

91-
| Layer | Technology | Purpose |
92-
|-------|------------|---------|
93-
| **API Framework** | Fiber v2 | High-performance HTTP server |
94-
| **GraphQL** | graphql-go | Query flexibility |
95-
| **Database** | ArangoDB 3.11+ | Graph + document store |
96-
| **Auth** | golang-jwt/jwt | JWT generation/validation |
97-
| **Password** | bcrypt | Password hashing |
98-
| **CVE Data** | OSV.dev API | Vulnerability database |
99-
| **CVSS** | pandatix/go-cvss | Score calculation |
100-
| **Git** | go-git | GitOps integration |
101-
| **Email** | net/smtp | SMTP invitations |
91+
| Layer | Technology | Purpose |
92+
|-------------------|------------------|------------------------------|
93+
| **API Framework** | Fiber v2 | High-performance HTTP server |
94+
| **GraphQL** | graphql-go | Query flexibility |
95+
| **Database** | ArangoDB 3.11+ | Graph + document store |
96+
| **Auth** | golang-jwt/jwt | JWT generation/validation |
97+
| **Password** | bcrypt | Password hashing |
98+
| **CVE Data** | OSV.dev API | Vulnerability database |
99+
| **CVSS** | pandatix/go-cvss | Score calculation |
100+
| **Git** | go-git | GitOps integration |
101+
| **Email** | net/smtp | SMTP invitations |
102102

103103
---
104104

@@ -1489,17 +1489,17 @@ graph TB
14891489
14901490
### Glossary
14911491
1492-
| Term | Definition |
1493-
|------|------------|
1494-
| **PURL** | Package URL - standardized package identifier (pkg:type/namespace/name@version) |
1495-
| **Hub-and-Spoke** | Graph pattern using central hub nodes to reduce edge count |
1496-
| **MTTR** | Mean Time To Remediate - average days from CVE discovery to fix deployment |
1497-
| **SLA** | Service Level Agreement - target remediation time based on severity |
1498-
| **SBOM** | Software Bill of Materials - inventory of software components |
1499-
| **CVE** | Common Vulnerabilities and Exposures - unique vulnerability identifier |
1500-
| **CVSS** | Common Vulnerability Scoring System - severity scoring standard (0-10) |
1501-
| **GitOps** | Infrastructure/config as code with Git as source of truth |
1502-
| **Materialized Edge** | Pre-computed edge stored for performance (e.g., release2cve) |
1492+
| Term | Definition |
1493+
|-----------------------|---------------------------------------------------------------------------------|
1494+
| **PURL** | Package URL - standardized package identifier (pkg:type/namespace/name@version) |
1495+
| **Hub-and-Spoke** | Graph pattern using central hub nodes to reduce edge count |
1496+
| **MTTR** | Mean Time To Remediate - average days from CVE discovery to fix deployment |
1497+
| **SLA** | Service Level Agreement - target remediation time based on severity |
1498+
| **SBOM** | Software Bill of Materials - inventory of software components |
1499+
| **CVE** | Common Vulnerabilities and Exposures - unique vulnerability identifier |
1500+
| **CVSS** | Common Vulnerability Scoring System - severity scoring standard (0-10) |
1501+
| **GitOps** | Infrastructure/config as code with Git as source of truth |
1502+
| **Materialized Edge** | Pre-computed edge stored for performance (e.g., release2cve) |
15031503
15041504
### References
15051505

events/kafka.json

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
"type": "object",
3232
"description": "Reference to the stored SBOM content",
3333
"properties": {
34-
"cid": { "type": "string", "description": "IPFS CID of the SBOM content" },
34+
"cid": {
35+
"type": "string",
36+
"description": "IPFS CID of the SBOM content"
37+
},
3538
"storage_type": { "type": "string", "enum": ["ipfs", "s3"] },
3639
"content_sha": { "type": "string" },
3740
"uploaded_at": { "type": "string", "format": "date-time" }
@@ -43,9 +46,21 @@
4346
"description": "The deployment target (Endpoint) metadata",
4447
"properties": {
4548
"name": { "type": "string" },
46-
"endpoint_type": {
47-
"type": "string",
48-
"enum": ["cluster", "ec2", "lambda", "ecs", "eks", "gke", "aks", "fargate", "edge", "iot", "mission_asset"]
49+
"endpoint_type": {
50+
"type": "string",
51+
"enum": [
52+
"cluster",
53+
"ec2",
54+
"lambda",
55+
"ecs",
56+
"eks",
57+
"gke",
58+
"aks",
59+
"fargate",
60+
"edge",
61+
"iot",
62+
"mission_asset"
63+
]
4964
},
5065
"environment": { "type": "string" },
5166
"is_public": { "type": "boolean", "default": true }
@@ -66,4 +81,4 @@
6681
"sbom_ref",
6782
"endpoint"
6883
]
69-
}
84+
}

hub_and_spoke_guide.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -916,22 +916,22 @@ graph TB
916916

917917
### Query Performance Benchmarks
918918

919-
| Query | Traditional | Hub-and-Spoke | Speedup |
920-
|-------|-------------|---------------|---------|
921-
| CVE → Releases | 30s | 3s | 10x |
922-
| Release → CVEs | 15s | 0.5s | 30x |
923-
| Dashboard MTTR | 60s | 2s | 30x |
924-
| Org-filtered queries | 45s | 1s | 45x |
925-
| Post-deployment detection | 20s | 1s | 20x |
919+
| Query | Traditional | Hub-and-Spoke | Speedup |
920+
|---------------------------|-------------|---------------|---------|
921+
| CVE → Releases | 30s | 3s | 10x |
922+
| Release → CVEs | 15s | 0.5s | 30x |
923+
| Dashboard MTTR | 60s | 2s | 30x |
924+
| Org-filtered queries | 45s | 1s | 45x |
925+
| Post-deployment detection | 20s | 1s | 20x |
926926

927927
### Storage Requirements
928928

929-
| Data | Count | Traditional Size | Hub-and-Spoke Size | Reduction |
930-
|------|-------|------------------|-------------------|-----------|
931-
| **Nodes** | 11,100 | 5 MB | 5 MB | 0% |
932-
| **Edges** | - | 500 MB | 25 MB | 95% |
933-
| **Indexes** | - | 100 MB | 10 MB | 90% |
934-
| **Total** | - | 605 MB | 40 MB | **93.4%** |
929+
| Data | Count | Traditional Size | Hub-and-Spoke Size | Reduction |
930+
|-------------|--------|------------------|--------------------|-----------|
931+
| **Nodes** | 11,100 | 5 MB | 5 MB | 0% |
932+
| **Edges** | - | 500 MB | 25 MB | 95% |
933+
| **Indexes** | - | 100 MB | 10 MB | 90% |
934+
| **Total** | - | 605 MB | 40 MB | **93.4%** |
935935

936936
---
937937

internal/kafka/processor.go

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ import (
1313
"github.com/segmentio/kafka-go"
1414
)
1515

16-
// RunEventProcessor starts the Kafka consumer for release events.
17-
// Kafka messages contain the SBOM CID (and optional metadata)
18-
func RunEventProcessor(ctx context.Context, db database.DBConnection) {
19-
// Parse Kafka brokers from environment variable
16+
// RunEventProcessor attempts to connect to Kafka 3 times.
17+
// If successful, it starts the consumer loop. If not, it returns an error.
18+
func RunEventProcessor(ctx context.Context, db database.DBConnection) error {
2019
brokersEnv := os.Getenv("KAFKA_BROKERS")
2120
var brokers []string
2221
if brokersEnv != "" {
@@ -25,50 +24,58 @@ func RunEventProcessor(ctx context.Context, db database.DBConnection) {
2524
brokers = []string{"localhost:9092"}
2625
}
2726

28-
// Create Kafka reader
27+
topic := "release-events"
28+
var conn *kafka.Conn
29+
var err error
30+
31+
// Retry logic: 3 tries
32+
for i := 1; i <= 3; i++ {
33+
log.Printf("Kafka connection attempt %d/3...", i)
34+
conn, err = kafka.DialContext(ctx, "tcp", brokers[0])
35+
if err == nil {
36+
conn.Close()
37+
break
38+
}
39+
if i < 3 {
40+
time.Sleep(2 * time.Second)
41+
}
42+
}
43+
44+
if err != nil {
45+
return err // Give up after 3 tries
46+
}
47+
48+
// If connection is successful, start the reader
2949
reader := kafka.NewReader(kafka.ReaderConfig{
3050
Brokers: brokers,
3151
GroupID: "pdvd-backend-worker",
32-
Topic: "release-events",
33-
MaxBytes: 10e6, // 10MB per message
52+
Topic: topic,
53+
MaxBytes: 10e6,
3454
})
35-
defer func() {
36-
if err := reader.Close(); err != nil {
37-
log.Printf("Error closing Kafka reader: %v", err)
38-
}
39-
}()
40-
41-
// Initialize ReleaseService
42-
service := &services.ReleaseServiceWrapper{DB: db}
4355

44-
// Initialize SBOM fetcher
45-
fetcher := &services.CIDFetcher{} // implements release.SBOMFetcher
56+
go func() {
57+
defer reader.Close()
58+
service := &services.ReleaseServiceWrapper{DB: db}
59+
fetcher := &services.CIDFetcher{}
4660

47-
log.Println("Kafka Event Processor started. Listening for release events...")
61+
log.Println("Kafka Event Processor started. Listening for release events...")
4862

49-
for {
50-
select {
51-
case <-ctx.Done():
52-
log.Println("Kafka Event Processor shutting down...")
53-
return
54-
default:
55-
// Read message
56-
msg, err := reader.ReadMessage(ctx)
57-
if err != nil {
58-
if ctx.Err() != nil {
59-
return
63+
for {
64+
select {
65+
case <-ctx.Done():
66+
return
67+
default:
68+
msg, err := reader.ReadMessage(ctx)
69+
if err != nil {
70+
if ctx.Err() != nil {
71+
return
72+
}
73+
continue
6074
}
61-
log.Printf("Kafka read error: %v. Retrying in 1s...", err)
62-
time.Sleep(time.Second)
63-
continue
64-
}
65-
66-
// Pass the raw message to the release handler along with fetcher and service
67-
if err := release.HandleReleaseSBOMCreatedWithService(ctx, msg.Value, fetcher, service); err != nil {
68-
log.Printf("Handler error for message key=%s: %v", string(msg.Key), err)
69-
} else {
70-
log.Printf("Successfully processed message key=%s offset=%d", string(msg.Key), msg.Offset)
75+
_ = release.HandleReleaseSBOMCreatedWithService(ctx, msg.Value, fetcher, service)
7176
}
7277
}
73-
}
78+
}()
79+
80+
return nil
7481
}

main.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,19 @@ import (
1313
)
1414

1515
func main() {
16-
// Initialize database connection
1716
db := database.InitializeDatabase()
1817

19-
// Handle graceful shutdown
2018
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
2119
defer cancel()
2220

23-
// Start Kafka processor
24-
go kafka.RunEventProcessor(ctx, db)
21+
// Attempt to start Kafka (Optional)
22+
if err := kafka.RunEventProcessor(ctx, db); err != nil {
23+
log.Printf("Warning: Kafka initialization failed after 3 tries: %v. Starting without Kafka support.", err)
24+
} else {
25+
log.Println("Kafka processor initialized successfully.")
26+
}
2527

26-
// Start Fiber server with API routes
28+
// Start everything else normally
2729
app := api.NewFiberApp(db)
2830
port := os.Getenv("MS_PORT")
2931
if port == "" {
@@ -37,7 +39,6 @@ func main() {
3739
}
3840
}()
3941

40-
// Wait for termination signal
4142
<-ctx.Done()
4243
log.Println("Shutting down pdvd-backend...")
4344
app.Shutdown()

restapi/modules/auth/rbac_fiber_handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ func ApplyRBAC(db database.DBConnection, config *PeriobolosConfig, emailConfig *
311311
if err != nil {
312312
newOrg := &model.Org{
313313
Name: normalizedOrgName, // Store lowercase
314-
DisplayName: displayName, // Store display name
314+
DisplayName: displayName, // Store display name
315315
Description: orgDef.Description,
316316
Metadata: orgDef.Metadata,
317317
CreatedAt: time.Now(),

util/org.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func NormalizeOrgNames(orgs []string) []string {
1414
if orgs == nil {
1515
return []string{}
1616
}
17-
17+
1818
normalized := make([]string, len(orgs))
1919
for i, org := range orgs {
2020
normalized[i] = NormalizeOrgName(org)

0 commit comments

Comments
 (0)