Files

167 lines
6.5 KiB
Go
Raw Permalink Normal View History

2026-04-02 10:57:36 -04:00
package main
import (
"bytes"
"database/sql"
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"time"
"epigas.gitea.cloud/RiskRancher/core/pkg/auth"
"epigas.gitea.cloud/RiskRancher/core/pkg/datastore"
)
func main() {
sizeFlag := flag.String("size", "small", "Choose 'small' (100 tickets) or 'large' (300,000 tickets)")
flag.Parse()
totalTickets := 100
batchSize := 100
if *sizeFlag == "large" {
totalTickets = 300000
batchSize = 10000 // Ingest in chunks of 10k
}
db := datastore.InitDB("./data/RiskRancher.db")
defer db.Close()
log.Printf("🧹 Sweeping the ranch (Deleting old test data)...")
db.Exec("DELETE FROM ticket_assignments")
db.Exec("DELETE FROM tickets")
db.Exec("DELETE FROM sync_logs")
db.Exec("DELETE FROM draft_tickets")
// Reset the auto-increment counters so Ticket IDs reliably start at 1
db.Exec("DELETE FROM sqlite_sequence")
log.Println("⚙️ Seeding global config, adapters, and SLA matrix...")
db.Exec("INSERT OR IGNORE INTO app_config (id, timezone, business_start, business_end, default_extension_days) VALUES (1, 'America/New_York', 9, 17, 30)")
db.Exec("INSERT OR IGNORE INTO domains (name) VALUES ('Vulnerability'), ('Privacy'), ('Compliance'), ('Incident')")
db.Exec("INSERT OR IGNORE INTO departments (name) VALUES ('Security'), ('IT'), ('Privacy'), ('Legal'), ('Compliance')")
slaQuery := `INSERT OR IGNORE INTO sla_policies (domain, severity, days_to_triage, days_to_remediate, max_extensions) VALUES
('Vulnerability', 'Critical', 1, 3, 0), ('Vulnerability', 'High', 3, 14, 1), ('Vulnerability', 'Medium', 5, 30, 2), ('Vulnerability', 'Low', 8, 90, 3), ('Vulnerability', 'Info', 0, 0, 0)`
db.Exec(slaQuery)
adapterQuery := `INSERT OR IGNORE INTO data_adapters (name, source_name, findings_path, mapping_title, mapping_asset, mapping_severity) VALUES
('Trivy Container Security', 'Trivy', '.', 'title', 'asset', 'severity'),
('GitHub Dependabot', 'Dependabot', '.', 'title', 'asset', 'severity'),
('Tenable Nessus', 'Nessus', '.', 'title', 'asset', 'severity'),
('Manual Entry API', 'Manual', '.', 'title', 'asset', 'severity')`
db.Exec(adapterQuery)
validHash, _ := auth.HashPassword("password123")
_, err := db.Exec("INSERT OR REPLACE INTO users (id, email, full_name, password_hash, global_role, is_active) VALUES (999, 'stress@ranch.com', 'Stress Tester', ?, 'Sheriff', 1)", validHash)
if err != nil {
log.Fatalf("🚨 Failed to seed Stress User (Database locked?): %v", err)
}
_, err = db.Exec("INSERT OR REPLACE INTO sessions (session_token, user_id, expires_at) VALUES ('stress_token_123', 999, datetime('now', '+1 hour'))")
if err != nil {
log.Fatalf("🚨 Failed to seed Stress Session: %v", err)
}
log.Println("==========================================================================")
log.Printf("🚀 COMMENCING %d TICKET API LOAD TEST (%s mode)", totalTickets, *sizeFlag)
log.Println("⚠️ CRITICAL: Ensure your RiskRancher server is running in another terminal!")
log.Println("==========================================================================")
time.Sleep(1 * time.Second)
client := &http.Client{Timeout: 5 * time.Minute}
baseURL := "http://localhost:8080"
sessionCookie := &http.Cookie{Name: "session_token", Value: "stress_token_123"}
ticketCounter := 1
log.Printf("📥 PHASE 1: Ingesting via API in batches of %d...", batchSize)
for b := 0; b < totalTickets/batchSize; b++ {
var payload []map[string]string
for i := 0; i < batchSize; i++ {
assetName := fmt.Sprintf("server-prod-%05d", (ticketCounter%50)+1)
sev := "Medium"
if ticketCounter%10 == 0 {
sev = "Critical"
} else if ticketCounter%5 == 0 {
sev = "High"
} else if ticketCounter%2 == 0 {
sev = "Low"
}
source := "Trivy"
if ticketCounter%3 == 0 {
source = "Dependabot"
} else if ticketCounter%7 == 0 {
source = "Nessus"
}
payload = append(payload, map[string]string{
"source": source,
"asset_identifier": assetName,
"title": fmt.Sprintf("Vulnerability-%06d", ticketCounter),
"severity": sev,
"description": fmt.Sprintf("Stress test vulnerability payload #%d", ticketCounter),
})
ticketCounter++
}
body, _ := json.Marshal(payload)
req, _ := http.NewRequest(http.MethodPost, baseURL+"/api/ingest", bytes.NewBuffer(body))
req.AddCookie(sessionCookie)
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatalf("🚨 API Request failed: %v", err)
}
if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
log.Fatalf("🚨 API returned unexpected status: %d", resp.StatusCode)
}
resp.Body.Close()
fmt.Printf("✅ Ingested batch %d/%d (%d tickets)\n", b+1, totalTickets/batchSize, len(payload))
}
log.Println("\n🔀 PHASE 2: Distributing tickets to valid Core workflows...")
unassignedEnd := int(float64(totalTickets) * 0.60) // 60% stay in Holding Pen
assignedEnd := int(float64(totalTickets) * 0.75) // 15% go to Chute
returnedEnd := int(float64(totalTickets) * 0.85) // 10% Returned to Security
falsePosEnd := int(float64(totalTickets) * 0.90) // 5% False Positive
patchedEnd := totalTickets // 10% Patched
log.Printf("⏳ Keeping Tickets 1 - %d in the Holding Pen (Unassigned)...", unassignedEnd)
bulkUpdateDB(db, unassignedEnd+1, assignedEnd, "Assigned Out", "it-network@ranch.com")
bulkUpdateDB(db, assignedEnd+1, returnedEnd, "Returned to Security", "it-endpoint@ranch.com")
bulkUpdateDB(db, returnedEnd+1, falsePosEnd, "False Positive", "security@ranch.com")
bulkUpdateDB(db, falsePosEnd+1, patchedEnd, "Patched", "it-network@ranch.com")
log.Println("\n🎉 STRESS TEST COMPLETE!")
log.Println("==========================================================================")
log.Println("🤠 The ranch is fully loaded with Core data. Go check the Dashboard!")
log.Println("🔑 Login -> Email: stress@ranch.com | Password: password123")
log.Println("==========================================================================")
}
// bulkUpdateDB executes direct SQLite updates
func bulkUpdateDB(db *sql.DB, startID, endID int, status, assignee string) {
if startID > endID {
return
}
fmt.Printf("Moving %d tickets (%d to %d) -> %s...\n", (endID-startID)+1, startID, endID, status)
query := `UPDATE tickets SET status = ?, assignee = ?, latest_comment = 'Stress test auto-distribution', updated_at = CURRENT_TIMESTAMP WHERE id >= ? AND id <= ?`
_, err := db.Exec(query, status, assignee, startID, endID)
if err != nil {
log.Fatalf("🚨 DB update failed: %v", err)
}
}