Files

321 lines
16 KiB
Go

package database
import (
"time"
"github.com/uptrace/bun"
)
// Run represents a workflow execution
type Run struct {
bun.BaseModel `bun:"table:runs,alias:r"`
ID string `bun:"id,pk,type:text" json:"id"`
RunID string `bun:"run_id,unique,notnull" json:"run_id"`
WorkflowName string `bun:"workflow_name,notnull" json:"workflow_name"`
WorkflowKind string `bun:"workflow_kind,notnull" json:"workflow_kind"`
Target string `bun:"target,notnull" json:"target"`
Params map[string]interface{} `bun:"params,type:json" json:"params"`
Status string `bun:"status,notnull" json:"status"`
WorkspacePath string `bun:"workspace_path" json:"workspace_path"`
StartedAt *time.Time `bun:"started_at" json:"started_at"`
CompletedAt *time.Time `bun:"completed_at" json:"completed_at"`
ErrorMessage string `bun:"error_message" json:"error_message,omitempty"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
// Scheduling context
ScheduleID string `bun:"schedule_id" json:"schedule_id,omitempty"`
TriggerType string `bun:"trigger_type" json:"trigger_type,omitempty"` // manual, cron, event
TriggerName string `bun:"trigger_name" json:"trigger_name,omitempty"`
// Job grouping - multiple targets from same request share a JobID
JobID string `bun:"job_id" json:"job_id,omitempty"`
// Progress tracking
TotalSteps int `bun:"total_steps" json:"total_steps"`
CompletedSteps int `bun:"completed_steps" json:"completed_steps"`
// Relations
Steps []*StepResult `bun:"rel:has-many,join:id=run_id" json:"steps,omitempty"`
Artifacts []*Artifact `bun:"rel:has-many,join:id=run_id" json:"artifacts,omitempty"`
Events []*EventLog `bun:"rel:has-many,join:run_id=run_id" json:"events,omitempty"`
}
// StepResult represents a step execution result
type StepResult struct {
bun.BaseModel `bun:"table:step_results,alias:sr"`
ID string `bun:"id,pk,type:text" json:"id"`
RunID string `bun:"run_id,notnull,type:text" json:"run_id"`
StepName string `bun:"step_name,notnull" json:"step_name"`
StepType string `bun:"step_type,notnull" json:"step_type"`
Status string `bun:"status,notnull" json:"status"`
Command string `bun:"command" json:"command,omitempty"`
Output string `bun:"output" json:"output,omitempty"`
ErrorMessage string `bun:"error_message" json:"error_message,omitempty"`
Exports map[string]interface{} `bun:"exports,type:json" json:"exports,omitempty"`
DurationMs int64 `bun:"duration_ms" json:"duration_ms"`
LogFile string `bun:"log_file" json:"log_file,omitempty"`
StartedAt *time.Time `bun:"started_at" json:"started_at"`
CompletedAt *time.Time `bun:"completed_at" json:"completed_at"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
// Relations
Run *Run `bun:"rel:belongs-to,join:run_id=id" json:"run,omitempty"`
}
// Artifact content type constants
const (
ContentTypeJSON = "json"
ContentTypeJSONL = "jsonl"
ContentTypeYAML = "yaml"
ContentTypeHTML = "html"
ContentTypeMarkdown = "md"
ContentTypeLog = "log"
ContentTypePDF = "pdf"
ContentTypePNG = "png"
ContentTypeText = "txt"
ContentTypeZip = "zip"
ContentTypeFolder = "folder"
ContentTypeUnknown = "unknown"
)
// Artifact type constants for categorization
const (
ArtifactTypeReport = "report" // Workflow reports from reports: section
ArtifactTypeStateFile = "state_file" // State files like run-state.json
ArtifactTypeOutput = "output" // General output files
ArtifactTypeScreenshot = "screenshot" // Screenshots
)
// Default state file names
var DefaultStateFiles = []struct {
Name string
FileName string
ContentType string
ArtifactType string
Description string
}{
{"state-execution-log", "run-execution.log", ContentTypeLog, ArtifactTypeStateFile, "Execution log file"},
{"state-console-log", "run-console.log", ContentTypeLog, ArtifactTypeStateFile, "Console output capture"},
{"state-completed", "run-completed.json", ContentTypeJSON, ArtifactTypeStateFile, "Completed state marker"},
{"state-file", "run-state.json", ContentTypeJSON, ArtifactTypeStateFile, "Run state tracking file"},
{"state-workflow", "run-workflow.yaml", ContentTypeYAML, ArtifactTypeStateFile, "Workflow definition used for the run"},
}
// Artifact represents an output file from a run
type Artifact struct {
bun.BaseModel `bun:"table:artifacts,alias:a"`
ID string `bun:"id,pk,type:text" json:"id"`
RunID string `bun:"run_id,notnull,type:text" json:"run_id"`
Workspace string `bun:"workspace,notnull" json:"workspace"`
Name string `bun:"name,notnull" json:"name"`
ArtifactPath string `bun:"artifact_path,notnull" json:"artifact_path"`
ArtifactType string `bun:"artifact_type" json:"artifact_type,omitempty"` // report, state_file, output, screenshot
ContentType string `bun:"content_type" json:"content_type,omitempty"` // json, jsonl, yaml, html, md, log, pdf, png, txt, zip, folder, unknown
SizeBytes int64 `bun:"size_bytes" json:"size_bytes"`
LineCount int `bun:"line_count" json:"line_count"`
Description string `bun:"description" json:"description,omitempty"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
// Relations
Run *Run `bun:"rel:belongs-to,join:run_id=id" json:"run,omitempty"`
}
// EventLog represents a system event for auditing and trigger history
type EventLog struct {
bun.BaseModel `bun:"table:event_logs,alias:el"`
ID int64 `bun:"id,pk,autoincrement" json:"id"`
Topic string `bun:"topic,notnull" json:"topic"` // e.g., "webhook.received"
EventID string `bun:"event_id" json:"event_id"` // UUID
Name string `bun:"name" json:"name"` // e.g., "scan.started"
Source string `bun:"source" json:"source"` // e.g., "scheduler", "api"
DataType string `bun:"data_type" json:"data_type"` // e.g., "scan", "asset"
Data string `bun:"data" json:"data"` // JSON payload
// Context
Workspace string `bun:"workspace" json:"workspace,omitempty"`
RunID string `bun:"run_id" json:"run_id,omitempty"`
WorkflowName string `bun:"workflow_name" json:"workflow_name,omitempty"`
// Result
Processed bool `bun:"processed,default:false" json:"processed"`
ProcessedAt *time.Time `bun:"processed_at" json:"processed_at,omitempty"`
Error string `bun:"error" json:"error,omitempty"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
}
// Schedule represents a workflow schedule
type Schedule struct {
bun.BaseModel `bun:"table:schedules,alias:sch"`
ID string `bun:"id,pk,type:text" json:"id"`
Name string `bun:"name,notnull" json:"name"`
WorkflowName string `bun:"workflow_name,notnull" json:"workflow_name"`
WorkflowPath string `bun:"workflow_path,notnull" json:"workflow_path"`
TriggerName string `bun:"trigger_name,notnull" json:"trigger_name"`
TriggerType string `bun:"trigger_type,notnull" json:"trigger_type"`
Schedule string `bun:"schedule" json:"schedule,omitempty"`
EventTopic string `bun:"event_topic" json:"event_topic,omitempty"`
WatchPath string `bun:"watch_path" json:"watch_path,omitempty"`
InputConfig map[string]interface{} `bun:"input_config,type:json" json:"input_config,omitempty"`
IsEnabled bool `bun:"is_enabled,default:true" json:"is_enabled"`
LastRun *time.Time `bun:"last_run" json:"last_run,omitempty"`
NextRun *time.Time `bun:"next_run" json:"next_run,omitempty"`
RunCount int `bun:"run_count,default:0" json:"run_count"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}
// Event topic constants
const (
TopicRunStarted = "run.started"
TopicRunCompleted = "run.completed"
TopicRunFailed = "run.failed"
TopicAssetDiscovered = "asset.discovered"
TopicAssetUpdated = "asset.updated"
TopicWebhookReceived = "webhook.received"
TopicScheduleTriggered = "schedule.triggered"
TopicStepCompleted = "step.completed"
TopicStepFailed = "step.failed"
)
// Asset represents an HTTP endpoint/asset discovered during scanning
type Asset struct {
bun.BaseModel `bun:"table:assets,alias:as"`
ID int64 `bun:"id,pk,autoincrement" json:"id"`
Workspace string `bun:"workspace,notnull" json:"workspace"`
AssetValue string `bun:"asset_value,notnull" json:"asset_value"`
// HTTP data
URL string `bun:"url" json:"url,omitempty"`
Input string `bun:"input" json:"input,omitempty"`
Scheme string `bun:"scheme" json:"scheme,omitempty"`
Method string `bun:"method" json:"method,omitempty"`
Path string `bun:"path" json:"path,omitempty"`
// Response data
StatusCode int `bun:"status_code" json:"status_code,omitempty"`
ContentType string `bun:"content_type" json:"content_type,omitempty"`
ContentLength int64 `bun:"content_length" json:"content_length,omitempty"`
Title string `bun:"title" json:"title,omitempty"`
Words int `bun:"words" json:"words,omitempty"`
Lines int `bun:"lines" json:"lines,omitempty"`
// Network data
HostIP string `bun:"host_ip" json:"host_ip,omitempty"`
DnsRecords []string `bun:"dns_records,type:json" json:"a,omitempty"`
TLS string `bun:"tls" json:"tls,omitempty"`
// Metadata
AssetType string `bun:"asset_type" json:"asset_type,omitempty"`
Technologies []string `bun:"technologies,type:json" json:"tech,omitempty"`
ResponseTime string `bun:"response_time" json:"time,omitempty"`
Labels string `bun:"labels" json:"remarks,omitempty"`
Source string `bun:"source" json:"source,omitempty"` // e.g., "httpx", "nuclei"
RawJsonData string `bun:"raw_json_data" json:"raw_json_data,omitempty"` // Original JSON
RawResponse string `bun:"raw_response" json:"raw_response,omitempty"`
ScreenshotBase64Data string `bun:"screenshot_base64_data" json:"screenshot_base64_data,omitempty"`
// Timestamps
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}
// Workspace represents a scan workspace with aggregated statistics
type Workspace struct {
bun.BaseModel `bun:"table:workspaces,alias:ws"`
ID int64 `bun:"id,pk,autoincrement" json:"id"`
Name string `bun:"name,unique,notnull" json:"name"`
LocalPath string `bun:"local_path" json:"local_path"`
DataSource string `bun:"data_source,default:'local'" json:"data_source"` // local, cloud, imported
// Asset statistics
TotalAssets int `bun:"total_assets,default:0" json:"total_assets"`
TotalSubdomains int `bun:"total_subdomains,default:0" json:"total_subdomains"`
TotalURLs int `bun:"total_urls,default:0" json:"total_urls"`
TotalVulns int `bun:"total_vulns,default:0" json:"total_vulns"`
TotalIPs int `bun:"total_ips,default:0" json:"total_ips"`
TotalLinks int `bun:"total_links,default:0" json:"total_links"`
TotalContent int `bun:"total_content,default:0" json:"total_content"`
TotalArchive int `bun:"total_archive,default:0" json:"total_archive"`
// Vulnerability severity breakdown
VulnCritical int `bun:"vuln_critical,default:0" json:"vuln_critical"`
VulnHigh int `bun:"vuln_high,default:0" json:"vuln_high"`
VulnMedium int `bun:"vuln_medium,default:0" json:"vuln_medium"`
VulnLow int `bun:"vuln_low,default:0" json:"vuln_low"`
VulnPotential int `bun:"vuln_potential,default:0" json:"vuln_potential"`
// Risk and metadata
RiskScore float64 `bun:"risk_score,default:0" json:"risk_score"`
Tags []string `bun:"tags,type:json" json:"tags"`
// Run info
LastRun *time.Time `bun:"last_run" json:"last_run"`
RunWorkflow string `bun:"run_workflow" json:"run_workflow"`
// State file paths
StateExecutionLog string `bun:"state_execution_log" json:"state_execution_log,omitempty"`
StateCompletedFile string `bun:"state_completed_file" json:"state_completed_file,omitempty"`
StateWorkflowFile string `bun:"state_workflow_file" json:"state_workflow_file,omitempty"`
StateWorkflowFolder string `bun:"state_workflow_folder" json:"state_workflow_folder,omitempty"`
// Timestamps
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}
// WorkflowMeta stores workflow metadata in database for faster querying
type WorkflowMeta struct {
bun.BaseModel `bun:"table:workflow_meta,alias:wm"`
ID int64 `bun:"id,pk,autoincrement" json:"id"`
Name string `bun:"name,unique,notnull" json:"name"`
Kind string `bun:"kind,notnull" json:"kind"` // "module" or "flow"
Description string `bun:"description" json:"description"`
FilePath string `bun:"file_path,notnull" json:"file_path"`
Checksum string `bun:"checksum" json:"checksum"` // SHA256 for change detection
Tags []string `bun:"tags,type:json" json:"tags"`
// Metadata
StepCount int `bun:"step_count" json:"step_count"`
ModuleCount int `bun:"module_count" json:"module_count"`
ParamsJSON string `bun:"params_json" json:"params_json"` // Serialized params
// Timestamps
IndexedAt time.Time `bun:"indexed_at,notnull" json:"indexed_at"`
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}
// Vulnerability represents a security vulnerability discovered during scanning
type Vulnerability struct {
bun.BaseModel `bun:"table:vulnerabilities,alias:vl"`
ID int64 `bun:"id,pk,autoincrement" json:"id"`
Workspace string `bun:"workspace,notnull" json:"workspace"`
VulnInfo string `bun:"vuln_info" json:"vuln_info"`
VulnTitle string `bun:"vuln_title" json:"vuln_title"`
VulnDesc string `bun:"vuln_desc" json:"vuln_desc"`
VulnPOC string `bun:"vuln_poc" json:"vuln_poc"`
Severity string `bun:"severity" json:"severity"`
Confidence string `bun:"confidence" json:"confidence"` // Certain, Firm, Tentative, Manual Review Required
AssetType string `bun:"asset_type" json:"asset_type"`
AssetValue string `bun:"asset_value" json:"asset_value"`
Tags []string `bun:"tags,type:json" json:"tags,omitempty"`
DetailHTTPRequest string `bun:"detail_http_request" json:"detail_http_request"`
DetailHTTPResponse string `bun:"detail_http_response" json:"detail_http_response"`
RawVulnJSON string `bun:"raw_vuln_json" json:"raw_vuln_json"`
// Timestamps
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp" json:"created_at"`
UpdatedAt time.Time `bun:"updated_at,notnull,default:current_timestamp" json:"updated_at"`
}