mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-06 15:22:47 +01:00
Release catalyst
This commit is contained in:
182
database/playbookutils.go
Normal file
182
database/playbookutils.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/caql"
|
||||
"github.com/SecurityBrewery/catalyst/dag"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
func playbookGraph(playbook *models.Playbook) (*dag.Graph, error) {
|
||||
d := dag.NewGraph()
|
||||
|
||||
var taskIDs []string
|
||||
for taskID := range playbook.Tasks {
|
||||
taskIDs = append(taskIDs, taskID)
|
||||
}
|
||||
sort.Strings(taskIDs)
|
||||
|
||||
for _, taskID := range taskIDs {
|
||||
if err := d.AddNode(taskID); err != nil {
|
||||
return nil, errors.New("could not add node")
|
||||
}
|
||||
}
|
||||
for _, taskID := range taskIDs {
|
||||
task := playbook.Tasks[taskID]
|
||||
for next := range task.Next {
|
||||
if err := d.AddEdge(taskID, next); err != nil {
|
||||
return nil, errors.New("could not add edge")
|
||||
}
|
||||
}
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
func toTaskResponse(playbook *models.Playbook, taskID string, order int, graph *dag.Graph) (*models.TaskResponse, error) {
|
||||
task, ok := playbook.Tasks[taskID]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("task %s not found", taskID)
|
||||
}
|
||||
|
||||
tr := &models.TaskResponse{
|
||||
Automation: task.Automation,
|
||||
Closed: task.Closed,
|
||||
Created: task.Created,
|
||||
Data: task.Data,
|
||||
Done: task.Done,
|
||||
Join: task.Join,
|
||||
Payload: task.Payload,
|
||||
Name: task.Name,
|
||||
Next: task.Next,
|
||||
Owner: task.Owner,
|
||||
Schema: task.Schema,
|
||||
Type: task.Type,
|
||||
// Active: active,
|
||||
// Order: v.Order,
|
||||
}
|
||||
|
||||
tr.Order = int64(order)
|
||||
|
||||
taskActive, _ := active(playbook, taskID, graph, task)
|
||||
tr.Active = taskActive
|
||||
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
func activePlaybook(playbook *models.Playbook, taskID string) (bool, error) {
|
||||
task, ok := playbook.Tasks[taskID]
|
||||
if !ok {
|
||||
return false, fmt.Errorf("playbook does not contain tasks %s", taskID)
|
||||
}
|
||||
|
||||
d, err := playbookGraph(playbook)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return active(playbook, taskID, d, task)
|
||||
}
|
||||
|
||||
func active(playbook *models.Playbook, taskID string, d *dag.Graph, task *models.Task) (bool, error) {
|
||||
if task.Done {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
parents := d.GetParents(taskID)
|
||||
|
||||
if len(parents) == 0 {
|
||||
return true, nil // valid(&task)
|
||||
}
|
||||
|
||||
if task.Join != nil && *task.Join {
|
||||
for _, parent := range parents {
|
||||
parentTask := playbook.Tasks[parent]
|
||||
if !parentTask.Done {
|
||||
return false, nil
|
||||
}
|
||||
requirement := parentTask.Next[taskID]
|
||||
|
||||
b, err := evalRequirement(requirement, parentTask.Data)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if !b {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
for _, parent := range parents {
|
||||
parentTask := playbook.Tasks[parent]
|
||||
if !parentTask.Done {
|
||||
// return false, nil
|
||||
continue
|
||||
}
|
||||
requirement := parentTask.Next[taskID]
|
||||
|
||||
b, err := evalRequirement(requirement, parentTask.Data)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if b {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func evalRequirement(aql string, data interface{}) (bool, error) {
|
||||
if aql == "" {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
parser := caql.Parser{}
|
||||
tree, err := parser.Parse(aql)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var dataMap map[string]interface{}
|
||||
if data != nil {
|
||||
if dataMapX, ok := data.(map[string]interface{}); ok {
|
||||
dataMap = dataMapX
|
||||
} else {
|
||||
log.Println("wrong data type for task data")
|
||||
}
|
||||
}
|
||||
|
||||
v, err := tree.Eval(dataMap)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if b, ok := v.(bool); ok {
|
||||
return b, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
/*
|
||||
// "github.com/qri-io/jsonschema"
|
||||
func valid(task *models.Task) (bool, error) {
|
||||
schema, err := json.Marshal(task.Schema)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
rs := &jsonschema.Schema{}
|
||||
if err := json.Unmarshal(schema, rs); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
state := rs.Validate(context.Background(), task.Data)
|
||||
return len(*state.Errs) > 0, nil
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user