mirror of
https://github.com/j3ssie/osmedeus.git
synced 2026-09-06 01:37:46 +02:00
Major features: - Add run registry for tracking active runs with PID management - Add API-based run cancellation with process termination - Add event trigger input vars syntax for multi-variable extraction - Add filter_functions with utility function support in triggers - Add event envelope injection for full event context in workflows - Add write coordinator for batched database operations API improvements: - Add logout endpoint and diffs endpoints for assets/vulnerabilities - Add step-results listing endpoint - Update schedule model with target, workspace, params fields - Change run_id to run_uuid across API responses Performance: - Add compiled JS program caching for 60-80% faster loop conditions - Add parallel shard rendering for 20-40% faster workflow startup - Add memory-mapped I/O for large file line counting - Add efficient output buffer combining in runners - Add mtime-based cache invalidation for workflow loader Other changes: - Rename trigger field from trigger to triggers in workflow YAML - Disable pongo2 HTML autoescape for shell command templates - Update JWT expiration default to 1440 minutes (1 day) - Change CORS default to reflect-origin for credentials support - Add source_type field to events (run, eval, api) - Skip copying core Unix tools to external-binaries
137 lines
4.5 KiB
Go
137 lines
4.5 KiB
Go
package functions
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/dop251/goja"
|
|
"github.com/google/uuid"
|
|
"github.com/j3ssie/osmedeus/v5/internal/notify"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// generateEvent sends a structured event with workspace, topic, source, data_type, and data.
|
|
// It attempts to send to the server first, falls back to database queuing if unavailable,
|
|
// and also sends to configured webhooks.
|
|
// Usage: generate_event(workspace, topic, source, data_type, data)
|
|
// RunID and WorkflowName are automatically populated from the runtime context.
|
|
func (vf *vmFunc) generateEvent(call goja.FunctionCall) goja.Value {
|
|
workspace := call.Argument(0).String()
|
|
topic := call.Argument(1).String()
|
|
source := call.Argument(2).String()
|
|
dataType := call.Argument(3).String()
|
|
|
|
// Validate required fields
|
|
if workspace == "" || topic == "" || source == "" || dataType == "" {
|
|
zap.L().Warn("generateEvent: missing required fields",
|
|
zap.String("workspace", workspace),
|
|
zap.String("topic", topic),
|
|
zap.String("source", source),
|
|
zap.String("data_type", dataType))
|
|
return vf.vm.ToValue(false)
|
|
}
|
|
|
|
// Get data (can be string or object)
|
|
var data interface{}
|
|
if !goja.IsUndefined(call.Argument(4)) && !goja.IsNull(call.Argument(4)) {
|
|
data = call.Argument(4).Export()
|
|
}
|
|
|
|
// Get runtime context for RunID and WorkflowName
|
|
var runID, workflowName string
|
|
sourceType := "eval" // Default to "eval" for events generated via osmedeus eval
|
|
if ctx := vf.getContext(); ctx != nil {
|
|
runID = ctx.scanID
|
|
workflowName = ctx.workflowName
|
|
if runID != "" {
|
|
sourceType = "run" // From workflow execution
|
|
}
|
|
}
|
|
|
|
// Generate UUID if no run context (e.g., from osmedeus eval)
|
|
if runID == "" {
|
|
runID = uuid.New().String()[:8] // Short UUID for eval-generated events
|
|
}
|
|
|
|
// Use SendEventWithFallback to try server first, then queue to DB, and also send to webhooks
|
|
err := notify.SendEventWithFallback(workspace, topic, source, dataType, runID, workflowName, sourceType, data)
|
|
if err != nil {
|
|
zap.L().Debug("generateEvent: server delivery failed (event queued or webhook sent)",
|
|
zap.String("topic", topic),
|
|
zap.Error(err))
|
|
}
|
|
// Return true even if server was unavailable, as event is queued for later processing
|
|
return vf.vm.ToValue(true)
|
|
}
|
|
|
|
// generateEventFromFile reads a file and generates an event for each non-empty line.
|
|
// It attempts to send to the server first, falls back to database queuing if unavailable,
|
|
// and also sends to configured webhooks.
|
|
// Usage: generate_event_from_file(workspace, topic, source, data_type, filePath)
|
|
// RunID and WorkflowName are automatically populated from the runtime context.
|
|
func (vf *vmFunc) generateEventFromFile(call goja.FunctionCall) goja.Value {
|
|
workspace := call.Argument(0).String()
|
|
topic := call.Argument(1).String()
|
|
source := call.Argument(2).String()
|
|
dataType := call.Argument(3).String()
|
|
filePath := call.Argument(4).String()
|
|
|
|
// Validate required fields
|
|
if workspace == "" || filePath == "" || topic == "" || source == "" || dataType == "" {
|
|
zap.L().Warn("generateEventFromFile: missing required fields",
|
|
zap.String("workspace", workspace),
|
|
zap.String("path", filePath),
|
|
zap.String("topic", topic),
|
|
zap.String("source", source),
|
|
zap.String("data_type", dataType))
|
|
return vf.vm.ToValue(0)
|
|
}
|
|
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
zap.L().Warn("generateEventFromFile: failed to open file",
|
|
zap.String("path", filePath),
|
|
zap.Error(err))
|
|
return vf.vm.ToValue(0)
|
|
}
|
|
defer func() { _ = file.Close() }()
|
|
|
|
// Get runtime context for RunID and WorkflowName
|
|
var runID, workflowName string
|
|
sourceType := "eval" // Default to "eval" for events generated via osmedeus eval
|
|
if ctx := vf.getContext(); ctx != nil {
|
|
runID = ctx.scanID
|
|
workflowName = ctx.workflowName
|
|
if runID != "" {
|
|
sourceType = "run" // From workflow execution
|
|
}
|
|
}
|
|
|
|
// Generate UUID if no run context (e.g., from osmedeus eval)
|
|
if runID == "" {
|
|
runID = uuid.New().String()[:8] // Short UUID for eval-generated events
|
|
}
|
|
|
|
count := 0
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
line := strings.TrimSpace(scanner.Text())
|
|
if line == "" {
|
|
continue
|
|
}
|
|
|
|
// Use SendEventWithFallback to try server first, then queue to DB, and also send to webhooks
|
|
_ = notify.SendEventWithFallback(workspace, topic, source, dataType, runID, workflowName, sourceType, line)
|
|
count++ // Count all attempts since events are queued if server unavailable
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
zap.L().Warn("generateEventFromFile: error reading file",
|
|
zap.String("path", filePath),
|
|
zap.Error(err))
|
|
}
|
|
|
|
return vf.vm.ToValue(count)
|
|
}
|