Migrate to Go 1.18 (#45)

* Migrate to Go 1.18 and add linters
This commit is contained in:
Jonas Plum
2022-03-20 03:17:18 +01:00
committed by GitHub
parent 03a4806d45
commit 2bad1f5f28
88 changed files with 1430 additions and 868 deletions

View File

@@ -23,7 +23,7 @@ func (db *Database) ArtifactGet(ctx context.Context, id int64, name string) (*mo
FOR a in NOT_NULL(d.artifacts, [])
FILTER a.name == @name
RETURN a`
cursor, _, err := db.Query(ctx, query, mergeMaps(ticketFilterVars, map[string]interface{}{
cursor, _, err := db.Query(ctx, query, mergeMaps(ticketFilterVars, map[string]any{
"@collection": TicketCollectionName,
"ID": fmt.Sprint(id),
"name": name,
@@ -55,7 +55,8 @@ func (db *Database) ArtifactUpdate(ctx context.Context, id int64, name string, a
LET newartifacts = APPEND(REMOVE_VALUE(d.artifacts, a), @artifact)
UPDATE d WITH { "artifacts": newartifacts } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"@collection": TicketCollectionName,
"ID": id,
"name": name,
@@ -69,7 +70,7 @@ func (db *Database) ArtifactUpdate(ctx context.Context, id int64, name string, a
}
func (db *Database) EnrichArtifact(ctx context.Context, id int64, name string, enrichmentForm *model.EnrichmentForm) (*model.TicketWithTickets, error) {
enrichment := model.Enrichment{time.Now().UTC(), enrichmentForm.Data, enrichmentForm.Name}
enrichment := model.Enrichment{Created: time.Now().UTC(), Data: enrichmentForm.Data, Name: enrichmentForm.Name}
ticketFilterQuery, ticketFilterVars, err := db.Hooks.TicketWriteFilter(ctx)
if err != nil {
@@ -85,7 +86,8 @@ func (db *Database) EnrichArtifact(ctx context.Context, id int64, name string, e
LET newartifacts = APPEND(REMOVE_VALUE(d.artifacts, a), MERGE(a, { "enrichments": newenrichments }))
UPDATE d WITH { "artifacts": newartifacts } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"@collection": TicketCollectionName,
"ID": id,
"name": name,

View File

@@ -10,7 +10,7 @@ import (
"github.com/SecurityBrewery/catalyst/generated/model"
)
func toAutomation(doc *model.AutomationForm) interface{} {
func toAutomation(doc *model.AutomationForm) *model.Automation {
return &model.Automation{
Image: doc.Image,
Script: doc.Script,
@@ -72,12 +72,13 @@ func (db *Database) AutomationUpdate(ctx context.Context, id string, automation
func (db *Database) AutomationDelete(ctx context.Context, id string) error {
_, err := db.automationCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) AutomationList(ctx context.Context) ([]*model.AutomationResponse, error) {
query := "FOR d IN @@collection SORT d._key ASC RETURN UNSET(d, 'script')"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": AutomationCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": AutomationCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -40,10 +40,12 @@ type Operation struct {
Ids []driver.DocumentID
}
var CreateOperation = &Operation{Type: bus.DatabaseEntryCreated}
var ReadOperation = &Operation{Type: bus.DatabaseEntryRead}
var (
CreateOperation = &Operation{Type: bus.DatabaseEntryCreated}
ReadOperation = &Operation{Type: bus.DatabaseEntryRead}
)
func (db BusDatabase) Query(ctx context.Context, query string, vars map[string]interface{}, operation *Operation) (cur driver.Cursor, logs *model.LogEntry, err error) {
func (db *BusDatabase) Query(ctx context.Context, query string, vars map[string]any, operation *Operation) (cur driver.Cursor, logs *model.LogEntry, err error) {
defer func() { err = toHTTPErr(err) }()
cur, err = db.internal.Query(ctx, query, vars)
@@ -61,31 +63,31 @@ func (db BusDatabase) Query(ctx context.Context, query string, vars map[string]i
return cur, logs, err
}
func (db BusDatabase) Remove(ctx context.Context) (err error) {
func (db *BusDatabase) Remove(ctx context.Context) (err error) {
defer func() { err = toHTTPErr(err) }()
return db.internal.Remove(ctx)
}
func (db BusDatabase) Collection(ctx context.Context, name string) (col driver.Collection, err error) {
func (db *BusDatabase) Collection(ctx context.Context, name string) (col driver.Collection, err error) {
defer func() { err = toHTTPErr(err) }()
return db.internal.Collection(ctx, name)
}
type Collection struct {
type Collection[T any] struct {
internal driver.Collection
db *BusDatabase
}
func NewCollection(internal driver.Collection, db *BusDatabase) *Collection {
return &Collection{internal: internal, db: db}
func NewCollection[T any](internal driver.Collection, db *BusDatabase) *Collection[T] {
return &Collection[T]{internal: internal, db: db}
}
func (c Collection) CreateDocument(ctx, newctx context.Context, key string, document interface{}) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) CreateDocument(ctx, newctx context.Context, key string, document *T) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
meta, err = c.internal.CreateDocument(newctx, &Keyed{Key: key, Doc: document})
meta, err = c.internal.CreateDocument(newctx, &Keyed[T]{Key: key, Doc: document})
if err != nil {
return meta, err
}
@@ -94,10 +96,11 @@ func (c Collection) CreateDocument(ctx, newctx context.Context, key string, docu
if err != nil {
return meta, err
}
return meta, nil
}
func (c Collection) CreateEdge(ctx, newctx context.Context, edge *driver.EdgeDocument) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) CreateEdge(ctx, newctx context.Context, edge *driver.EdgeDocument) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
meta, err = c.internal.CreateDocument(newctx, edge)
@@ -109,10 +112,11 @@ func (c Collection) CreateEdge(ctx, newctx context.Context, edge *driver.EdgeDoc
if err != nil {
return meta, err
}
return meta, nil
}
func (c Collection) CreateEdges(ctx context.Context, edges []*driver.EdgeDocument) (meta driver.DocumentMetaSlice, err error) {
func (c *Collection[T]) CreateEdges(ctx context.Context, edges []*driver.EdgeDocument) (meta driver.DocumentMetaSlice, err error) {
defer func() { err = toHTTPErr(err) }()
metas, errs, err := c.internal.CreateDocuments(ctx, edges)
@@ -136,13 +140,13 @@ func (c Collection) CreateEdges(ctx context.Context, edges []*driver.EdgeDocumen
return metas, nil
}
func (c Collection) DocumentExists(ctx context.Context, id string) (exists bool, err error) {
func (c *Collection[T]) DocumentExists(ctx context.Context, id string) (exists bool, err error) {
defer func() { err = toHTTPErr(err) }()
return c.internal.DocumentExists(ctx, id)
}
func (c Collection) ReadDocument(ctx context.Context, key string, result interface{}) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) ReadDocument(ctx context.Context, key string, result *T) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
meta, err = c.internal.ReadDocument(ctx, key, result)
@@ -150,7 +154,7 @@ func (c Collection) ReadDocument(ctx context.Context, key string, result interfa
return
}
func (c Collection) UpdateDocument(ctx context.Context, key string, update interface{}) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) UpdateDocument(ctx context.Context, key string, update any) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
meta, err = c.internal.UpdateDocument(ctx, key, update)
@@ -161,7 +165,7 @@ func (c Collection) UpdateDocument(ctx context.Context, key string, update inter
return meta, c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryUpdated)
}
func (c Collection) ReplaceDocument(ctx context.Context, key string, document interface{}) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) ReplaceDocument(ctx context.Context, key string, document *T) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
meta, err = c.internal.ReplaceDocument(ctx, key, document)
@@ -172,13 +176,13 @@ func (c Collection) ReplaceDocument(ctx context.Context, key string, document in
return meta, c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryUpdated)
}
func (c Collection) RemoveDocument(ctx context.Context, formatInt string) (meta driver.DocumentMeta, err error) {
func (c *Collection[T]) RemoveDocument(ctx context.Context, formatInt string) (meta driver.DocumentMeta, err error) {
defer func() { err = toHTTPErr(err) }()
return c.internal.RemoveDocument(ctx, formatInt)
}
func (c Collection) Truncate(ctx context.Context) (err error) {
func (c *Collection[T]) Truncate(ctx context.Context) (err error) {
defer func() { err = toHTTPErr(err) }()
return c.internal.Truncate(ctx)
@@ -190,7 +194,9 @@ func toHTTPErr(err error) error {
if errors.As(err, &ae) {
return &api.HTTPError{Status: ae.Code, Internal: err}
}
return err
}
return nil
}

View File

@@ -8,9 +8,11 @@ import (
"github.com/SecurityBrewery/catalyst/role"
)
type contextKey string
const (
userContextKey = "user"
groupContextKey = "groups"
userContextKey contextKey = "user"
groupContextKey contextKey = "groups"
)
func SetContext(r *http.Request, user *model.UserResponse) *http.Request {
@@ -25,10 +27,12 @@ func SetGroupContext(r *http.Request, groups []string) *http.Request {
func UserContext(ctx context.Context, user *model.UserResponse) context.Context {
user.Roles = role.Strings(role.Explodes(user.Roles))
return context.WithValue(ctx, userContextKey, user)
}
func UserFromContext(ctx context.Context) (*model.UserResponse, bool) {
u, ok := ctx.Value(userContextKey).(*model.UserResponse)
return u, ok
}

View File

@@ -2,18 +2,18 @@ package busdb
import "encoding/json"
type Keyed struct {
type Keyed[T any] struct {
Key string
Doc interface{}
Doc *T
}
func (p Keyed) MarshalJSON() ([]byte, error) {
func (p *Keyed[T]) MarshalJSON() ([]byte, error) {
b, err := json.Marshal(p.Doc)
if err != nil {
panic(err)
}
var m map[string]interface{}
var m map[string]any
err = json.Unmarshal(b, &m)
if err != nil {
panic(err)

View File

@@ -3,6 +3,7 @@ package busdb
import (
"context"
"errors"
"log"
"strings"
"github.com/arangodb/go-driver"
@@ -45,7 +46,12 @@ func (db *BusDatabase) LogBatchCreate(ctx context.Context, logentries []*model.L
}
}
if ids != nil {
go db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryCreated)
go func() {
err := db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryCreated)
if err != nil {
log.Println(err)
}
}()
}
_, errs, err := db.logCollection.CreateDocuments(ctx, logentries)
@@ -62,7 +68,7 @@ func (db *BusDatabase) LogBatchCreate(ctx context.Context, logentries []*model.L
func (db *BusDatabase) LogList(ctx context.Context, reference string) ([]*model.LogEntry, error) {
query := "FOR d IN @@collection FILTER d.reference == @reference SORT d.created DESC RETURN d"
cursor, err := db.internal.Query(ctx, query, map[string]interface{}{
cursor, err := db.internal.Query(ctx, query, map[string]any{
"@collection": LogCollectionName,
"reference": reference,
})

View File

@@ -72,12 +72,13 @@ func (db *Database) DashboardUpdate(ctx context.Context, id string, dashboard *m
func (db *Database) DashboardDelete(ctx context.Context, id string) error {
_, err := db.dashboardCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) DashboardList(ctx context.Context) ([]*model.DashboardResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": DashboardCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": DashboardCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}
@@ -103,15 +104,16 @@ func (db *Database) parseWidgets(dashboard *model.Dashboard) error {
_, err := parser.Parse(widget.Aggregation)
if err != nil {
return fmt.Errorf("invalid aggregation query (%s): syntax error\n", widget.Aggregation)
return fmt.Errorf("invalid aggregation query (%s): syntax error", widget.Aggregation)
}
if widget.Filter != nil {
_, err := parser.Parse(*widget.Filter)
if err != nil {
return fmt.Errorf("invalid filter query (%s): syntax error\n", *widget.Filter)
return fmt.Errorf("invalid filter query (%s): syntax error", *widget.Filter)
}
}
}
return nil
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/SecurityBrewery/catalyst/bus"
"github.com/SecurityBrewery/catalyst/database/busdb"
"github.com/SecurityBrewery/catalyst/database/migrations"
"github.com/SecurityBrewery/catalyst/generated/model"
"github.com/SecurityBrewery/catalyst/hooks"
"github.com/SecurityBrewery/catalyst/index"
)
@@ -38,18 +39,18 @@ type Database struct {
bus *bus.Bus
Hooks *hooks.Hooks
templateCollection *busdb.Collection
ticketCollection *busdb.Collection
playbookCollection *busdb.Collection
automationCollection *busdb.Collection
userdataCollection *busdb.Collection
userCollection *busdb.Collection
tickettypeCollection *busdb.Collection
jobCollection *busdb.Collection
settingsCollection *busdb.Collection
dashboardCollection *busdb.Collection
templateCollection *busdb.Collection[model.TicketTemplate]
ticketCollection *busdb.Collection[model.Ticket]
playbookCollection *busdb.Collection[model.PlaybookTemplate]
automationCollection *busdb.Collection[model.Automation]
userdataCollection *busdb.Collection[model.UserData]
userCollection *busdb.Collection[model.User]
tickettypeCollection *busdb.Collection[model.TicketType]
jobCollection *busdb.Collection[model.Job]
settingsCollection *busdb.Collection[model.Settings]
dashboardCollection *busdb.Collection[model.Dashboard]
relatedCollection *busdb.Collection
relatedCollection *busdb.Collection[driver.EdgeDocument]
// containsCollection *busdb.Collection
}
@@ -145,17 +146,17 @@ func New(ctx context.Context, index *index.Index, bus *bus.Bus, hooks *hooks.Hoo
bus: bus,
Index: index,
Hooks: hooks,
templateCollection: busdb.NewCollection(templateCollection, hookedDB),
ticketCollection: busdb.NewCollection(ticketCollection, hookedDB),
playbookCollection: busdb.NewCollection(playbookCollection, hookedDB),
automationCollection: busdb.NewCollection(automationCollection, hookedDB),
relatedCollection: busdb.NewCollection(relatedCollection, hookedDB),
userdataCollection: busdb.NewCollection(userdataCollection, hookedDB),
userCollection: busdb.NewCollection(userCollection, hookedDB),
tickettypeCollection: busdb.NewCollection(tickettypeCollection, hookedDB),
jobCollection: busdb.NewCollection(jobCollection, hookedDB),
settingsCollection: busdb.NewCollection(settingsCollection, hookedDB),
dashboardCollection: busdb.NewCollection(dashboardCollection, hookedDB),
templateCollection: busdb.NewCollection[model.TicketTemplate](templateCollection, hookedDB),
ticketCollection: busdb.NewCollection[model.Ticket](ticketCollection, hookedDB),
playbookCollection: busdb.NewCollection[model.PlaybookTemplate](playbookCollection, hookedDB),
automationCollection: busdb.NewCollection[model.Automation](automationCollection, hookedDB),
userdataCollection: busdb.NewCollection[model.UserData](userdataCollection, hookedDB),
userCollection: busdb.NewCollection[model.User](userCollection, hookedDB),
tickettypeCollection: busdb.NewCollection[model.TicketType](tickettypeCollection, hookedDB),
jobCollection: busdb.NewCollection[model.Job](jobCollection, hookedDB),
settingsCollection: busdb.NewCollection[model.Settings](settingsCollection, hookedDB),
dashboardCollection: busdb.NewCollection[model.Dashboard](dashboardCollection, hookedDB),
relatedCollection: busdb.NewCollection[driver.EdgeDocument](relatedCollection, hookedDB),
}
return db, nil
@@ -194,16 +195,16 @@ func SetupDB(ctx context.Context, client driver.Client, dbName string) (driver.D
}
func (db *Database) Truncate(ctx context.Context) {
db.templateCollection.Truncate(ctx)
db.ticketCollection.Truncate(ctx)
db.playbookCollection.Truncate(ctx)
db.automationCollection.Truncate(ctx)
db.userdataCollection.Truncate(ctx)
db.userCollection.Truncate(ctx)
db.tickettypeCollection.Truncate(ctx)
db.jobCollection.Truncate(ctx)
db.relatedCollection.Truncate(ctx)
db.settingsCollection.Truncate(ctx)
db.dashboardCollection.Truncate(ctx)
_ = db.templateCollection.Truncate(ctx)
_ = db.ticketCollection.Truncate(ctx)
_ = db.playbookCollection.Truncate(ctx)
_ = db.automationCollection.Truncate(ctx)
_ = db.userdataCollection.Truncate(ctx)
_ = db.userCollection.Truncate(ctx)
_ = db.tickettypeCollection.Truncate(ctx)
_ = db.jobCollection.Truncate(ctx)
_ = db.relatedCollection.Truncate(ctx)
_ = db.settingsCollection.Truncate(ctx)
_ = db.dashboardCollection.Truncate(ctx)
// db.containsCollection.Truncate(ctx)
}

View File

@@ -38,7 +38,7 @@ func (db *Database) toJobResponse(ctx context.Context, key string, doc *model.Jo
inspect, err := cli.ContainerInspect(ctx, key)
if err != nil || inspect.State == nil {
if update {
db.JobUpdate(ctx, key, &model.JobUpdate{
_, _ = db.JobUpdate(ctx, key, &model.JobUpdate{
Status: doc.Status,
Running: false,
})
@@ -46,7 +46,7 @@ func (db *Database) toJobResponse(ctx context.Context, key string, doc *model.Jo
} else if doc.Status != inspect.State.Status {
status = inspect.State.Status
if update {
db.JobUpdate(ctx, key, &model.JobUpdate{
_, _ = db.JobUpdate(ctx, key, &model.JobUpdate{
Status: status,
Running: doc.Running,
})
@@ -107,7 +107,7 @@ func (db *Database) JobUpdate(ctx context.Context, id string, job *model.JobUpda
func (db *Database) JobLogAppend(ctx context.Context, id string, logLine string) error {
query := `LET d = DOCUMENT(@@collection, @ID)
UPDATE d WITH { "log": CONCAT(NOT_NULL(d.log, ""), @logline) } IN @@collection`
cur, _, err := db.Query(ctx, query, map[string]interface{}{
cur, _, err := db.Query(ctx, query, map[string]any{
"@collection": JobCollectionName,
"ID": id,
"logline": logLine,
@@ -125,10 +125,10 @@ func (db *Database) JobLogAppend(ctx context.Context, id string, logLine string)
return nil
}
func (db *Database) JobComplete(ctx context.Context, id string, out interface{}) error {
func (db *Database) JobComplete(ctx context.Context, id string, out any) error {
query := `LET d = DOCUMENT(@@collection, @ID)
UPDATE d WITH { "output": @out, "status": "completed", "running": false } IN @@collection`
cur, _, err := db.Query(ctx, query, map[string]interface{}{
cur, _, err := db.Query(ctx, query, map[string]any{
"@collection": JobCollectionName,
"ID": id,
"out": out,
@@ -148,12 +148,13 @@ func (db *Database) JobComplete(ctx context.Context, id string, out interface{})
func (db *Database) JobDelete(ctx context.Context, id string) error {
_, err := db.jobCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) JobList(ctx context.Context) ([]*model.JobResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": JobCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": JobCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}
@@ -188,24 +189,24 @@ func publishJobMapping(id, automation string, contextStructs *model.Context, ori
return publishJob(id, automation, contextStructs, origin, msg, db)
}
func publishJob(id, automation string, contextStructs *model.Context, origin *model.Origin, payload map[string]interface{}, db *Database) error {
func publishJob(id, automation string, contextStructs *model.Context, origin *model.Origin, payload map[string]any, db *Database) error {
return db.bus.PublishJob(id, automation, payload, contextStructs, origin)
}
func generatePayload(msgMapping map[string]string, contextStructs *model.Context) (map[string]interface{}, error) {
contextJson, err := json.Marshal(contextStructs)
func generatePayload(msgMapping map[string]string, contextStructs *model.Context) (map[string]any, error) {
contextJSON, err := json.Marshal(contextStructs)
if err != nil {
return nil, err
}
automationContext := map[string]interface{}{}
err = json.Unmarshal(contextJson, &automationContext)
automationContext := map[string]any{}
err = json.Unmarshal(contextJSON, &automationContext)
if err != nil {
return nil, err
}
parser := caql.Parser{}
msg := map[string]interface{}{}
msg := map[string]any{}
for arg, expr := range msgMapping {
tree, err := parser.Parse(expr)
if err != nil {
@@ -218,5 +219,6 @@ func generatePayload(msgMapping map[string]string, contextStructs *model.Context
}
msg[arg] = v
}
return msg, nil
}

View File

@@ -32,34 +32,34 @@ func generateMigrations() ([]Migration, error) {
&createGraph{ID: "create-ticket-graph", Name: "Graph", EdgeDefinitions: []driver.EdgeDefinition{{Collection: "related", From: []string{"tickets"}, To: []string{"tickets"}}}},
&createDocument{ID: "create-template-default", Collection: "templates", Document: &busdb.Keyed{Key: "default", Doc: model.TicketTemplate{Schema: DefaultTemplateSchema, Name: "Default"}}},
&createDocument{ID: "create-automation-vt.hash", Collection: "automations", Document: &busdb.Keyed{Key: "vt.hash", Doc: model.Automation{Image: "docker.io/python:3", Script: VTHashAutomation}}},
&createDocument{ID: "create-automation-comment", Collection: "automations", Document: &busdb.Keyed{Key: "comment", Doc: model.Automation{Image: "docker.io/python:3", Script: CommentAutomation}}},
&createDocument{ID: "create-automation-hash.sha1", Collection: "automations", Document: &busdb.Keyed{Key: "hash.sha1", Doc: model.Automation{Image: "docker.io/python:3", Script: SHA1HashAutomation}}},
&createDocument{ID: "create-playbook-malware", Collection: "playbooks", Document: &busdb.Keyed{Key: "malware", Doc: model.PlaybookTemplate{Name: "Malware", Yaml: MalwarePlaybook}}},
&createDocument{ID: "create-playbook-phishing", Collection: "playbooks", Document: &busdb.Keyed{Key: "phishing", Doc: model.PlaybookTemplate{Name: "Phishing", Yaml: PhishingPlaybook}}},
&createDocument{ID: "create-tickettype-alert", Collection: "tickettypes", Document: &busdb.Keyed{Key: "alert", Doc: model.TicketType{Name: "Alerts", Icon: "mdi-alert", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument{ID: "create-tickettype-incident", Collection: "tickettypes", Document: &busdb.Keyed{Key: "incident", Doc: model.TicketType{Name: "Incidents", Icon: "mdi-radioactive", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument{ID: "create-tickettype-investigation", Collection: "tickettypes", Document: &busdb.Keyed{Key: "investigation", Doc: model.TicketType{Name: "Forensic Investigations", Icon: "mdi-fingerprint", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument{ID: "create-tickettype-hunt", Collection: "tickettypes", Document: &busdb.Keyed{Key: "hunt", Doc: model.TicketType{Name: "Threat Hunting", Icon: "mdi-target", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument[busdb.Keyed[model.TicketTemplate]]{ID: "create-template-default", Collection: "templates", Document: &busdb.Keyed[model.TicketTemplate]{Key: "default", Doc: &model.TicketTemplate{Schema: DefaultTemplateSchema, Name: "Default"}}},
&createDocument[busdb.Keyed[model.Automation]]{ID: "create-automation-vt.hash", Collection: "automations", Document: &busdb.Keyed[model.Automation]{Key: "vt.hash", Doc: &model.Automation{Image: "docker.io/python:3", Script: VTHashAutomation}}},
&createDocument[busdb.Keyed[model.Automation]]{ID: "create-automation-comment", Collection: "automations", Document: &busdb.Keyed[model.Automation]{Key: "comment", Doc: &model.Automation{Image: "docker.io/python:3", Script: CommentAutomation}}},
&createDocument[busdb.Keyed[model.Automation]]{ID: "create-automation-hash.sha1", Collection: "automations", Document: &busdb.Keyed[model.Automation]{Key: "hash.sha1", Doc: &model.Automation{Image: "docker.io/python:3", Script: SHA1HashAutomation}}},
&createDocument[busdb.Keyed[model.PlaybookTemplate]]{ID: "create-playbook-malware", Collection: "playbooks", Document: &busdb.Keyed[model.PlaybookTemplate]{Key: "malware", Doc: &model.PlaybookTemplate{Name: "Malware", Yaml: MalwarePlaybook}}},
&createDocument[busdb.Keyed[model.PlaybookTemplate]]{ID: "create-playbook-phishing", Collection: "playbooks", Document: &busdb.Keyed[model.PlaybookTemplate]{Key: "phishing", Doc: &model.PlaybookTemplate{Name: "Phishing", Yaml: PhishingPlaybook}}},
&createDocument[busdb.Keyed[model.TicketType]]{ID: "create-tickettype-alert", Collection: "tickettypes", Document: &busdb.Keyed[model.TicketType]{Key: "alert", Doc: &model.TicketType{Name: "Alerts", Icon: "mdi-alert", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument[busdb.Keyed[model.TicketType]]{ID: "create-tickettype-incident", Collection: "tickettypes", Document: &busdb.Keyed[model.TicketType]{Key: "incident", Doc: &model.TicketType{Name: "Incidents", Icon: "mdi-radioactive", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument[busdb.Keyed[model.TicketType]]{ID: "create-tickettype-investigation", Collection: "tickettypes", Document: &busdb.Keyed[model.TicketType]{Key: "investigation", Doc: &model.TicketType{Name: "Forensic Investigations", Icon: "mdi-fingerprint", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&createDocument[busdb.Keyed[model.TicketType]]{ID: "create-tickettype-hunt", Collection: "tickettypes", Document: &busdb.Keyed[model.TicketType]{Key: "hunt", Doc: &model.TicketType{Name: "Threat Hunting", Icon: "mdi-target", DefaultTemplate: "default", DefaultPlaybooks: []string{}, DefaultGroups: nil}}},
&updateSchema{ID: "update-automation-collection-1", Name: "automations", DataType: "automation", Schema: `{"properties":{"image":{"type":"string"},"script":{"type":"string"}},"required":["image","script"],"type":"object"}`},
&updateDocument{ID: "update-automation-vt.hash-1", Collection: "automations", Key: "vt.hash", Document: model.Automation{Image: "docker.io/python:3", Script: VTHashAutomation, Schema: pointer.String(`{"title":"Input","type":"object","properties":{"default":{"type":"string","title":"Value"}},"required":["default"]}`), Type: []string{"global", "artifact", "playbook"}}},
&updateDocument{ID: "update-automation-comment-1", Collection: "automations", Key: "comment", Document: model.Automation{Image: "docker.io/python:3", Script: CommentAutomation, Type: []string{"playbook"}}},
&updateDocument{ID: "update-automation-hash.sha1-1", Collection: "automations", Key: "hash.sha1", Document: model.Automation{Image: "docker.io/python:3", Script: SHA1HashAutomation, Schema: pointer.String(`{"title":"Input","type":"object","properties":{"default":{"type":"string","title":"Value"}},"required":["default"]}`), Type: []string{"global", "artifact", "playbook"}}},
&updateDocument[model.Automation]{ID: "update-automation-vt.hash-1", Collection: "automations", Key: "vt.hash", Document: &model.Automation{Image: "docker.io/python:3", Script: VTHashAutomation, Schema: pointer.String(`{"title":"Input","type":"object","properties":{"default":{"type":"string","title":"Value"}},"required":["default"]}`), Type: []string{"global", "artifact", "playbook"}}},
&updateDocument[model.Automation]{ID: "update-automation-comment-1", Collection: "automations", Key: "comment", Document: &model.Automation{Image: "docker.io/python:3", Script: CommentAutomation, Type: []string{"playbook"}}},
&updateDocument[model.Automation]{ID: "update-automation-hash.sha1-1", Collection: "automations", Key: "hash.sha1", Document: &model.Automation{Image: "docker.io/python:3", Script: SHA1HashAutomation, Schema: pointer.String(`{"title":"Input","type":"object","properties":{"default":{"type":"string","title":"Value"}},"required":["default"]}`), Type: []string{"global", "artifact", "playbook"}}},
&createCollection{ID: "create-job-collection", Name: "jobs", DataType: "job", Schema: `{"properties":{"automation":{"type":"string"},"log":{"type":"string"},"payload":{},"origin":{"properties":{"artifact_origin":{"properties":{"artifact":{"type":"string"},"ticket_id":{"format":"int64","type":"integer"}},"required":["artifact","ticket_id"],"type":"object"},"task_origin":{"properties":{"playbook_id":{"type":"string"},"task_id":{"type":"string"},"ticket_id":{"format":"int64","type":"integer"}},"required":["playbook_id","task_id","ticket_id"],"type":"object"}},"type":"object"},"output":{"properties":{},"type":"object"},"running":{"type":"boolean"},"status":{"type":"string"}},"required":["automation","running","status"],"type":"object"}`},
&createDocument{ID: "create-playbook-simple", Collection: "playbooks", Document: &busdb.Keyed{Key: "simple", Doc: model.PlaybookTemplate{Name: "Simple", Yaml: SimplePlaybook}}},
&createDocument[busdb.Keyed[model.PlaybookTemplate]]{ID: "create-playbook-simple", Collection: "playbooks", Document: &busdb.Keyed[model.PlaybookTemplate]{Key: "simple", Doc: &model.PlaybookTemplate{Name: "Simple", Yaml: SimplePlaybook}}},
&createCollection{ID: "create-settings-collection", Name: "settings", DataType: "settings", Schema: `{"type":"object","properties":{"artifactStates":{"title":"Artifact States","items":{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"]},"type":"array"},"artifactKinds":{"title":"Artifact Kinds","items":{"type":"object","properties":{"color":{"title":"Color","type":"string","enum":["error","info","success","warning"]},"icon":{"title":"Icon (https://materialdesignicons.com)","type":"string"},"id":{"title":"ID","type":"string"},"name":{"title":"Name","type":"string"}},"required":["id","name","icon"]},"type":"array"},"timeformat":{"title":"Time Format","type":"string"}},"required":["timeformat","artifactKinds","artifactStates"]}`},
&createDocument{ID: "create-settings-global", Collection: "settings", Document: &busdb.Keyed{Key: "global", Doc: model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "YYYY-MM-DDThh:mm:ss"}}},
&createDocument[busdb.Keyed[model.Settings]]{ID: "create-settings-global", Collection: "settings", Document: &busdb.Keyed[model.Settings]{Key: "global", Doc: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "YYYY-MM-DDThh:mm:ss"}}},
&updateSchema{ID: "update-ticket-collection", Name: "tickets", DataType: "ticket", Schema: `{"properties":{"artifacts":{"items":{"properties":{"enrichments":{"additionalProperties":{"properties":{"created":{"format":"date-time","type":"string"},"data":{"example":{"hash":"b7a067a742c20d07a7456646de89bc2d408a1153"},"properties":{},"type":"object"},"name":{"example":"hash.sha1","type":"string"}},"required":["created","data","name"],"type":"object"},"type":"object"},"name":{"example":"2.2.2.2","type":"string"},"status":{"example":"Unknown","type":"string"},"type":{"type":"string"},"kind":{"type":"string"}},"required":["name"],"type":"object"},"type":"array"},"comments":{"items":{"properties":{"created":{"format":"date-time","type":"string"},"creator":{"type":"string"},"message":{"type":"string"}},"required":["created","creator","message"],"type":"object"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"example":{"description":"my little incident"},"properties":{},"type":"object"},"files":{"items":{"properties":{"key":{"example":"myfile","type":"string"},"name":{"example":"notes.docx","type":"string"}},"required":["key","name"],"type":"object"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"example":"WannyCry","type":"string"},"owner":{"example":"bob","type":"string"},"playbooks":{"additionalProperties":{"properties":{"name":{"example":"Phishing","type":"string"},"tasks":{"additionalProperties":{"properties":{"automation":{"type":"string"},"closed":{"format":"date-time","type":"string"},"created":{"format":"date-time","type":"string"},"data":{"properties":{},"type":"object"},"done":{"type":"boolean"},"join":{"example":false,"type":"boolean"},"payload":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"example":"Inform user","type":"string"},"next":{"additionalProperties":{"type":"string"},"type":"object"},"owner":{"type":"string"},"schema":{"properties":{},"type":"object"},"type":{"enum":["task","input","automation"],"example":"task","type":"string"}},"required":["created","done","name","type"],"type":"object"},"type":"object"}},"required":["name","tasks"],"type":"object"},"type":"object"},"read":{"example":["bob"],"items":{"type":"string"},"type":"array"},"references":{"items":{"properties":{"href":{"example":"https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2017-0144","type":"string"},"name":{"example":"CVE-2017-0144","type":"string"}},"required":["href","name"],"type":"object"},"type":"array"},"schema":{"example":"{}","type":"string"},"status":{"example":"open","type":"string"},"type":{"example":"incident","type":"string"},"write":{"example":["alice"],"items":{"type":"string"},"type":"array"}},"required":["created","modified","name","schema","status","type"],"type":"object"}`},
&createCollection{ID: "create-dashboard-collection", Name: "dashboards", DataType: "dashboards", Schema: `{"type":"object","properties":{"name":{"type":"string"},"widgets":{"items":{"type":"object","properties":{"aggregation":{"type":"string"},"filter":{"type":"string"},"name":{"type":"string"},"type":{"enum":[ "bar", "line", "pie" ]},"width": { "type": "integer", "minimum": 1, "maximum": 12 }},"required":["name","aggregation", "type", "width"]},"type":"array"}},"required":["name","widgets"]}`},
&updateDocument{ID: "update-settings-global-1", Collection: "settings", Key: "global", Document: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "yyyy-MM-dd hh:mm:ss"}},
&updateDocument[model.Settings]{ID: "update-settings-global-1", Collection: "settings", Key: "global", Document: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "yyyy-MM-dd hh:mm:ss"}},
}, nil
}
@@ -67,6 +67,7 @@ func loadSchema(dataType, jsonschema string) (*driver.CollectionSchemaOptions, e
ticketCollectionSchema := &driver.CollectionSchemaOptions{Level: driver.CollectionSchemaLevelStrict, Message: fmt.Sprintf("Validation of %s failed", dataType)}
err := ticketCollectionSchema.LoadRule([]byte(jsonschema))
return ticketCollectionSchema, err
}
@@ -101,6 +102,7 @@ func PerformMigrations(ctx context.Context, db driver.Database) error {
}
}
}
return nil
}
@@ -171,41 +173,43 @@ func (m *createGraph) Migrate(ctx context.Context, db driver.Database) error {
_, err := db.CreateGraph(ctx, m.Name, &driver.CreateGraphOptions{
EdgeDefinitions: m.EdgeDefinitions,
})
return err
}
type createDocument struct {
type createDocument[T any] struct {
ID string
Collection string
Document interface{}
Document *T
}
func (m *createDocument) MID() string {
func (m *createDocument[T]) MID() string {
return m.ID
}
func (m *createDocument) Migrate(ctx context.Context, driver driver.Database) error {
func (m *createDocument[T]) Migrate(ctx context.Context, driver driver.Database) error {
collection, err := driver.Collection(ctx, m.Collection)
if err != nil {
return err
}
_, err = collection.CreateDocument(ctx, m.Document)
return err
}
type updateDocument struct {
type updateDocument[T any] struct {
ID string
Collection string
Key string
Document interface{}
Document *T
}
func (m *updateDocument) MID() string {
func (m *updateDocument[T]) MID() string {
return m.ID
}
func (m *updateDocument) Migrate(ctx context.Context, driver driver.Database) error {
func (m *updateDocument[T]) Migrate(ctx context.Context, driver driver.Database) error {
collection, err := driver.Collection(ctx, m.Collection)
if err != nil {
return err
@@ -218,9 +222,11 @@ func (m *updateDocument) Migrate(ctx context.Context, driver driver.Database) er
if !exists {
_, err = collection.CreateDocument(ctx, m.Document)
return err
}
_, err = collection.ReplaceDocument(ctx, m.Key, m.Document)
return err
}

View File

@@ -22,7 +22,7 @@ type PlaybookYAML struct {
type TaskYAML struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Schema interface{} `yaml:"schema"`
Schema any `yaml:"schema"`
Automation string `yaml:"automation"`
Payload map[string]string `yaml:"payload"`
Next map[string]string `yaml:"next"`
@@ -42,6 +42,7 @@ func toPlaybooks(docs []*model.PlaybookTemplateForm) (map[string]*model.Playbook
playbooks[strcase.ToKebab(playbook.Name)] = playbook
}
}
return playbooks, nil
}
@@ -53,11 +54,17 @@ func toPlaybook(doc *model.PlaybookTemplateForm) (*model.Playbook, error) {
}
for idx, task := range ticketPlaybook.Tasks {
if task.Schema != nil {
task.Schema = dyno.ConvertMapI2MapS(task.Schema).(map[string]interface{})
schema, ok := dyno.ConvertMapI2MapS(task.Schema).(map[string]any)
if ok {
task.Schema = schema
} else {
return nil, errors.New("could not convert schema")
}
}
task.Created = time.Now().UTC()
ticketPlaybook.Tasks[idx] = task
}
return ticketPlaybook, nil
}
@@ -84,7 +91,7 @@ func (db *Database) PlaybookCreate(ctx context.Context, playbook *model.Playbook
var doc model.PlaybookTemplate
newctx := driver.WithReturnNew(ctx, &doc)
meta, err := db.playbookCollection.CreateDocument(ctx, newctx, strcase.ToKebab(playbookYAML.Name), p)
meta, err := db.playbookCollection.CreateDocument(ctx, newctx, strcase.ToKebab(playbookYAML.Name), &p)
if err != nil {
return nil, err
}
@@ -104,6 +111,7 @@ func (db *Database) PlaybookGet(ctx context.Context, id string) (*model.Playbook
func (db *Database) PlaybookDelete(ctx context.Context, id string) error {
_, err := db.playbookCollection.RemoveDocument(ctx, id)
return err
}
@@ -121,7 +129,7 @@ func (db *Database) PlaybookUpdate(ctx context.Context, id string, playbook *mod
var doc model.PlaybookTemplate
ctx = driver.WithReturnNew(ctx, &doc)
meta, err := db.playbookCollection.ReplaceDocument(ctx, id, model.PlaybookTemplate{Name: pb.Name, Yaml: playbook.Yaml})
meta, err := db.playbookCollection.ReplaceDocument(ctx, id, &model.PlaybookTemplate{Name: pb.Name, Yaml: playbook.Yaml})
if err != nil {
return nil, err
}
@@ -131,7 +139,7 @@ func (db *Database) PlaybookUpdate(ctx context.Context, id string, playbook *mod
func (db *Database) PlaybookList(ctx context.Context) ([]*model.PlaybookTemplateResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": PlaybookCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": PlaybookCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -33,6 +33,7 @@ func playbookGraph(playbook *model.Playbook) (*dag.Graph, error) {
}
}
}
return d, nil
}
@@ -109,6 +110,7 @@ func active(playbook *model.Playbook, taskID string, d *dag.Graph, task *model.T
return false, nil
}
}
return true, nil
}
@@ -129,10 +131,11 @@ func active(playbook *model.Playbook, taskID string, d *dag.Graph, task *model.T
return true, nil
}
}
return false, nil
}
func evalRequirement(aql string, data interface{}) (bool, error) {
func evalRequirement(aql string, data any) (bool, error) {
if aql == "" {
return true, nil
}
@@ -143,9 +146,9 @@ func evalRequirement(aql string, data interface{}) (bool, error) {
return false, err
}
var dataMap map[string]interface{}
var dataMap map[string]any
if data != nil {
if dataMapX, ok := data.(map[string]interface{}); ok {
if dataMapX, ok := data.(map[string]any); ok {
dataMap = dataMapX
} else {
log.Println("wrong data type for task data")
@@ -160,6 +163,7 @@ func evalRequirement(aql string, data interface{}) (bool, error) {
if b, ok := v.(bool); ok {
return b, nil
}
return false, err
}

View File

@@ -12,11 +12,11 @@ var playbook2 = &model.Playbook{
Name: "Phishing",
Tasks: map[string]*model.Task{
"board": {Next: map[string]string{
"escalate": "boardInvolved == true",
"aquire-mail": "boardInvolved == false",
"escalate": "boardInvolved == true",
"acquire-mail": "boardInvolved == false",
}},
"escalate": {},
"aquire-mail": {Next: map[string]string{
"acquire-mail": {Next: map[string]string{
"extract-iocs": "schemaKey == 'yes'",
"block-sender": "schemaKey == 'yes'",
"search-email-gateway": "schemaKey == 'no'",
@@ -34,11 +34,11 @@ var playbook3 = &model.Playbook{
Name: "Phishing",
Tasks: map[string]*model.Task{
"board": {Next: map[string]string{
"escalate": "boardInvolved == true",
"aquire-mail": "boardInvolved == false",
}, Data: map[string]interface{}{"boardInvolved": true}, Done: true},
"escalate": "boardInvolved == true",
"acquire-mail": "boardInvolved == false",
}, Data: map[string]any{"boardInvolved": true}, Done: true},
"escalate": {},
"aquire-mail": {Next: map[string]string{
"acquire-mail": {Next: map[string]string{
"extract-iocs": "schemaKey == 'yes'",
"block-sender": "schemaKey == 'yes'",
"search-email-gateway": "schemaKey == 'no'",
@@ -71,6 +71,8 @@ var playbook4 = &model.Playbook{
}
func Test_canBeCompleted(t *testing.T) {
t.Parallel()
type args struct {
playbook *model.Playbook
taskID string
@@ -83,18 +85,22 @@ func Test_canBeCompleted(t *testing.T) {
}{
{"playbook2 board", args{playbook: playbook2, taskID: "board"}, true, false},
{"playbook2 escalate", args{playbook: playbook2, taskID: "escalate"}, false, false},
{"playbook2 aquire-mail", args{playbook: playbook2, taskID: "aquire-mail"}, false, false},
{"playbook2 acquire-mail", args{playbook: playbook2, taskID: "acquire-mail"}, false, false},
{"playbook2 block-ioc", args{playbook: playbook2, taskID: "block-ioc"}, false, false},
{"playbook3 board", args{playbook: playbook3, taskID: "board"}, false, false},
{"playbook3 escalate", args{playbook: playbook3, taskID: "escalate"}, true, false},
{"playbook3 aquire-mail", args{playbook: playbook3, taskID: "aquire-mail"}, false, false},
{"playbook3 acquire-mail", args{playbook: playbook3, taskID: "acquire-mail"}, false, false},
{"playbook3 block-ioc", args{playbook: playbook3, taskID: "block-ioc"}, false, false},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := activePlaybook(tt.args.playbook, tt.args.taskID)
if (err != nil) != tt.wantErr {
t.Errorf("activePlaybook() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
@@ -105,6 +111,8 @@ func Test_canBeCompleted(t *testing.T) {
}
func Test_playbookOrder(t *testing.T) {
t.Parallel()
type args struct {
playbook *model.Playbook
}
@@ -117,10 +125,14 @@ func Test_playbookOrder(t *testing.T) {
{"playbook4", args{playbook: playbook4}, []string{"file-or-hash", "enter-hash", "upload", "hash", "virustotal"}, false},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := toPlaybookResponse(tt.args.playbook)
if (err != nil) != tt.wantErr {
t.Errorf("activePlaybook() error = %v, wantErr %v", err, tt.wantErr)
return
}

View File

@@ -20,11 +20,13 @@ func (db *Database) RelatedCreate(ctx context.Context, id, id2 int64) error {
From: driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id))),
To: driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id2))),
})
return err
}
func (db *Database) RelatedBatchCreate(ctx context.Context, edges []*driver.EdgeDocument) error {
_, err := db.relatedCollection.CreateEdges(ctx, edges)
return err
}
@@ -33,7 +35,7 @@ func (db *Database) RelatedRemove(ctx context.Context, id, id2 int64) error {
FOR d in @@collection
FILTER (d._from == @id && d._to == @id2) || (d._to == @id && d._from == @id2)
REMOVE d in @@collection`
_, _, err := db.Query(ctx, q, map[string]interface{}{
_, _, err := db.Query(ctx, q, map[string]any{
"@collection": RelatedTicketsCollectionName,
"id": driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id))),
"id2": driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id2))),
@@ -44,5 +46,6 @@ func (db *Database) RelatedRemove(ctx context.Context, id, id2 int64) error {
driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id2))),
},
})
return err
}

View File

@@ -44,12 +44,12 @@ func (db *Database) Statistics(ctx context.Context) (*model.Statistics, error) {
return &statistics, nil
}
func (db *Database) WidgetData(ctx context.Context, aggregation string, filter *string) (map[string]interface{}, error) {
func (db *Database) WidgetData(ctx context.Context, aggregation string, filter *string) (map[string]any, error) {
parser := &caql.Parser{Searcher: db.Index, Prefix: "d."}
queryTree, err := parser.Parse(aggregation)
if err != nil {
return nil, fmt.Errorf("invalid aggregation query (%s): syntax error\n", aggregation)
return nil, fmt.Errorf("invalid aggregation query (%s): syntax error", aggregation)
}
aggregationString, err := queryTree.String()
if err != nil {
@@ -61,7 +61,7 @@ func (db *Database) WidgetData(ctx context.Context, aggregation string, filter *
if filter != nil && *filter != "" {
queryTree, err := parser.Parse(*filter)
if err != nil {
return nil, fmt.Errorf("invalid filter query (%s): syntax error\n", *filter)
return nil, fmt.Errorf("invalid filter query (%s): syntax error", *filter)
}
filterString, err := queryTree.String()
if err != nil {
@@ -82,7 +82,7 @@ func (db *Database) WidgetData(ctx context.Context, aggregation string, filter *
}
defer cur.Close()
statistics := map[string]interface{}{}
statistics := map[string]any{}
if _, err := cur.ReadDocument(ctx, &statistics); err != nil {
return nil, err
}

View File

@@ -10,10 +10,10 @@ import (
)
type playbookResponse struct {
PlaybookId string `json:"playbook_id"`
PlaybookID string `json:"playbook_id"`
PlaybookName string `json:"playbook_name"`
Playbook model.Playbook `json:"playbook"`
TicketId int64 `json:"ticket_id"`
TicketID int64 `json:"ticket_id"`
TicketName string `json:"ticket_name"`
}
@@ -28,7 +28,7 @@ func (db *Database) TaskList(ctx context.Context) ([]*model.TaskWithContext, err
FILTER d.status == 'open'
FOR playbook IN NOT_NULL(VALUES(d.playbooks), [])
RETURN { ticket_id: TO_NUMBER(d._key), ticket_name: d.name, playbook_id: POSITION(d.playbooks, playbook, true), playbook_name: playbook.name, playbook: playbook }`
cursor, _, err := db.Query(ctx, query, mergeMaps(ticketFilterVars, map[string]interface{}{
cursor, _, err := db.Query(ctx, query, mergeMaps(ticketFilterVars, map[string]any{
"@collection": TicketCollectionName,
}), busdb.ReadOperation)
if err != nil {
@@ -53,10 +53,10 @@ func (db *Database) TaskList(ctx context.Context) ([]*model.TaskWithContext, err
for _, task := range playbook.Tasks {
if task.Active {
docs = append(docs, &model.TaskWithContext{
PlaybookId: doc.PlaybookId,
PlaybookId: doc.PlaybookID,
PlaybookName: doc.PlaybookName,
Task: task,
TicketId: doc.TicketId,
TicketId: doc.TicketID,
TicketName: doc.TicketName,
})
}

View File

@@ -62,12 +62,13 @@ func (db *Database) TemplateUpdate(ctx context.Context, id string, template *mod
func (db *Database) TemplateDelete(ctx context.Context, id string) error {
_, err := db.templateCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) TemplateList(ctx context.Context) ([]*model.TicketTemplateResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": TemplateCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": TemplateCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -10,16 +10,20 @@ import (
"github.com/SecurityBrewery/catalyst/test"
)
var template1 = &model.TicketTemplateForm{
Schema: migrations.DefaultTemplateSchema,
Name: "Template 1",
}
var default1 = &model.TicketTemplateForm{
Schema: migrations.DefaultTemplateSchema,
Name: "Default",
}
var (
template1 = &model.TicketTemplateForm{
Schema: migrations.DefaultTemplateSchema,
Name: "Template 1",
}
default1 = &model.TicketTemplateForm{
Schema: migrations.DefaultTemplateSchema,
Name: "Default",
}
)
func TestDatabase_TemplateCreate(t *testing.T) {
t.Parallel()
type args struct {
template *model.TicketTemplateForm
}
@@ -35,7 +39,10 @@ func TestDatabase_TemplateCreate(t *testing.T) {
{name: "Only name", args: args{template: &model.TicketTemplateForm{Name: "name"}}, wantErr: false},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -50,6 +57,8 @@ func TestDatabase_TemplateCreate(t *testing.T) {
}
func TestDatabase_TemplateDelete(t *testing.T) {
t.Parallel()
type args struct {
id string
}
@@ -62,7 +71,10 @@ func TestDatabase_TemplateDelete(t *testing.T) {
{name: "Not existing", args: args{"foobar"}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -81,6 +93,8 @@ func TestDatabase_TemplateDelete(t *testing.T) {
}
func TestDatabase_TemplateGet(t *testing.T) {
t.Parallel()
type args struct {
id string
}
@@ -94,7 +108,10 @@ func TestDatabase_TemplateGet(t *testing.T) {
{name: "Not existing", args: args{id: "foobar"}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -108,6 +125,7 @@ func TestDatabase_TemplateGet(t *testing.T) {
got, err := db.TemplateGet(test.Context(), tt.args.id)
if (err != nil) != tt.wantErr {
t.Errorf("TemplateGet() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
@@ -120,6 +138,8 @@ func TestDatabase_TemplateGet(t *testing.T) {
}
func TestDatabase_TemplateList(t *testing.T) {
t.Parallel()
tests := []struct {
name string
want []*model.TicketTemplateResponse
@@ -128,7 +148,10 @@ func TestDatabase_TemplateList(t *testing.T) {
{name: "Normal", want: []*model.TicketTemplateResponse{{ID: "default", Name: "Default", Schema: migrations.DefaultTemplateSchema}, {ID: "template-1", Name: template1.Name, Schema: template1.Schema}}},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -142,6 +165,7 @@ func TestDatabase_TemplateList(t *testing.T) {
got, err := db.TemplateList(test.Context())
if (err != nil) != tt.wantErr {
t.Errorf("TemplateList() error = %v, wantErr %v", err, tt.wantErr)
return
}
assert.Equal(t, got, tt.want)
@@ -150,6 +174,8 @@ func TestDatabase_TemplateList(t *testing.T) {
}
func TestDatabase_TemplateUpdate(t *testing.T) {
t.Parallel()
type args struct {
id string
template *model.TicketTemplateForm
@@ -163,7 +189,10 @@ func TestDatabase_TemplateUpdate(t *testing.T) {
{name: "Not existing", args: args{"foobar", template1}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"errors"
"fmt"
"log"
"sort"
"strconv"
"strings"
@@ -21,7 +22,7 @@ import (
"github.com/SecurityBrewery/catalyst/index"
)
func toTicket(ticketForm *model.TicketForm) (interface{}, error) {
func toTicket(ticketForm *model.TicketForm) (any, error) {
playbooks, err := toPlaybooks(ticketForm.Playbooks)
if err != nil {
return nil, err
@@ -65,8 +66,9 @@ func toTicket(ticketForm *model.TicketForm) (interface{}, error) {
ticket.Status = "open"
}
if ticketForm.ID != nil {
return &busdb.Keyed{Key: strconv.FormatInt(*ticketForm.ID, 10), Doc: ticket}, nil
return &busdb.Keyed[model.Ticket]{Key: strconv.FormatInt(*ticketForm.ID, 10), Doc: ticket}, nil
}
return ticket, nil
}
@@ -79,6 +81,7 @@ func toTicketResponses(tickets []*model.TicketSimpleResponse) ([]*model.TicketRe
}
extendedTickets = append(extendedTickets, tr)
}
return extendedTickets, nil
}
@@ -167,6 +170,7 @@ func toPlaybookResponses(playbooks map[string]*model.Playbook) (map[string]*mode
return nil, err
}
}
return pr, nil
}
@@ -195,6 +199,7 @@ func toPlaybookResponse(playbook *model.Playbook) (*model.PlaybookResponse, erro
re.Tasks[taskID] = rootTask
i++
}
return re, nil
}
@@ -204,7 +209,7 @@ func (db *Database) TicketBatchCreate(ctx context.Context, ticketForms []*model.
return nil, err
}
var dbTickets []interface{}
var dbTickets []any
for _, ticketForm := range ticketForms {
ticket, err := toTicket(ticketForm)
if err != nil {
@@ -231,7 +236,7 @@ func (db *Database) TicketBatchCreate(ctx context.Context, ticketForms []*model.
LET noiddoc = UNSET(keyeddoc, "id")
INSERT noiddoc INTO @@collection
RETURN NEW`
apiTickets, _, err := db.ticketListQuery(ctx, query, mergeMaps(map[string]interface{}{
apiTickets, _, err := db.ticketListQuery(ctx, query, mergeMaps(map[string]any{
"tickets": dbTickets,
}, ticketFilterVars), busdb.CreateOperation)
if err != nil {
@@ -247,7 +252,11 @@ func (db *Database) TicketBatchCreate(ctx context.Context, ticketForms []*model.
ids = append(ids, driver.NewDocumentID(TicketCollectionName, fmt.Sprint(apiTicket.ID)))
}
go db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryUpdated)
go func() {
if err := db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryUpdated); err != nil {
log.Println(err)
}
}()
ticketResponses, err := toTicketResponses(apiTickets)
if err != nil {
@@ -294,6 +303,7 @@ func batchIndex(index *index.Index, tickets []*model.TicketSimpleResponse) error
}
}
wg.Wait()
return nil
}
@@ -306,9 +316,9 @@ func (db *Database) TicketGet(ctx context.Context, ticketID int64) (*model.Ticke
return db.ticketGetQuery(ctx, ticketID, `LET d = DOCUMENT(@@collection, @ID) `+ticketFilterQuery+` RETURN d`, ticketFilterVars, busdb.ReadOperation)
}
func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query string, bindVars map[string]interface{}, operation *busdb.Operation) (*model.TicketWithTickets, error) {
func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query string, bindVars map[string]any, operation *busdb.Operation) (*model.TicketWithTickets, error) {
if bindVars == nil {
bindVars = map[string]interface{}{}
bindVars = map[string]any{}
}
bindVars["@collection"] = TicketCollectionName
if ticketID != 0 {
@@ -350,7 +360,7 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
` + ticketFilterQuery + `
RETURN d`
outTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]interface{}{
outTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]any{
"ID": fmt.Sprint(ticketID),
"graph": TicketArtifactsGraphName,
"@tickets": TicketCollectionName,
@@ -368,7 +378,7 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
` + ticketFilterQuery + `
RETURN d`
inTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]interface{}{
inTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]any{
"ID": fmt.Sprint(ticketID),
"graph": TicketArtifactsGraphName,
"@tickets": TicketCollectionName,
@@ -387,7 +397,7 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
FOR a IN NOT_NULL(d.artifacts, [])
FILTER POSITION(@artifacts, a.name)
RETURN d`
sameArtifactTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]interface{}{
sameArtifactTickets, _, err := db.ticketListQuery(ctx, ticketsQuery, mergeMaps(map[string]any{
"ID": fmt.Sprint(ticketID),
"artifacts": artifactNames,
}, ticketFilterVars), busdb.ReadOperation)
@@ -395,7 +405,8 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
return nil, err
}
tickets := append(outTickets, inTickets...)
tickets := outTickets
tickets = append(tickets, inTickets...)
tickets = append(tickets, sameArtifactTickets...)
sort.Slice(tickets, func(i, j int) bool {
return tickets[i].ID < tickets[j].ID
@@ -425,7 +436,8 @@ func (db *Database) TicketUpdate(ctx context.Context, ticketID int64, ticket *mo
REPLACE d WITH @ticket IN @@collection
RETURN NEW`
ticket.Modified = time.Now().UTC() // TODO make setable?
return db.ticketGetQuery(ctx, ticketID, query, mergeMaps(map[string]interface{}{"ticket": ticket}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, ticketID, query, mergeMaps(map[string]any{"ticket": ticket}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated, Ids: []driver.DocumentID{
driver.NewDocumentID(TicketCollectionName, strconv.FormatInt(ticketID, 10)),
},
@@ -447,15 +459,15 @@ func (db *Database) TicketDelete(ctx context.Context, ticketID int64) error {
}
func (db *Database) TicketList(ctx context.Context, ticketType string, query string, sorts []string, desc []bool, offset, count int64) (*model.TicketList, error) {
binVars := map[string]interface{}{}
binVars := map[string]any{}
var typeString = ""
typeString := ""
if ticketType != "" {
typeString = "FILTER d.type == @type "
binVars["type"] = ticketType
}
var filterString = ""
filterString := ""
if query != "" {
parser := &caql.Parser{Searcher: db.Index, Prefix: "d."}
queryTree, err := parser.Parse(query)
@@ -493,6 +505,7 @@ func (db *Database) TicketList(ctx context.Context, ticketType string, query str
RETURN d`
// RETURN KEEP(d, "_key", "id", "name", "type", "created")`
ticketList, _, err := db.ticketListQuery(ctx, q, mergeMaps(binVars, ticketFilterVars), busdb.ReadOperation)
return &model.TicketList{
Count: documentCount,
Tickets: ticketList,
@@ -500,9 +513,9 @@ func (db *Database) TicketList(ctx context.Context, ticketType string, query str
// return map[string]interface{}{"tickets": ticketList, "count": documentCount}, err
}
func (db *Database) ticketListQuery(ctx context.Context, query string, bindVars map[string]interface{}, operation *busdb.Operation) ([]*model.TicketSimpleResponse, *model.LogEntry, error) {
func (db *Database) ticketListQuery(ctx context.Context, query string, bindVars map[string]any, operation *busdb.Operation) ([]*model.TicketSimpleResponse, *model.LogEntry, error) {
if bindVars == nil {
bindVars = map[string]interface{}{}
bindVars = map[string]any{}
}
bindVars["@collection"] = TicketCollectionName
@@ -533,9 +546,9 @@ func (db *Database) ticketListQuery(ctx context.Context, query string, bindVars
return docs, logEntry, nil
}
func (db *Database) TicketCount(ctx context.Context, typequery, filterquery string, bindVars map[string]interface{}) (int, error) {
func (db *Database) TicketCount(ctx context.Context, typequery, filterquery string, bindVars map[string]any) (int, error) {
if bindVars == nil {
bindVars = map[string]interface{}{}
bindVars = map[string]any{}
}
bindVars["@collection"] = TicketCollectionName
@@ -555,10 +568,11 @@ func (db *Database) TicketCount(ctx context.Context, typequery, filterquery stri
return 0, err
}
cursor.Close()
return documentCount, nil
}
func sortQuery(paramsSort []string, paramsDesc []bool, bindVars map[string]interface{}) string {
func sortQuery(paramsSort []string, paramsDesc []bool, bindVars map[string]any) string {
sort := ""
if len(paramsSort) > 0 {
var sorts []string
@@ -572,21 +586,23 @@ func sortQuery(paramsSort []string, paramsDesc []bool, bindVars map[string]inter
}
sort = "SORT " + strings.Join(sorts, ", ")
}
return sort
}
func mergeMaps(a map[string]interface{}, b map[string]interface{}) map[string]interface{} {
merged := map[string]interface{}{}
func mergeMaps(a map[string]any, b map[string]any) map[string]any {
merged := map[string]any{}
for k, v := range a {
merged[k] = v
}
for k, v := range b {
merged[k] = v
}
return merged
}
func validate(e interface{}, schema *gojsonschema.Schema) error {
func validate(e any, schema *gojsonschema.Schema) error {
b, err := json.Marshal(e)
if err != nil {
return err
@@ -602,7 +618,9 @@ func validate(e interface{}, schema *gojsonschema.Schema) error {
for _, e := range res.Errors() {
l = append(l, e.String())
}
return fmt.Errorf("validation failed: %v", strings.Join(l, ", "))
}
return nil
}

View File

@@ -34,7 +34,8 @@ func (db *Database) AddArtifact(ctx context.Context, id int64, artifact *model.A
` + ticketFilterQuery + `
UPDATE d WITH { "modified": @now, "artifacts": PUSH(NOT_NULL(d.artifacts, []), @artifact) } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"artifact": artifact, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"artifact": artifact, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -57,6 +58,7 @@ func inferType(name string) string {
case commonregex.SHA256HexRegex.MatchString(name):
return "sha256"
}
return "unknown"
}
@@ -73,7 +75,8 @@ func (db *Database) RemoveArtifact(ctx context.Context, id int64, name string) (
LET newartifacts = REMOVE_VALUE(d.artifacts, a)
UPDATE d WITH { "modified": @now, "artifacts": newartifacts } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"name": name, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"name": name, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -91,7 +94,8 @@ func (db *Database) SetTemplate(ctx context.Context, id int64, schema string) (*
` + ticketFilterQuery + `
UPDATE d WITH { "schema": @schema } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"schema": schema}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"schema": schema}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -122,7 +126,8 @@ func (db *Database) AddComment(ctx context.Context, id int64, comment *model.Com
` + ticketFilterQuery + `
UPDATE d WITH { "modified": @now, "comments": PUSH(NOT_NULL(d.comments, []), @comment) } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"comment": comment, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"comment": comment, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -140,7 +145,8 @@ func (db *Database) RemoveComment(ctx context.Context, id int64, commentID int64
` + ticketFilterQuery + `
UPDATE d WITH { "modified": @now, "comments": REMOVE_NTH(d.comments, @commentID) } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"commentID": commentID, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"commentID": commentID, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -158,7 +164,8 @@ func (db *Database) SetReferences(ctx context.Context, id int64, references []*m
` + ticketFilterQuery + `
UPDATE d WITH { "modified": @now, "references": @references } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"references": references, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"references": references, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -176,7 +183,8 @@ func (db *Database) AddFile(ctx context.Context, id int64, file *model.File) (*m
` + ticketFilterQuery + `
UPDATE d WITH { "modified": @now, "files": APPEND(NOT_NULL(d.files, []), [@file]) } IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"file": file, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{"file": file, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
Type: bus.DatabaseEntryUpdated,
Ids: []driver.DocumentID{
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
@@ -213,7 +221,7 @@ func (db *Database) AddTicketPlaybook(ctx context.Context, id int64, playbookTem
LET newticket = MERGE(d, { "modified": @now, "playbooks": newplaybooks })
REPLACE d WITH newticket IN @@collection
RETURN NEW`
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"playbook": pb,
"playbookID": findName(parentTicket.Playbooks, playbookID),
"now": time.Now().UTC(),
@@ -258,6 +266,7 @@ func runRootTask(ticket *model.TicketResponse, playbookID string, db *Database)
}
runNextTasks(ticket.ID, playbookID, root.Next, root.Data, ticket, db)
return nil
}
@@ -273,7 +282,8 @@ func (db *Database) RemoveTicketPlaybook(ctx context.Context, id int64, playbook
LET newplaybooks = UNSET(d.playbooks, @playbookID)
REPLACE d WITH MERGE(d, { "modified": @now, "playbooks": newplaybooks }) IN @@collection
RETURN NEW`
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"playbookID": playbookID,
"now": time.Now().UTC(),
}, ticketFilterVars), &busdb.Operation{

View File

@@ -41,7 +41,7 @@ func (db *Database) TaskGet(ctx context.Context, id int64, playbookID string, ta
}, nil
}
func (db *Database) TaskComplete(ctx context.Context, id int64, playbookID string, taskID string, data interface{}) (*model.TicketWithTickets, error) {
func (db *Database) TaskComplete(ctx context.Context, id int64, playbookID string, taskID string, data any) (*model.TicketWithTickets, error) {
inc, err := db.TicketGet(ctx, id)
if err != nil {
return nil, err
@@ -68,7 +68,7 @@ func (db *Database) TaskComplete(ctx context.Context, id int64, playbookID strin
UPDATE d WITH { "modified": @now, "playbooks": newplaybooks } IN @@collection
RETURN NEW`
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"playbookID": playbookID,
"taskID": taskID,
"data": data,
@@ -130,7 +130,7 @@ func (db *Database) TaskUpdateOwner(ctx context.Context, id int64, playbookID st
UPDATE d WITH { "modified": @now, "playbooks": newplaybooks } IN @@collection
RETURN NEW`
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"playbookID": playbookID,
"taskID": taskID,
"owner": owner,
@@ -148,7 +148,7 @@ func (db *Database) TaskUpdateOwner(ctx context.Context, id int64, playbookID st
return ticket, nil
}
func (db *Database) TaskUpdateData(ctx context.Context, id int64, playbookID string, taskID string, data map[string]interface{}) (*model.TicketWithTickets, error) {
func (db *Database) TaskUpdateData(ctx context.Context, id int64, playbookID string, taskID string, data map[string]any) (*model.TicketWithTickets, error) {
ticketFilterQuery, ticketFilterVars, err := db.Hooks.TicketWriteFilter(ctx)
if err != nil {
return nil, err
@@ -165,7 +165,7 @@ func (db *Database) TaskUpdateData(ctx context.Context, id int64, playbookID str
UPDATE d WITH { "modified": @now, "playbooks": newplaybooks } IN @@collection
RETURN NEW`
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{
ticket, err := db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]any{
"playbookID": playbookID,
"taskID": taskID,
"data": data,
@@ -198,7 +198,7 @@ func (db *Database) TaskRun(ctx context.Context, id int64, playbookID string, ta
return nil
}
func runNextTasks(id int64, playbookID string, next map[string]string, data interface{}, ticket *model.TicketResponse, db *Database) {
func runNextTasks(id int64, playbookID string, next map[string]string, data any, ticket *model.TicketResponse, db *Database) {
for nextTaskID, requirement := range next {
nextTask := ticket.Playbooks[playbookID].Tasks[nextTaskID]
if nextTask.Type == model.TaskTypeAutomation {
@@ -220,5 +220,6 @@ func runTask(ticketID int64, playbookID string, taskID string, task *model.TaskR
msgContext := &model.Context{Playbook: playbook, Task: task, Ticket: ticket}
origin := &model.Origin{TaskOrigin: &model.TaskOrigin{TaskId: taskID, PlaybookId: playbookID, TicketId: ticketID}}
jobID := uuid.NewString()
return publishJobMapping(jobID, *task.Automation, msgContext, origin, task.Payload, db)
}

View File

@@ -75,12 +75,13 @@ func (db *Database) TicketTypeUpdate(ctx context.Context, id string, tickettype
func (db *Database) TicketTypeDelete(ctx context.Context, id string) error {
_, err := db.tickettypeCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) TicketTypeList(ctx context.Context) ([]*model.TicketTypeResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": TicketTypeCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": TicketTypeCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -28,6 +28,7 @@ func generateKey() string {
for i := range b {
b[i] = letters[rand.Intn(len(letters))]
}
return string(b)
}
@@ -78,8 +79,10 @@ func (db *Database) UserGetOrCreate(ctx context.Context, newUser *model.UserForm
if err != nil {
return nil, err
}
return &model.UserResponse{ID: newUser.ID, Roles: newUser.Roles, Blocked: newUser.Blocked}, nil
}
return user, nil
}
@@ -132,12 +135,13 @@ func (db *Database) UserGet(ctx context.Context, id string) (*model.UserResponse
func (db *Database) UserDelete(ctx context.Context, id string) error {
_, err := db.userCollection.RemoveDocument(ctx, id)
return err
}
func (db *Database) UserList(ctx context.Context) ([]*model.UserResponse, error) {
query := "FOR d IN @@collection RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": UserCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": UserCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}
@@ -163,7 +167,7 @@ func (db *Database) UserByHash(ctx context.Context, sha256 string) (*model.UserR
FILTER d.sha256 == @sha256
RETURN d`
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": UserCollectionName, "sha256": sha256}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": UserCollectionName, "sha256": sha256}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -29,6 +29,7 @@ func (db *Database) UserDataCreate(ctx context.Context, id string, userdata *mod
}
_, err := db.userdataCollection.CreateDocument(ctx, ctx, id, userdata)
return err
}
@@ -37,6 +38,7 @@ func (db *Database) UserDataGetOrCreate(ctx context.Context, id string, newUserD
if err != nil {
return toUserDataResponse(id, newUserData), db.UserDataCreate(ctx, id, newUserData)
}
return setting, nil
}
@@ -52,7 +54,7 @@ func (db *Database) UserDataGet(ctx context.Context, id string) (*model.UserData
func (db *Database) UserDataList(ctx context.Context) ([]*model.UserDataResponse, error) {
query := "FOR d IN @@collection SORT d.username ASC RETURN d"
cursor, _, err := db.Query(ctx, query, map[string]interface{}{"@collection": UserDataCollectionName}, busdb.ReadOperation)
cursor, _, err := db.Query(ctx, query, map[string]any{"@collection": UserDataCollectionName}, busdb.ReadOperation)
if err != nil {
return nil, err
}

View File

@@ -22,6 +22,8 @@ var bobResponse = &model.UserDataResponse{
}
func TestDatabase_UserDataCreate(t *testing.T) {
t.Parallel()
type args struct {
id string
setting *model.UserData
@@ -37,7 +39,10 @@ func TestDatabase_UserDataCreate(t *testing.T) {
{name: "Only settingname", args: args{id: "bob"}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -52,6 +57,8 @@ func TestDatabase_UserDataCreate(t *testing.T) {
}
func TestDatabase_UserDataGet(t *testing.T) {
t.Parallel()
type args struct {
id string
}
@@ -65,7 +72,10 @@ func TestDatabase_UserDataGet(t *testing.T) {
{name: "Not existing", args: args{id: "foo"}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -79,6 +89,7 @@ func TestDatabase_UserDataGet(t *testing.T) {
got, err := db.UserDataGet(test.Context(), tt.args.id)
if (err != nil) != tt.wantErr {
t.Errorf("UserDataGet() error = %v, wantErr %v", err, tt.wantErr)
return
}
if err != nil {
@@ -91,6 +102,8 @@ func TestDatabase_UserDataGet(t *testing.T) {
}
func TestDatabase_UserDataList(t *testing.T) {
t.Parallel()
tests := []struct {
name string
want []*model.UserDataResponse
@@ -99,7 +112,10 @@ func TestDatabase_UserDataList(t *testing.T) {
{name: "Normal list", want: []*model.UserDataResponse{bobResponse}},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)
@@ -113,6 +129,7 @@ func TestDatabase_UserDataList(t *testing.T) {
got, err := db.UserDataList(test.Context())
if (err != nil) != tt.wantErr {
t.Errorf("UserDataList() error = %v, wantErr %v", err, tt.wantErr)
return
}
@@ -122,6 +139,8 @@ func TestDatabase_UserDataList(t *testing.T) {
}
func TestDatabase_UserDataUpdate(t *testing.T) {
t.Parallel()
type args struct {
id string
setting *model.UserData
@@ -135,7 +154,10 @@ func TestDatabase_UserDataUpdate(t *testing.T) {
{name: "Not existing", args: args{id: "foo"}, wantErr: true},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
_, _, _, _, _, db, cleanup, err := test.DB(t)
if err != nil {
t.Fatal(err)