Files
j3ssie f5840272c5 feat: add run cancellation, event enhancements, and performance optimizations
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
2026-01-24 01:11:33 +08:00

235 lines
5.3 KiB
Go

package lib
import (
"time"
"github.com/j3ssie/osmedeus/v5/internal/core"
)
// RunResult holds the result of a workflow execution
type RunResult struct {
// WorkflowName is the name of the executed workflow
WorkflowName string
// RunUUID is the unique identifier for this execution
RunUUID string
// Target is the scan target
Target string
// Status indicates the final execution status
// Values: "completed", "failed", "cancelled", "skipped"
Status string
// StartTime is when execution started
StartTime time.Time
// EndTime is when execution finished
EndTime time.Time
// Duration is the total execution time
Duration time.Duration
// Steps contains results for each executed step
Steps []*StepResult
// Exports are variables exported by steps during execution
Exports map[string]interface{}
// Artifacts are file paths of generated outputs
Artifacts []string
// Error contains the error if execution failed
Error error
// OutputPath is the workspace directory path
OutputPath string
// Message contains optional status message (e.g., for skipped status)
Message string
}
// IsSuccess returns true if the workflow completed successfully
func (r *RunResult) IsSuccess() bool {
return r.Status == "completed"
}
// IsFailed returns true if the workflow failed
func (r *RunResult) IsFailed() bool {
return r.Status == "failed"
}
// IsCancelled returns true if the workflow was cancelled
func (r *RunResult) IsCancelled() bool {
return r.Status == "cancelled"
}
// IsSkipped returns true if the workflow was skipped
func (r *RunResult) IsSkipped() bool {
return r.Status == "skipped"
}
// GetExport retrieves an exported variable by name
func (r *RunResult) GetExport(name string) (interface{}, bool) {
if r.Exports == nil {
return nil, false
}
v, ok := r.Exports[name]
return v, ok
}
// GetExportString retrieves an exported variable as a string
func (r *RunResult) GetExportString(name string) (string, bool) {
v, ok := r.GetExport(name)
if !ok {
return "", false
}
if s, ok := v.(string); ok {
return s, true
}
return "", false
}
// GetExportBool retrieves an exported variable as a bool
func (r *RunResult) GetExportBool(name string) (bool, bool) {
v, ok := r.GetExport(name)
if !ok {
return false, false
}
if b, ok := v.(bool); ok {
return b, true
}
return false, false
}
// SuccessfulSteps returns the count of successful steps
func (r *RunResult) SuccessfulSteps() int {
count := 0
for _, step := range r.Steps {
if step.Status == "success" {
count++
}
}
return count
}
// FailedSteps returns the count of failed steps
func (r *RunResult) FailedSteps() int {
count := 0
for _, step := range r.Steps {
if step.Status == "failed" {
count++
}
}
return count
}
// SkippedSteps returns the count of skipped steps
func (r *RunResult) SkippedSteps() int {
count := 0
for _, step := range r.Steps {
if step.Status == "skipped" {
count++
}
}
return count
}
// StepResult holds the result of a single step execution
type StepResult struct {
// Name is the step name from the workflow
Name string
// Type is the step type (bash, function, etc.)
Type string
// Status indicates the step execution status
// Values: "success", "failed", "skipped"
Status string
// Output is the captured stdout/stderr from the step
Output string
// Duration is how long the step took to execute
Duration time.Duration
// Error contains the error if the step failed
Error error
// Exports are variables exported by this step
Exports map[string]interface{}
}
// IsSuccess returns true if the step completed successfully
func (s *StepResult) IsSuccess() bool {
return s.Status == "success"
}
// IsFailed returns true if the step failed
func (s *StepResult) IsFailed() bool {
return s.Status == "failed"
}
// IsSkipped returns true if the step was skipped
func (s *StepResult) IsSkipped() bool {
return s.Status == "skipped"
}
// GetExport retrieves an exported variable by name
func (s *StepResult) GetExport(name string) (interface{}, bool) {
if s.Exports == nil {
return nil, false
}
v, ok := s.Exports[name]
return v, ok
}
// fromWorkflowResult converts an internal WorkflowResult to a RunResult
func fromWorkflowResult(result *core.WorkflowResult, outputPath string) *RunResult {
if result == nil {
return nil
}
runResult := &RunResult{
WorkflowName: result.WorkflowName,
RunUUID: result.RunUUID,
Target: result.Target,
Status: string(result.Status),
StartTime: result.StartTime,
EndTime: result.EndTime,
Duration: result.EndTime.Sub(result.StartTime),
Exports: result.Exports,
Artifacts: result.Artifacts,
Error: result.Error,
OutputPath: outputPath,
Message: result.Message,
}
// Convert step results
if len(result.Steps) > 0 {
runResult.Steps = make([]*StepResult, len(result.Steps))
for i, step := range result.Steps {
runResult.Steps[i] = fromStepResult(step)
}
}
return runResult
}
// fromStepResult converts an internal StepResult to a lib StepResult
func fromStepResult(step *core.StepResult) *StepResult {
if step == nil {
return nil
}
return &StepResult{
Name: step.StepName,
Type: "", // Type is not stored in core.StepResult
Status: string(step.Status),
Output: step.Output,
Duration: step.Duration,
Error: step.Error,
Exports: step.Exports,
}
}