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) } }