mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2026-01-23 06:31:47 +01:00
@@ -1,26 +0,0 @@
|
||||
package automation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
func New(apiurl, apikey string, bus *bus.Bus, db *database.Database) error {
|
||||
if err := jobAutomation(jobContext(), apiurl, apikey, bus, db); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return resultAutomation(bus, db)
|
||||
}
|
||||
|
||||
func jobContext() context.Context {
|
||||
// TODO: change roles?
|
||||
bot := &models.UserResponse{ID: "bot", Roles: []string{role.Admin}}
|
||||
return busdb.UserContext(context.Background(), bot)
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package automation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
func jobAutomation(ctx context.Context, apiurl, apikey string, catalystBus *bus.Bus, db *database.Database) error {
|
||||
return catalystBus.SubscribeJob(func(automationMsg *bus.JobMsg) {
|
||||
job, err := db.JobCreate(ctx, automationMsg.ID, &models.JobForm{
|
||||
Automation: automationMsg.Automation,
|
||||
Payload: automationMsg.Message.Payload,
|
||||
Origin: automationMsg.Origin,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
automation, err := db.AutomationGet(ctx, automationMsg.Automation)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if automation.Script == "" {
|
||||
log.Println("automation is empty")
|
||||
return
|
||||
}
|
||||
|
||||
if automationMsg.Message.Secrets == nil {
|
||||
automationMsg.Message.Secrets = map[string]string{}
|
||||
}
|
||||
automationMsg.Message.Secrets["catalyst_apikey"] = apikey
|
||||
automationMsg.Message.Secrets["catalyst_apiurl"] = apiurl
|
||||
|
||||
scriptMessage, _ := json.Marshal(automationMsg.Message)
|
||||
|
||||
containerID, logs, err := createContainer(ctx, automation.Image, automation.Script, string(scriptMessage))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := db.JobUpdate(ctx, automationMsg.ID, &models.Job{
|
||||
Automation: job.Automation,
|
||||
Container: &containerID,
|
||||
Origin: job.Origin,
|
||||
Output: job.Output,
|
||||
Log: &logs,
|
||||
Payload: job.Payload,
|
||||
Status: job.Status,
|
||||
}); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
|
||||
stdout, _, err := runDocker(ctx, automationMsg.ID, containerID, db)
|
||||
if err != nil {
|
||||
result = map[string]interface{}{"error": fmt.Sprintf("error running script %s %s", err, string(stdout))}
|
||||
} else {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(stdout, &data); err != nil {
|
||||
result = map[string]interface{}{"error": string(stdout)}
|
||||
} else {
|
||||
result = data
|
||||
}
|
||||
}
|
||||
|
||||
if err := catalystBus.PublishResult(automationMsg.Automation, result, automationMsg.Origin); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
if err := db.JobComplete(ctx, automationMsg.ID, result); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func getAutomation(automationID string, config *Config) (*models.AutomationResponse, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, config.CatalystAPIUrl+"/automations/"+automationID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("PRIVATE-TOKEN", config.CatalystAPIKey)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var automation models.AutomationResponse
|
||||
if err := json.Unmarshal(b, &automation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &automation, nil
|
||||
}
|
||||
*/
|
||||
@@ -1,38 +0,0 @@
|
||||
package automation
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
func resultAutomation(catalystBus *bus.Bus, db *database.Database) error {
|
||||
return catalystBus.SubscribeResult(func(resultMsg *bus.ResultMsg) {
|
||||
if resultMsg.Target != nil {
|
||||
ctx := jobContext()
|
||||
switch {
|
||||
case resultMsg.Target.TaskOrigin != nil:
|
||||
if _, err := db.TaskComplete(
|
||||
ctx,
|
||||
resultMsg.Target.TaskOrigin.TicketId,
|
||||
resultMsg.Target.TaskOrigin.PlaybookId,
|
||||
resultMsg.Target.TaskOrigin.TaskId,
|
||||
resultMsg.Data,
|
||||
); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
case resultMsg.Target.ArtifactOrigin != nil:
|
||||
enrichment := &models.EnrichmentForm{
|
||||
Data: resultMsg.Data,
|
||||
Name: resultMsg.Automation,
|
||||
}
|
||||
_, err := db.EnrichArtifact(ctx, resultMsg.Target.ArtifactOrigin.TicketId, resultMsg.Target.ArtifactOrigin.Artifact, enrichment)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
94
bus/bus.go
94
bus/bus.go
@@ -4,16 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
emitter "github.com/emitter-io/go/v2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
const (
|
||||
channelUpdate = "data"
|
||||
channelJob = "job"
|
||||
channelResult = "result"
|
||||
)
|
||||
|
||||
type Bus struct {
|
||||
@@ -22,25 +13,13 @@ type Bus struct {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Host string
|
||||
Key string
|
||||
resultBusKey string
|
||||
jobBusKey string
|
||||
dataBusKey string
|
||||
APIUrl string
|
||||
}
|
||||
|
||||
type JobMsg struct {
|
||||
ID string `json:"id"`
|
||||
Automation string `json:"automation"`
|
||||
Origin *models.Origin `json:"origin"`
|
||||
Message *models.Message `json:"message"`
|
||||
}
|
||||
|
||||
type ResultMsg struct {
|
||||
Automation string `json:"automation"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Target *models.Origin `json:"target"`
|
||||
Host string
|
||||
Key string
|
||||
databaseUpdateBusKey string
|
||||
jobBusKey string
|
||||
resultBusKey string
|
||||
requestKey string
|
||||
APIUrl string
|
||||
}
|
||||
|
||||
func New(c *Config) (*Bus, error) {
|
||||
@@ -51,7 +30,7 @@ func New(c *Config) (*Bus, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c.dataBusKey, err = client.GenerateKey(c.Key, channelUpdate+"/", "rwls", 0)
|
||||
c.databaseUpdateBusKey, err = client.GenerateKey(c.Key, channelDatabaseUpdate+"/", "rwls", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -63,30 +42,14 @@ func New(c *Config) (*Bus, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.requestKey, err = client.GenerateKey(c.Key, ChannelRequest+"/", "rwls", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Bus{config: c, client: client}, err
|
||||
}
|
||||
|
||||
func (b *Bus) PublishUpdate(ids []driver.DocumentID) error {
|
||||
return b.jsonPublish(ids, channelUpdate, b.config.dataBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) PublishJob(id, automation string, payload interface{}, context *models.Context, origin *models.Origin) error {
|
||||
return b.jsonPublish(&JobMsg{
|
||||
ID: id,
|
||||
Automation: automation,
|
||||
Origin: origin,
|
||||
Message: &models.Message{
|
||||
Context: context,
|
||||
Payload: payload,
|
||||
},
|
||||
}, channelJob, b.config.jobBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) PublishResult(automation string, data map[string]interface{}, target *models.Origin) error {
|
||||
return b.jsonPublish(&ResultMsg{Automation: automation, Data: data, Target: target}, channelResult, b.config.resultBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) jsonPublish(msg interface{}, channel, key string) error {
|
||||
payload, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
@@ -96,39 +59,6 @@ func (b *Bus) jsonPublish(msg interface{}, channel, key string) error {
|
||||
return b.client.Publish(key, channel, payload)
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeUpdate(f func(ids []driver.DocumentID)) error {
|
||||
return b.safeSubscribe(b.config.dataBusKey, channelUpdate, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg []driver.DocumentID
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(msg)
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeJob(f func(msg *JobMsg)) error {
|
||||
return b.safeSubscribe(b.config.jobBusKey, channelJob, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg JobMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeResult(f func(msg *ResultMsg)) error {
|
||||
return b.safeSubscribe(b.config.resultBusKey, channelResult, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg ResultMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
|
||||
func (b *Bus) safeSubscribe(key, channel string, handler func(c *emitter.Client, m emitter.Message)) error {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
||||
42
bus/databaseupdate.go
Normal file
42
bus/databaseupdate.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package bus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
emitter "github.com/emitter-io/go/v2"
|
||||
)
|
||||
|
||||
const channelDatabaseUpdate = "databaseupdate"
|
||||
|
||||
type DatabaseUpdateType string
|
||||
|
||||
const (
|
||||
DatabaseEntryRead DatabaseUpdateType = "read"
|
||||
DatabaseEntryCreated DatabaseUpdateType = "created"
|
||||
DatabaseEntryUpdated DatabaseUpdateType = "updated"
|
||||
)
|
||||
|
||||
type DatabaseUpdateMsg struct {
|
||||
IDs []driver.DocumentID `json:"ids"`
|
||||
Type DatabaseUpdateType `json:"type"`
|
||||
}
|
||||
|
||||
func (b *Bus) PublishDatabaseUpdate(ids []driver.DocumentID, databaseUpdateType DatabaseUpdateType) error {
|
||||
return b.jsonPublish(&DatabaseUpdateMsg{
|
||||
IDs: ids,
|
||||
Type: databaseUpdateType,
|
||||
}, channelDatabaseUpdate, b.config.databaseUpdateBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeDatabaseUpdate(f func(msg *DatabaseUpdateMsg)) error {
|
||||
return b.safeSubscribe(b.config.databaseUpdateBusKey, channelDatabaseUpdate, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg DatabaseUpdateMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
42
bus/job.go
Normal file
42
bus/job.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package bus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
emitter "github.com/emitter-io/go/v2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
const channelJob = "job"
|
||||
|
||||
type JobMsg struct {
|
||||
ID string `json:"id"`
|
||||
Automation string `json:"automation"`
|
||||
Origin *models.Origin `json:"origin"`
|
||||
Message *models.Message `json:"message"`
|
||||
}
|
||||
|
||||
func (b *Bus) PublishJob(id, automation string, payload interface{}, context *models.Context, origin *models.Origin) error {
|
||||
return b.jsonPublish(&JobMsg{
|
||||
ID: id,
|
||||
Automation: automation,
|
||||
Origin: origin,
|
||||
Message: &models.Message{
|
||||
Context: context,
|
||||
Payload: payload,
|
||||
},
|
||||
}, channelJob, b.config.jobBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeJob(f func(msg *JobMsg)) error {
|
||||
return b.safeSubscribe(b.config.jobBusKey, channelJob, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg JobMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
36
bus/request.go
Normal file
36
bus/request.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package bus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
emitter "github.com/emitter-io/go/v2"
|
||||
)
|
||||
|
||||
const ChannelRequest = "request"
|
||||
|
||||
type RequestMsg struct {
|
||||
IDs []driver.DocumentID `json:"ids"`
|
||||
Function string `json:"function"`
|
||||
User string `json:"user"`
|
||||
}
|
||||
|
||||
func (b *Bus) PublishRequest(user, f string, ids []driver.DocumentID) error {
|
||||
return b.jsonPublish(&RequestMsg{
|
||||
User: user,
|
||||
Function: f,
|
||||
IDs: ids,
|
||||
}, ChannelRequest, b.config.requestKey)
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeRequest(f func(msg *RequestMsg)) error {
|
||||
return b.safeSubscribe(b.config.requestKey, ChannelRequest, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg RequestMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
33
bus/result.go
Normal file
33
bus/result.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package bus
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
emitter "github.com/emitter-io/go/v2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
const channelResult = "result"
|
||||
|
||||
type ResultMsg struct {
|
||||
Automation string `json:"automation"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Target *models.Origin `json:"target"`
|
||||
}
|
||||
|
||||
func (b *Bus) PublishResult(automation string, data map[string]interface{}, target *models.Origin) error {
|
||||
return b.jsonPublish(&ResultMsg{Automation: automation, Data: data, Target: target}, channelResult, b.config.resultBusKey)
|
||||
}
|
||||
|
||||
func (b *Bus) SubscribeResult(f func(msg *ResultMsg)) error {
|
||||
return b.safeSubscribe(b.config.resultBusKey, channelResult, func(c *emitter.Client, m emitter.Message) {
|
||||
var msg ResultMsg
|
||||
if err := json.Unmarshal(m.Payload(), &msg); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
go f(&msg)
|
||||
})
|
||||
}
|
||||
60
busservice/busservice.go
Normal file
60
busservice/busservice.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package busservice
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
"github.com/SecurityBrewery/catalyst/time"
|
||||
)
|
||||
|
||||
type busService struct {
|
||||
db *database.Database
|
||||
apiURL string
|
||||
apiKey string
|
||||
catalystBus *bus.Bus
|
||||
}
|
||||
|
||||
func New(apiurl, apikey string, catalystBus *bus.Bus, db *database.Database) error {
|
||||
|
||||
h := &busService{db: db, apiURL: apiurl, apiKey: apikey, catalystBus: catalystBus}
|
||||
|
||||
if err := catalystBus.SubscribeRequest(h.logRequest); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := catalystBus.SubscribeResult(h.handleResult); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := catalystBus.SubscribeJob(h.handleJob); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func busContext() context.Context {
|
||||
// TODO: change roles?
|
||||
bot := &models.UserResponse{ID: "bot", Roles: []string{role.Admin}}
|
||||
return busdb.UserContext(context.Background(), bot)
|
||||
}
|
||||
|
||||
func (h *busService) logRequest(msg *bus.RequestMsg) {
|
||||
var logEntries []*models.LogEntry
|
||||
for _, i := range msg.IDs {
|
||||
logEntries = append(logEntries, &models.LogEntry{
|
||||
Type: bus.ChannelRequest,
|
||||
Reference: i.String(),
|
||||
Creator: msg.User,
|
||||
Message: msg.Function,
|
||||
Created: time.Now().UTC(),
|
||||
})
|
||||
}
|
||||
|
||||
if err := h.db.LogBatchCreate(busContext(), logEntries); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package automation
|
||||
package busservice
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
113
busservice/job.go
Normal file
113
busservice/job.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package busservice
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
func (h *busService) handleJob(automationMsg *bus.JobMsg) {
|
||||
ctx := busContext()
|
||||
|
||||
job, err := h.db.JobCreate(ctx, automationMsg.ID, &models.JobForm{
|
||||
Automation: automationMsg.Automation,
|
||||
Payload: automationMsg.Message.Payload,
|
||||
Origin: automationMsg.Origin,
|
||||
})
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
automation, err := h.db.AutomationGet(ctx, automationMsg.Automation)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if automation.Script == "" {
|
||||
log.Println("automation is empty")
|
||||
return
|
||||
}
|
||||
|
||||
if automationMsg.Message.Secrets == nil {
|
||||
automationMsg.Message.Secrets = map[string]string{}
|
||||
}
|
||||
automationMsg.Message.Secrets["catalyst_apikey"] = h.apiKey
|
||||
automationMsg.Message.Secrets["catalyst_apiurl"] = h.apiURL
|
||||
|
||||
scriptMessage, _ := json.Marshal(automationMsg.Message)
|
||||
|
||||
containerID, logs, err := createContainer(ctx, automation.Image, automation.Script, string(scriptMessage))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := h.db.JobUpdate(ctx, automationMsg.ID, &models.Job{
|
||||
Automation: job.Automation,
|
||||
Container: &containerID,
|
||||
Origin: job.Origin,
|
||||
Output: job.Output,
|
||||
Log: &logs,
|
||||
Payload: job.Payload,
|
||||
Status: job.Status,
|
||||
}); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
var result map[string]interface{}
|
||||
|
||||
stdout, _, err := runDocker(ctx, automationMsg.ID, containerID, h.db)
|
||||
if err != nil {
|
||||
result = map[string]interface{}{"error": fmt.Sprintf("error running script %s %s", err, string(stdout))}
|
||||
} else {
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(stdout, &data); err != nil {
|
||||
result = map[string]interface{}{"error": string(stdout)}
|
||||
} else {
|
||||
result = data
|
||||
}
|
||||
}
|
||||
|
||||
if err := h.catalystBus.PublishResult(automationMsg.Automation, result, automationMsg.Origin); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
|
||||
if err := h.db.JobComplete(ctx, automationMsg.ID, result); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func getAutomation(automationID string, config *Config) (*models.AutomationResponse, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, config.CatalystAPIUrl+"/automations/"+automationID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req.Header.Set("PRIVATE-TOKEN", config.CatalystAPIKey)
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var automation models.AutomationResponse
|
||||
if err := json.Unmarshal(b, &automation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &automation, nil
|
||||
}
|
||||
*/
|
||||
35
busservice/result.go
Normal file
35
busservice/result.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package busservice
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
)
|
||||
|
||||
func (h *busService) handleResult(resultMsg *bus.ResultMsg) {
|
||||
if resultMsg.Target != nil {
|
||||
ctx := busContext()
|
||||
switch {
|
||||
case resultMsg.Target.TaskOrigin != nil:
|
||||
if _, err := h.db.TaskComplete(
|
||||
ctx,
|
||||
resultMsg.Target.TaskOrigin.TicketId,
|
||||
resultMsg.Target.TaskOrigin.PlaybookId,
|
||||
resultMsg.Target.TaskOrigin.TaskId,
|
||||
resultMsg.Data,
|
||||
); err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
case resultMsg.Target.ArtifactOrigin != nil:
|
||||
enrichment := &models.EnrichmentForm{
|
||||
Data: resultMsg.Data,
|
||||
Name: resultMsg.Automation,
|
||||
}
|
||||
_, err := h.db.EnrichArtifact(ctx, resultMsg.Target.ArtifactOrigin.TicketId, resultMsg.Target.ArtifactOrigin.Artifact, enrichment)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/time"
|
||||
@@ -60,11 +61,10 @@ func (db *Database) ArtifactUpdate(ctx context.Context, id int64, name string, a
|
||||
"name": name,
|
||||
"artifact": artifact,
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Update artifact %s", name),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -92,10 +92,9 @@ func (db *Database) EnrichArtifact(ctx context.Context, id int64, name string, e
|
||||
"enrichmentname": enrichment.Name,
|
||||
"enrichment": enrichment,
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Run %s on artifact", enrichment.Name),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -33,22 +33,13 @@ func NewDatabase(ctx context.Context, internal driver.Database, b *bus.Bus) (*Bu
|
||||
}, nil
|
||||
}
|
||||
|
||||
type OperationType int
|
||||
|
||||
const (
|
||||
Create OperationType = iota
|
||||
Read = iota
|
||||
Update = iota
|
||||
)
|
||||
|
||||
type Operation struct {
|
||||
OperationType OperationType
|
||||
Ids []driver.DocumentID
|
||||
Msg string
|
||||
Type bus.DatabaseUpdateType
|
||||
Ids []driver.DocumentID
|
||||
}
|
||||
|
||||
var CreateOperation = &Operation{OperationType: Create}
|
||||
var ReadOperation = &Operation{OperationType: Read}
|
||||
var CreateOperation = &Operation{Type: bus.DatabaseEntryCreated}
|
||||
var ReadOperation = &Operation{Type: bus.DatabaseEntryRead}
|
||||
|
||||
func (db BusDatabase) Query(ctx context.Context, query string, vars map[string]interface{}, operation *Operation) (driver.Cursor, *models.LogEntry, error) {
|
||||
cur, err := db.internal.Query(ctx, query, vars)
|
||||
@@ -59,8 +50,8 @@ func (db BusDatabase) Query(ctx context.Context, query string, vars map[string]i
|
||||
var logs *models.LogEntry
|
||||
|
||||
switch {
|
||||
case operation.OperationType == Update:
|
||||
if err := db.LogAndNotify(ctx, operation.Ids, operation.Msg); err != nil {
|
||||
case operation.Type == bus.DatabaseEntryCreated, operation.Type == bus.DatabaseEntryUpdated:
|
||||
if err := db.bus.PublishDatabaseUpdate(operation.Ids, operation.Type); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
@@ -68,19 +59,6 @@ func (db BusDatabase) Query(ctx context.Context, query string, vars map[string]i
|
||||
return cur, logs, err
|
||||
}
|
||||
|
||||
func (db BusDatabase) LogAndNotify(ctx context.Context, ids []driver.DocumentID, msg string) error {
|
||||
var logEntries []*models.LogEntry
|
||||
for _, i := range ids {
|
||||
logEntries = append(logEntries, &models.LogEntry{Reference: i.String(), Message: msg})
|
||||
}
|
||||
|
||||
if err := db.LogBatchCreate(ctx, logEntries); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return db.bus.PublishUpdate(ids)
|
||||
}
|
||||
|
||||
func (db BusDatabase) Remove(ctx context.Context) error {
|
||||
return db.internal.Remove(ctx)
|
||||
}
|
||||
@@ -104,7 +82,7 @@ func (c Collection) CreateDocument(ctx, newctx context.Context, key string, docu
|
||||
return meta, err
|
||||
}
|
||||
|
||||
err = c.db.LogAndNotify(ctx, []driver.DocumentID{meta.ID}, "Document created")
|
||||
err = c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryCreated)
|
||||
if err != nil {
|
||||
return meta, err
|
||||
}
|
||||
@@ -117,7 +95,7 @@ func (c Collection) CreateEdge(ctx, newctx context.Context, edge *driver.EdgeDoc
|
||||
return meta, err
|
||||
}
|
||||
|
||||
err = c.db.LogAndNotify(ctx, []driver.DocumentID{meta.ID}, "Document created")
|
||||
err = c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryCreated)
|
||||
if err != nil {
|
||||
return meta, err
|
||||
}
|
||||
@@ -138,7 +116,7 @@ func (c Collection) CreateEdges(ctx context.Context, edges []*driver.EdgeDocumen
|
||||
ids = append(ids, meta.ID)
|
||||
}
|
||||
|
||||
err = c.db.LogAndNotify(ctx, ids, "Document created")
|
||||
err = c.db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryCreated)
|
||||
if err != nil {
|
||||
return metas, err
|
||||
}
|
||||
@@ -160,7 +138,7 @@ func (c Collection) UpdateDocument(ctx context.Context, key string, update inter
|
||||
return meta, err
|
||||
}
|
||||
|
||||
return meta, c.db.bus.PublishUpdate([]driver.DocumentID{meta.ID})
|
||||
return meta, c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryUpdated)
|
||||
}
|
||||
|
||||
func (c Collection) ReplaceDocument(ctx context.Context, key string, document interface{}) (driver.DocumentMeta, error) {
|
||||
@@ -169,7 +147,7 @@ func (c Collection) ReplaceDocument(ctx context.Context, key string, document in
|
||||
return meta, err
|
||||
}
|
||||
|
||||
return meta, c.db.bus.PublishUpdate([]driver.DocumentID{meta.ID})
|
||||
return meta, c.db.bus.PublishDatabaseUpdate([]driver.DocumentID{meta.ID}, bus.DatabaseEntryUpdated)
|
||||
}
|
||||
|
||||
func (c Collection) RemoveDocument(ctx context.Context, formatInt string) (driver.DocumentMeta, error) {
|
||||
|
||||
@@ -3,6 +3,8 @@ package busdb
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"strings"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
@@ -12,15 +14,16 @@ import (
|
||||
|
||||
const LogCollectionName = "logs"
|
||||
|
||||
func (db *BusDatabase) LogCreate(ctx context.Context, reference, message string) (*models.LogEntry, error) {
|
||||
func (db *BusDatabase) LogCreate(ctx context.Context, logType, reference, message string) (*models.LogEntry, error) {
|
||||
user, ok := UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
|
||||
logentry := &models.LogEntry{
|
||||
Type: logType,
|
||||
Reference: reference,
|
||||
Created: time.Now(),
|
||||
Created: time.Now().UTC(),
|
||||
Creator: user.ID,
|
||||
Message: message,
|
||||
}
|
||||
@@ -31,27 +34,18 @@ func (db *BusDatabase) LogCreate(ctx context.Context, reference, message string)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &doc, db.bus.PublishUpdate([]driver.DocumentID{driver.DocumentID(logentry.Reference)})
|
||||
return &doc, nil
|
||||
}
|
||||
|
||||
func (db *BusDatabase) LogBatchCreate(ctx context.Context, logEntryForms []*models.LogEntry) error {
|
||||
user, ok := UserFromContext(ctx)
|
||||
if !ok {
|
||||
return errors.New("no user in context")
|
||||
}
|
||||
|
||||
func (db *BusDatabase) LogBatchCreate(ctx context.Context, logentries []*models.LogEntry) error {
|
||||
var ids []driver.DocumentID
|
||||
var logentries []*models.LogEntry
|
||||
for _, logEntryForm := range logEntryForms {
|
||||
logentry := &models.LogEntry{
|
||||
Reference: logEntryForm.Reference,
|
||||
Created: time.Now(),
|
||||
Creator: user.ID,
|
||||
Message: logEntryForm.Message,
|
||||
for _, entry := range logentries {
|
||||
if strings.HasPrefix(entry.Reference, "tickets/") {
|
||||
ids = append(ids, driver.DocumentID(entry.Reference))
|
||||
}
|
||||
|
||||
logentries = append(logentries, logentry)
|
||||
ids = append(ids, driver.DocumentID(logentry.Reference))
|
||||
}
|
||||
if ids != nil {
|
||||
go db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryCreated)
|
||||
}
|
||||
|
||||
_, errs, err := db.logCollection.CreateDocuments(ctx, logentries)
|
||||
@@ -63,7 +57,7 @@ func (db *BusDatabase) LogBatchCreate(ctx context.Context, logEntryForms []*mode
|
||||
return err
|
||||
}
|
||||
|
||||
return db.bus.PublishUpdate(ids)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *BusDatabase) LogList(ctx context.Context, reference string) ([]*models.LogEntry, error) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/caql"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
@@ -144,11 +145,10 @@ func (db *Database) JobLogAppend(ctx context.Context, id string, logLine string)
|
||||
"ID": id,
|
||||
"logline": logLine,
|
||||
}, &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%s", JobCollectionName, id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Append logline"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -166,11 +166,10 @@ func (db *Database) JobComplete(ctx context.Context, id string, out interface{})
|
||||
"ID": id,
|
||||
"out": out,
|
||||
}, &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%s", JobCollectionName, id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Set output"),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
)
|
||||
|
||||
@@ -37,12 +38,11 @@ func (db *Database) RelatedRemove(ctx context.Context, id, id2 int64) error {
|
||||
"id": driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id))),
|
||||
"id2": driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id2))),
|
||||
}, &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id))),
|
||||
driver.DocumentID(TicketCollectionName + "/" + strconv.Itoa(int(id2))),
|
||||
},
|
||||
Msg: "Removed ticket/artifact relation",
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/caql"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
@@ -133,7 +134,7 @@ func toTicketSimpleResponse(key string, ticket *models.Ticket) (*models.TicketSi
|
||||
}, nil
|
||||
}
|
||||
|
||||
func toTicketWithTickets(ticketResponse *models.TicketResponse, tickets []*models.TicketSimpleResponse) *models.TicketWithTickets {
|
||||
func toTicketWithTickets(ticketResponse *models.TicketResponse, tickets []*models.TicketSimpleResponse, logs []*models.LogEntry) *models.TicketWithTickets {
|
||||
return &models.TicketWithTickets{
|
||||
Artifacts: ticketResponse.Artifacts,
|
||||
Comments: ticketResponse.Comments,
|
||||
@@ -152,6 +153,7 @@ func toTicketWithTickets(ticketResponse *models.TicketResponse, tickets []*model
|
||||
Type: ticketResponse.Type,
|
||||
Write: ticketResponse.Write,
|
||||
|
||||
Logs: logs,
|
||||
Tickets: tickets,
|
||||
}
|
||||
}
|
||||
@@ -244,9 +246,8 @@ func (db *Database) TicketBatchCreate(ctx context.Context, ticketForms []*models
|
||||
for _, apiTicket := range apiTickets {
|
||||
ids = append(ids, driver.NewDocumentID(TicketCollectionName, fmt.Sprint(apiTicket.ID)))
|
||||
}
|
||||
if err := db.BusDatabase.LogAndNotify(ctx, ids, "Ticket created"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go db.bus.PublishDatabaseUpdate(ids, bus.DatabaseEntryUpdated)
|
||||
|
||||
ticketResponses, err := toTicketResponses(apiTickets)
|
||||
if err != nil {
|
||||
@@ -405,7 +406,12 @@ func (db *Database) ticketGetQuery(ctx context.Context, ticketID int64, query st
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toTicketWithTickets(ticketResponse, tickets), nil
|
||||
logs, err := db.LogList(ctx, fmt.Sprintf("%s/%d", TicketCollectionName, ticketID))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return toTicketWithTickets(ticketResponse, tickets, logs), nil
|
||||
}
|
||||
|
||||
func (db *Database) TicketUpdate(ctx context.Context, ticketID int64, ticket *models.Ticket) (*models.TicketWithTickets, error) {
|
||||
@@ -420,10 +426,9 @@ func (db *Database) TicketUpdate(ctx context.Context, ticketID int64, ticket *mo
|
||||
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{
|
||||
OperationType: busdb.Update, Ids: []driver.DocumentID{
|
||||
Type: bus.DatabaseEntryUpdated, Ids: []driver.DocumentID{
|
||||
driver.NewDocumentID(TicketCollectionName, strconv.FormatInt(ticketID, 10)),
|
||||
},
|
||||
Msg: "Ticket updated",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/iancoleman/strcase"
|
||||
"github.com/mingrammer/commonregex"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/pointer"
|
||||
@@ -34,11 +35,10 @@ func (db *Database) AddArtifact(ctx context.Context, id int64, artifact *models.
|
||||
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{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Add artifact",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -74,11 +74,10 @@ func (db *Database) RemoveArtifact(ctx context.Context, id int64, name string) (
|
||||
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{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Remove artifact",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -93,11 +92,10 @@ func (db *Database) SetTemplate(ctx context.Context, id int64, schema string) (*
|
||||
UPDATE d WITH { "schema": @schema } IN @@collection
|
||||
RETURN NEW`
|
||||
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"schema": schema}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Set Template",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -125,11 +123,10 @@ func (db *Database) AddComment(ctx context.Context, id int64, comment *models.Co
|
||||
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{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Add comment",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -144,11 +141,10 @@ func (db *Database) RemoveComment(ctx context.Context, id int64, commentID int64
|
||||
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{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Remove comment",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -163,11 +159,10 @@ func (db *Database) SetReferences(ctx context.Context, id int64, references []*m
|
||||
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{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Changed references",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -182,11 +177,10 @@ func (db *Database) LinkFiles(ctx context.Context, id int64, files []*models.Fil
|
||||
UPDATE d WITH { "modified": @now, "files": @files } IN @@collection
|
||||
RETURN NEW`
|
||||
return db.ticketGetQuery(ctx, id, query, mergeMaps(map[string]interface{}{"files": files, "now": time.Now().UTC()}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.DocumentID(fmt.Sprintf("%s/%d", TicketCollectionName, id)),
|
||||
},
|
||||
Msg: "Linked files",
|
||||
})
|
||||
}
|
||||
|
||||
@@ -224,11 +218,10 @@ func (db *Database) AddTicketPlaybook(ctx context.Context, id int64, playbookTem
|
||||
"playbookID": findName(parentTicket.Playbooks, playbookID),
|
||||
"now": time.Now().UTC(),
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.NewDocumentID(TicketCollectionName, fmt.Sprintf("%d", id)),
|
||||
},
|
||||
Msg: "Added playbook",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -284,10 +277,9 @@ func (db *Database) RemoveTicketPlaybook(ctx context.Context, id int64, playbook
|
||||
"playbookID": playbookID,
|
||||
"now": time.Now().UTC(),
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.NewDocumentID(TicketCollectionName, fmt.Sprintf("%d", id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Removed playbook %s", playbookID),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/time"
|
||||
@@ -74,11 +75,10 @@ func (db *Database) TaskComplete(ctx context.Context, id int64, playbookID strin
|
||||
"closed": time.Now().UTC(),
|
||||
"now": time.Now().UTC(),
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.NewDocumentID(TicketCollectionName, fmt.Sprintf("%d", id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Completed task %s in playbook %s", taskID, playbookID),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -136,11 +136,10 @@ func (db *Database) TaskUpdate(ctx context.Context, id int64, playbookID string,
|
||||
"task": task,
|
||||
"now": time.Now().UTC(),
|
||||
}, ticketFilterVars), &busdb.Operation{
|
||||
OperationType: busdb.Update,
|
||||
Type: bus.DatabaseEntryUpdated,
|
||||
Ids: []driver.DocumentID{
|
||||
driver.NewDocumentID(TicketCollectionName, fmt.Sprintf("%d", id)),
|
||||
},
|
||||
Msg: fmt.Sprintf("Saved task %s in playbook %s", taskID, playbookID),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -16,14 +16,15 @@ paths:
|
||||
schema: { type: array, items: { $ref: "#/definitions/LogEntry" } }
|
||||
examples:
|
||||
test:
|
||||
- { "created": "2021-12-12T12:12:12.000000012Z","creator": "bob","reference": "tickets/294511","message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim." }
|
||||
- { type: "manual", "created": "2021-12-12T12:12:12.000000012Z","creator": "bob","reference": "tickets/294511","message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim." }
|
||||
security: [ { roles: [ "log:read" ] } ]
|
||||
|
||||
definitions:
|
||||
LogEntry:
|
||||
type: object
|
||||
required: [ reference, creator, created, message ]
|
||||
required: [ type, reference, creator, created, message ]
|
||||
properties:
|
||||
type: { type: string }
|
||||
reference: { type: string }
|
||||
creator: { type: string }
|
||||
created: { type: string, format: "date-time" }
|
||||
|
||||
@@ -1037,6 +1037,8 @@ definitions:
|
||||
comments: { type: array, items: { $ref: '#/definitions/Comment' } }
|
||||
artifacts: { type: array, items: { $ref: "#/definitions/Artifact" } }
|
||||
|
||||
logs: { type: array, items: { $ref: '#/definitions/LogEntry' } }
|
||||
|
||||
created: { type: string, format: "date-time", example: "1985-04-12T23:20:50.52Z" }
|
||||
modified: { type: string, format: "date-time", example: "1985-04-12T23:20:50.52Z" }
|
||||
|
||||
|
||||
@@ -723,7 +723,8 @@
|
||||
"created" : "2021-12-12T12:12:12.000+0000",
|
||||
"creator" : "bob",
|
||||
"message" : "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.",
|
||||
"reference" : "tickets/294511"
|
||||
"reference" : "tickets/294511",
|
||||
"type" : "manual"
|
||||
} ]
|
||||
}
|
||||
},
|
||||
@@ -5418,9 +5419,12 @@
|
||||
},
|
||||
"reference" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required" : [ "created", "creator", "message", "reference" ],
|
||||
"required" : [ "created", "creator", "message", "reference", "type" ],
|
||||
"type" : "object"
|
||||
},
|
||||
"Message" : {
|
||||
@@ -6445,6 +6449,12 @@
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"logs" : {
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/LogEntry"
|
||||
},
|
||||
"type" : "array"
|
||||
},
|
||||
"modified" : {
|
||||
"format" : "date-time",
|
||||
"type" : "string"
|
||||
|
||||
@@ -312,7 +312,10 @@ definitions:
|
||||
type: string
|
||||
reference:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
- reference
|
||||
- creator
|
||||
- created
|
||||
@@ -1152,6 +1155,10 @@ definitions:
|
||||
example: 123
|
||||
format: int64
|
||||
type: integer
|
||||
logs:
|
||||
items:
|
||||
$ref: '#/definitions/LogEntry'
|
||||
type: array
|
||||
modified:
|
||||
example: 1985-04-12T23:20:50.52Z
|
||||
format: date-time
|
||||
@@ -1945,6 +1952,7 @@ paths:
|
||||
combine wish influence income guess run stand. Charge limit crime
|
||||
ignore statement foundation study issue stop claim.
|
||||
reference: tickets/294511
|
||||
type: manual
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/LogEntry'
|
||||
|
||||
@@ -491,7 +491,8 @@
|
||||
"created" : "2021-12-12T12:12:12.000+0000",
|
||||
"creator" : "bob",
|
||||
"message" : "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.",
|
||||
"reference" : "tickets/294511"
|
||||
"reference" : "tickets/294511",
|
||||
"type" : "manual"
|
||||
} ]
|
||||
}
|
||||
},
|
||||
@@ -4905,9 +4906,12 @@
|
||||
},
|
||||
"reference" : {
|
||||
"type" : "string"
|
||||
},
|
||||
"type" : {
|
||||
"type" : "string"
|
||||
}
|
||||
},
|
||||
"required" : [ "created", "creator", "message", "reference" ],
|
||||
"required" : [ "created", "creator", "message", "reference", "type" ],
|
||||
"type" : "object"
|
||||
},
|
||||
"Message" : {
|
||||
@@ -5866,6 +5870,12 @@
|
||||
"format" : "int64",
|
||||
"type" : "integer"
|
||||
},
|
||||
"logs" : {
|
||||
"items" : {
|
||||
"$ref" : "#/components/schemas/LogEntry"
|
||||
},
|
||||
"type" : "array"
|
||||
},
|
||||
"modified" : {
|
||||
"format" : "date-time",
|
||||
"type" : "string"
|
||||
|
||||
@@ -247,7 +247,10 @@ definitions:
|
||||
type: string
|
||||
reference:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
- type
|
||||
- reference
|
||||
- creator
|
||||
- created
|
||||
@@ -1033,6 +1036,10 @@ definitions:
|
||||
example: 123
|
||||
format: int64
|
||||
type: integer
|
||||
logs:
|
||||
items:
|
||||
$ref: '#/definitions/LogEntry'
|
||||
type: array
|
||||
modified:
|
||||
example: 1985-04-12T23:20:50.52Z
|
||||
format: date-time
|
||||
@@ -1674,6 +1681,7 @@ paths:
|
||||
combine wish influence income guess run stand. Charge limit crime
|
||||
ignore statement foundation study issue stop claim.
|
||||
reference: tickets/294511
|
||||
type: manual
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/LogEntry'
|
||||
|
||||
@@ -77,7 +77,7 @@ func init() {
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["automation","running","status"],"x-embed":"","properties":{"automation":{"type":"string"},"container":{"type":"string"},"log":{"type":"string"},"origin":{"$ref":"#/definitions/Origin"},"output":{"type":"object"},"payload":{},"running":{"type":"boolean"},"status":{"type":"string"}},"$id":"#/definitions/Job"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["automation"],"x-embed":"","properties":{"automation":{"type":"string"},"origin":{"$ref":"#/definitions/Origin"},"payload":{}},"$id":"#/definitions/JobForm"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","automation","status"],"x-embed":"","properties":{"automation":{"type":"string"},"container":{"type":"string"},"id":{"type":"string"},"log":{"type":"string"},"origin":{"$ref":"#/definitions/Origin"},"output":{"type":"object"},"payload":{},"status":{"type":"string"}},"$id":"#/definitions/JobResponse"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["reference","creator","created","message"],"x-embed":"","properties":{"created":{"format":"date-time","type":"string"},"creator":{"type":"string"},"message":{"type":"string"},"reference":{"type":"string"}},"$id":"#/definitions/LogEntry"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["type","reference","creator","created","message"],"x-embed":"","properties":{"created":{"format":"date-time","type":"string"},"creator":{"type":"string"},"message":{"type":"string"},"reference":{"type":"string"},"type":{"type":"string"}},"$id":"#/definitions/LogEntry"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","x-embed":"","properties":{"context":{"$ref":"#/definitions/Context"},"payload":{"type":"object"},"secrets":{"type":"object","additionalProperties":{"type":"string"}}},"$id":"#/definitions/Message"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","blocked","roles"],"x-embed":"","properties":{"blocked":{"type":"boolean"},"id":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"},"secret":{"type":"string"}},"$id":"#/definitions/NewUserResponse"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","x-embed":"","properties":{"artifact_origin":{"$ref":"#/definitions/ArtifactOrigin"},"task_origin":{"$ref":"#/definitions/TaskOrigin"}},"$id":"#/definitions/Origin"}`),
|
||||
@@ -105,7 +105,7 @@ func init() {
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["name","icon","default_template","default_playbooks"],"x-embed":"","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"name":{"type":"string"}},"$id":"#/definitions/TicketType"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["name","icon","default_template","default_playbooks"],"x-embed":"","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"$id":"#/definitions/TicketTypeForm"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","name","icon","default_template","default_playbooks"],"x-embed":"","properties":{"default_groups":{"items":{"type":"string"},"type":"array"},"default_playbooks":{"items":{"type":"string"},"type":"array"},"default_template":{"type":"string"},"icon":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"$id":"#/definitions/TicketTypeResponse"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","name","type","status","created","modified","schema"],"x-embed":"","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"$id":"#/definitions/TicketWithTickets"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","name","type","status","created","modified","schema"],"x-embed":"","properties":{"artifacts":{"items":{"$ref":"#/definitions/Artifact"},"type":"array"},"comments":{"items":{"$ref":"#/definitions/Comment"},"type":"array"},"created":{"format":"date-time","type":"string"},"details":{"type":"object"},"files":{"items":{"$ref":"#/definitions/File"},"type":"array"},"id":{"format":"int64","type":"integer"},"logs":{"items":{"$ref":"#/definitions/LogEntry"},"type":"array"},"modified":{"format":"date-time","type":"string"},"name":{"type":"string"},"owner":{"type":"string"},"playbooks":{"type":"object","additionalProperties":{"$ref":"#/definitions/PlaybookResponse"}},"read":{"items":{"type":"string"},"type":"array"},"references":{"items":{"$ref":"#/definitions/Reference"},"type":"array"},"schema":{"type":"string"},"status":{"type":"string"},"tickets":{"items":{"$ref":"#/definitions/TicketSimpleResponse"},"type":"array"},"type":{"type":"string"},"write":{"items":{"type":"string"},"type":"array"}},"$id":"#/definitions/TicketWithTickets"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["id","name","icon"],"x-embed":"","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"}},"$id":"#/definitions/Type"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","required":["blocked","apikey","roles"],"x-embed":"","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"sha256":{"type":"string"}},"$id":"#/definitions/User"}`),
|
||||
gojsonschema.NewStringLoader(`{"type":"object","x-embed":"","properties":{"email":{"type":"string"},"image":{"type":"string"},"name":{"type":"string"},"timeformat":{"title":"Time Format (https://moment.github.io/luxon/docs/manual/formatting.html#table-of-tokens)","type":"string"}},"$id":"#/definitions/UserData"}`),
|
||||
@@ -271,6 +271,7 @@ type LogEntry struct {
|
||||
Creator string `json:"creator"`
|
||||
Message string `json:"message"`
|
||||
Reference string `json:"reference"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
@@ -530,6 +531,7 @@ type TicketWithTickets struct {
|
||||
Details interface{} `json:"details,omitempty"`
|
||||
Files []*File `json:"files,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
Logs []*LogEntry `json:"logs,omitempty"`
|
||||
Modified time.Time `json:"modified"`
|
||||
Name string `json:"name"`
|
||||
Owner *string `json:"owner,omitempty"`
|
||||
|
||||
@@ -640,7 +640,8 @@ func init() {
|
||||
"created": "2021-12-12T12:12:12.000000012Z",
|
||||
"creator": "bob",
|
||||
"message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.",
|
||||
"reference": "tickets/294511"
|
||||
"reference": "tickets/294511",
|
||||
"type": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5680,6 +5681,7 @@ func init() {
|
||||
"LogEntry": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"reference",
|
||||
"creator",
|
||||
"created",
|
||||
@@ -5698,6 +5700,9 @@ func init() {
|
||||
},
|
||||
"reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -6816,6 +6821,12 @@ func init() {
|
||||
"format": "int64",
|
||||
"example": 123
|
||||
},
|
||||
"logs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LogEntry"
|
||||
}
|
||||
},
|
||||
"modified": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
@@ -7668,7 +7679,8 @@ func init() {
|
||||
"created": "2021-12-12T12:12:12.000000012Z",
|
||||
"creator": "bob",
|
||||
"message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.",
|
||||
"reference": "tickets/294511"
|
||||
"reference": "tickets/294511",
|
||||
"type": "manual"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12708,6 +12720,7 @@ func init() {
|
||||
"LogEntry": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"reference",
|
||||
"creator",
|
||||
"created",
|
||||
@@ -12726,6 +12739,9 @@ func init() {
|
||||
},
|
||||
"reference": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -13844,6 +13860,12 @@ func init() {
|
||||
"format": "int64",
|
||||
"example": 123
|
||||
},
|
||||
"logs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/LogEntry"
|
||||
}
|
||||
},
|
||||
"modified": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
|
||||
@@ -233,7 +233,7 @@ func TestService(t *testing.T) {
|
||||
args: args{method: "GET", url: "/api/logs/tickets%252F294511"},
|
||||
want: want{
|
||||
status: 200,
|
||||
body: []interface{}{map[string]interface{}{"created": "2021-12-12T12:12:12.000000012Z", "creator": "bob", "message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.", "reference": "tickets/294511"}},
|
||||
body: []interface{}{map[string]interface{}{"created": "2021-12-12T12:12:12.000000012Z", "creator": "bob", "message": "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim.", "reference": "tickets/294511", "type": "manual"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
2
go.mod
2
go.mod
@@ -55,7 +55,7 @@ require (
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.mongodb.org/mongo-driver v1.7.4 // indirect
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
|
||||
golang.org/x/net v0.0.0-20211105192438-b53810dc28af
|
||||
golang.org/x/net v0.0.0-20211105192438-b53810dc28af // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c // indirect
|
||||
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/automation"
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/busservice"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
@@ -72,7 +72,7 @@ func New(hooks *hooks.Hooks, config *Config) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = automation.New(config.Bus.APIUrl, config.InitialAPIKey, catalystBus, catalystDatabase)
|
||||
err = busservice.New(config.Bus.APIUrl, config.InitialAPIKey, catalystBus, catalystDatabase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,25 +10,29 @@ import (
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/tickets"
|
||||
)
|
||||
|
||||
func (s *Service) RunArtifact(ctx context.Context, params *tickets.RunArtifactParams) *api.Response {
|
||||
func (s *Service) RunArtifact(ctx context.Context, params *tickets.RunArtifactParams) (r *api.Response) {
|
||||
artifact, err := s.database.ArtifactGet(ctx, params.ID, params.Name)
|
||||
if err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "RunArtifact", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
jobID := uuid.NewString()
|
||||
origin := &models.Origin{ArtifactOrigin: &models.ArtifactOrigin{TicketId: params.ID, Artifact: params.Name}}
|
||||
return response(nil, s.bus.PublishJob(jobID, params.Automation, params.Name, &models.Context{Artifact: artifact}, origin))
|
||||
err = s.bus.PublishJob(jobID, params.Automation, params.Name, &models.Context{Artifact: artifact}, origin)
|
||||
return s.response(ctx, "RunArtifact", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) EnrichArtifact(ctx context.Context, params *tickets.EnrichArtifactParams) *api.Response {
|
||||
return response(s.database.EnrichArtifact(ctx, params.ID, params.Name, params.Data))
|
||||
i, err := s.database.EnrichArtifact(ctx, params.ID, params.Name, params.Data)
|
||||
return s.response(ctx, "EnrichArtifact", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) SetArtifact(ctx context.Context, params *tickets.SetArtifactParams) *api.Response {
|
||||
return response(s.database.ArtifactUpdate(ctx, params.ID, params.Name, params.Artifact))
|
||||
i, err := s.database.ArtifactUpdate(ctx, params.ID, params.Name, params.Artifact)
|
||||
return s.response(ctx, "SetArtifact", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetArtifact(ctx context.Context, params *tickets.GetArtifactParams) *api.Response {
|
||||
return response(s.database.ArtifactGet(ctx, params.ID, params.Name))
|
||||
i, err := s.database.ArtifactGet(ctx, params.ID, params.Name)
|
||||
return s.response(ctx, "GetArtifact", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -2,27 +2,40 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/automations"
|
||||
)
|
||||
|
||||
func automationID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.AutomationCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) CreateAutomation(ctx context.Context, params *automations.CreateAutomationParams) *api.Response {
|
||||
return response(s.database.AutomationCreate(ctx, params.Automation))
|
||||
i, err := s.database.AutomationCreate(ctx, params.Automation)
|
||||
return s.response(ctx, "CreateAutomation", automationID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetAutomation(ctx context.Context, params *automations.GetAutomationParams) *api.Response {
|
||||
return response(s.database.AutomationGet(ctx, params.ID))
|
||||
i, err := s.database.AutomationGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetAutomation", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateAutomation(ctx context.Context, params *automations.UpdateAutomationParams) *api.Response {
|
||||
return response(s.database.AutomationUpdate(ctx, params.ID, params.Automation))
|
||||
i, err := s.database.AutomationUpdate(ctx, params.ID, params.Automation)
|
||||
return s.response(ctx, "UpdateAutomation", automationID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteAutomation(ctx context.Context, params *automations.DeleteAutomationParams) *api.Response {
|
||||
return response(nil, s.database.AutomationDelete(ctx, params.ID))
|
||||
err := s.database.AutomationDelete(ctx, params.ID)
|
||||
return s.response(ctx, "DeleteAutomation", automationID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListAutomations(ctx context.Context) *api.Response {
|
||||
return response(s.database.AutomationList(ctx))
|
||||
i, err := s.database.AutomationList(ctx)
|
||||
return s.response(ctx, "ListAutomations", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -2,28 +2,38 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/jobs"
|
||||
)
|
||||
|
||||
func (s *Service) RunJob(_ context.Context, params *jobs.RunJobParams) *api.Response {
|
||||
func jobID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.JobCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) RunJob(ctx context.Context, params *jobs.RunJobParams) *api.Response {
|
||||
msgContext := &models.Context{}
|
||||
jobID := uuid.NewString()
|
||||
return response(nil, s.bus.PublishJob(jobID, params.Job.Automation, params.Job.Payload, msgContext, params.Job.Origin))
|
||||
newJobID := uuid.NewString()
|
||||
return s.response(ctx, "RunJob", jobID(newJobID), nil, s.bus.PublishJob(newJobID, params.Job.Automation, params.Job.Payload, msgContext, params.Job.Origin))
|
||||
}
|
||||
|
||||
func (s *Service) GetJob(ctx context.Context, params *jobs.GetJobParams) *api.Response {
|
||||
return response(s.database.JobGet(ctx, params.ID))
|
||||
i, err := s.database.JobGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetJob", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListJobs(ctx context.Context) *api.Response {
|
||||
return response(s.database.JobList(ctx))
|
||||
i, err := s.database.JobList(ctx)
|
||||
return s.response(ctx, "ListJobs", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateJob(ctx context.Context, params *jobs.UpdateJobParams) *api.Response {
|
||||
return response(s.database.JobUpdate(ctx, params.ID, params.Job))
|
||||
i, err := s.database.JobUpdate(ctx, params.ID, params.Job)
|
||||
return s.response(ctx, "UpdateJob", jobID(i.ID), i, err)
|
||||
}
|
||||
|
||||
@@ -10,5 +10,6 @@ import (
|
||||
|
||||
func (s *Service) GetLogs(ctx context.Context, params *logs.GetLogsParams) *api.Response {
|
||||
id, _ := url.QueryUnescape(params.Reference)
|
||||
return response(s.database.LogList(ctx, id))
|
||||
i, err := s.database.LogList(ctx, id)
|
||||
return s.response(ctx, "GetLogs", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -5,35 +5,46 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/playbooks"
|
||||
)
|
||||
|
||||
func playbookID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.PlaybookCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) CreatePlaybook(ctx context.Context, params *playbooks.CreatePlaybookParams) *api.Response {
|
||||
return response(s.database.PlaybookCreate(ctx, params.Playbook))
|
||||
i, err := s.database.PlaybookCreate(ctx, params.Playbook)
|
||||
return s.response(ctx, "CreatePlaybook", playbookID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetPlaybook(ctx context.Context, params *playbooks.GetPlaybookParams) *api.Response {
|
||||
return response(s.database.PlaybookGet(ctx, params.ID))
|
||||
i, err := s.database.PlaybookGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetPlaybook", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdatePlaybook(ctx context.Context, params *playbooks.UpdatePlaybookParams) *api.Response {
|
||||
if err := validate(params.Playbook, models.PlaybookTemplateFormSchema); err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "UpdatePlaybook", nil, nil, err)
|
||||
}
|
||||
|
||||
return response(s.database.PlaybookUpdate(ctx, params.ID, params.Playbook))
|
||||
i, err := s.database.PlaybookUpdate(ctx, params.ID, params.Playbook)
|
||||
return s.response(ctx, "UpdatePlaybook", playbookID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeletePlaybook(ctx context.Context, params *playbooks.DeletePlaybookParams) *api.Response {
|
||||
return response(nil, s.database.PlaybookDelete(ctx, params.ID))
|
||||
err := s.database.PlaybookDelete(ctx, params.ID)
|
||||
return s.response(ctx, "DeletePlaybook", playbookID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListPlaybooks(ctx context.Context) *api.Response {
|
||||
return response(s.database.PlaybookList(ctx))
|
||||
i, err := s.database.PlaybookList(ctx)
|
||||
return s.response(ctx, "ListPlaybooks", nil, i, err)
|
||||
}
|
||||
|
||||
func validate(e interface{}, schema *gojsonschema.Schema) error {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
@@ -30,11 +32,22 @@ func (s *Service) Healthy() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func response(v interface{}, err error) *api.Response {
|
||||
func (s *Service) response(ctx context.Context, function string, ids []driver.DocumentID, v interface{}, err error) *api.Response {
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return &api.Response{Code: httpStatus(err), Body: gin.H{"error": err.Error()}}
|
||||
}
|
||||
|
||||
if ids != nil {
|
||||
userID := "unknown"
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
if ok {
|
||||
userID = user.ID
|
||||
}
|
||||
|
||||
go s.bus.PublishRequest(userID, function, ids)
|
||||
}
|
||||
|
||||
if v == nil {
|
||||
return &api.Response{Code: http.StatusNoContent, Body: v}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) GetStatistics(ctx context.Context) *api.Response {
|
||||
return response(s.database.Statistics(ctx))
|
||||
i, err := s.database.Statistics(ctx)
|
||||
return s.response(ctx, "GetStatistics", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) ListTasks(ctx context.Context) *api.Response {
|
||||
return response(s.database.TaskList(ctx))
|
||||
i, err := s.database.TaskList(ctx)
|
||||
return s.response(ctx, "ListTasks", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -2,27 +2,40 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/templates"
|
||||
)
|
||||
|
||||
func templateID(s string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.TemplateCollectionName, s))}
|
||||
}
|
||||
|
||||
func (s *Service) CreateTemplate(ctx context.Context, params *templates.CreateTemplateParams) *api.Response {
|
||||
return response(s.database.TemplateCreate(ctx, params.Template))
|
||||
i, err := s.database.TemplateCreate(ctx, params.Template)
|
||||
return s.response(ctx, "CreateTemplate", templateID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetTemplate(ctx context.Context, params *templates.GetTemplateParams) *api.Response {
|
||||
return response(s.database.TemplateGet(ctx, params.ID))
|
||||
i, err := s.database.TemplateGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetTemplate", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateTemplate(ctx context.Context, params *templates.UpdateTemplateParams) *api.Response {
|
||||
return response(s.database.TemplateUpdate(ctx, params.ID, params.Template))
|
||||
i, err := s.database.TemplateUpdate(ctx, params.ID, params.Template)
|
||||
return s.response(ctx, "UpdateTemplate", templateID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteTemplate(ctx context.Context, params *templates.DeleteTemplateParams) *api.Response {
|
||||
return response(nil, s.database.TemplateDelete(ctx, params.ID))
|
||||
err := s.database.TemplateDelete(ctx, params.ID)
|
||||
return s.response(ctx, "DeleteTemplate", templateID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListTemplates(ctx context.Context) *api.Response {
|
||||
return response(s.database.TemplateList(ctx))
|
||||
i, err := s.database.TemplateList(ctx)
|
||||
return s.response(ctx, "ListTemplates", nil, i, err)
|
||||
}
|
||||
|
||||
@@ -4,39 +4,56 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/models"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/tickets"
|
||||
)
|
||||
|
||||
func ticketID(id int64) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%d", database.TicketCollectionName, id))}
|
||||
}
|
||||
|
||||
func ticketIDs(ticketResponses []*models.TicketResponse) []driver.DocumentID {
|
||||
var ids []driver.DocumentID
|
||||
for _, ticketResponse := range ticketResponses {
|
||||
ids = append(ids, ticketID(ticketResponse.ID)...)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func (s *Service) CreateTicket(ctx context.Context, params *tickets.CreateTicketParams) *api.Response {
|
||||
createdTickets, err := s.database.TicketBatchCreate(ctx, []*models.TicketForm{params.Ticket})
|
||||
if len(createdTickets) > 0 {
|
||||
return response(createdTickets[0], err)
|
||||
return s.response(ctx, "CreateTicket", ticketIDs(createdTickets), createdTickets[0], err)
|
||||
}
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "CreateTicket", ticketIDs(createdTickets), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) CreateTicketBatch(ctx context.Context, params *tickets.CreateTicketBatchParams) *api.Response {
|
||||
_, err := s.database.TicketBatchCreate(ctx, params.Ticket)
|
||||
return response(nil, err)
|
||||
ticketBatch, err := s.database.TicketBatchCreate(ctx, params.Ticket)
|
||||
return s.response(ctx, "CreateTicketBatch", ticketIDs(ticketBatch), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetTicket(ctx context.Context, params *tickets.GetTicketParams) *api.Response {
|
||||
return response(s.database.TicketGet(ctx, params.ID))
|
||||
ticket, err := s.database.TicketGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetTicket", nil, ticket, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateTicket(ctx context.Context, params *tickets.UpdateTicketParams) *api.Response {
|
||||
return response(s.database.TicketUpdate(ctx, params.ID, params.Ticket))
|
||||
ticket, err := s.database.TicketUpdate(ctx, params.ID, params.Ticket)
|
||||
return s.response(ctx, "UpdateTicket", ticketID(ticket.ID), ticket, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteTicket(ctx context.Context, params *tickets.DeleteTicketParams) *api.Response {
|
||||
if err := s.database.TicketDelete(ctx, params.ID); err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "DeleteTicket", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
_ = s.storage.DeleteBucket(fmt.Sprint(params.ID))
|
||||
return response(nil, nil)
|
||||
return s.response(ctx, "DeleteTicket", ticketID(params.ID), nil, nil)
|
||||
}
|
||||
|
||||
func (s *Service) ListTickets(ctx context.Context, params *tickets.ListTicketsParams) *api.Response {
|
||||
@@ -48,5 +65,7 @@ func (s *Service) ListTickets(ctx context.Context, params *tickets.ListTicketsPa
|
||||
if params.Type != nil && *params.Type != "" {
|
||||
t = *params.Type
|
||||
}
|
||||
return response(s.database.TicketList(ctx, t, q, params.Sort, params.Desc, *params.Offset, *params.Count))
|
||||
|
||||
ticketList, err := s.database.TicketList(ctx, t, q, params.Sort, params.Desc, *params.Offset, *params.Count)
|
||||
return s.response(ctx, "ListTickets", nil, ticketList, err)
|
||||
}
|
||||
|
||||
@@ -8,67 +8,81 @@ import (
|
||||
)
|
||||
|
||||
func (s *Service) AddArtifact(ctx context.Context, params *tickets.AddArtifactParams) *api.Response {
|
||||
return response(s.database.AddArtifact(ctx, params.ID, params.Artifact))
|
||||
i, err := s.database.AddArtifact(ctx, params.ID, params.Artifact)
|
||||
return s.response(ctx, "AddArtifact", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) RemoveArtifact(ctx context.Context, params *tickets.RemoveArtifactParams) *api.Response {
|
||||
return response(s.database.RemoveArtifact(ctx, params.ID, params.Name))
|
||||
i, err := s.database.RemoveArtifact(ctx, params.ID, params.Name)
|
||||
return s.response(ctx, "RemoveArtifact", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) SetSchema(ctx context.Context, params *tickets.SetSchemaParams) *api.Response {
|
||||
return response(s.database.SetTemplate(ctx, params.ID, params.Schema))
|
||||
i, err := s.database.SetTemplate(ctx, params.ID, params.Schema)
|
||||
return s.response(ctx, "SetSchema", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) AddComment(ctx context.Context, params *tickets.AddCommentParams) *api.Response {
|
||||
return response(s.database.AddComment(ctx, params.ID, params.Comment))
|
||||
i, err := s.database.AddComment(ctx, params.ID, params.Comment)
|
||||
return s.response(ctx, "AddComment", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) RemoveComment(ctx context.Context, params *tickets.RemoveCommentParams) *api.Response {
|
||||
return response(s.database.RemoveComment(ctx, params.ID, params.CommentID))
|
||||
i, err := s.database.RemoveComment(ctx, params.ID, params.CommentID)
|
||||
return s.response(ctx, "RemoveComment", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) LinkTicket(ctx context.Context, params *tickets.LinkTicketParams) *api.Response {
|
||||
err := s.database.RelatedCreate(ctx, params.ID, params.LinkedID)
|
||||
if err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "LinkTicket", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
return s.GetTicket(ctx, &tickets.GetTicketParams{ID: params.ID})
|
||||
i, err := s.database.TicketGet(ctx, params.ID)
|
||||
return s.response(ctx, "LinkTicket", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) UnlinkTicket(ctx context.Context, params *tickets.UnlinkTicketParams) *api.Response {
|
||||
err := s.database.RelatedRemove(ctx, params.ID, params.LinkedID)
|
||||
if err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "UnlinkTicket", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
return s.GetTicket(ctx, &tickets.GetTicketParams{ID: params.ID})
|
||||
i, err := s.database.TicketGet(ctx, params.ID)
|
||||
return s.response(ctx, "UnlinkTicket", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) SetReferences(ctx context.Context, params *tickets.SetReferencesParams) *api.Response {
|
||||
return response(s.database.SetReferences(ctx, params.ID, params.References))
|
||||
i, err := s.database.SetReferences(ctx, params.ID, params.References)
|
||||
return s.response(ctx, "SetReferences", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) LinkFiles(ctx context.Context, params *tickets.LinkFilesParams) *api.Response {
|
||||
return response(s.database.LinkFiles(ctx, params.ID, params.Files))
|
||||
i, err := s.database.LinkFiles(ctx, params.ID, params.Files)
|
||||
return s.response(ctx, "LinkFiles", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) AddTicketPlaybook(ctx context.Context, params *tickets.AddTicketPlaybookParams) *api.Response {
|
||||
return response(s.database.AddTicketPlaybook(ctx, params.ID, params.Playbook))
|
||||
i, err := s.database.AddTicketPlaybook(ctx, params.ID, params.Playbook)
|
||||
return s.response(ctx, "AddTicketPlaybook", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) RemoveTicketPlaybook(ctx context.Context, params *tickets.RemoveTicketPlaybookParams) *api.Response {
|
||||
return response(s.database.RemoveTicketPlaybook(ctx, params.ID, params.PlaybookID))
|
||||
i, err := s.database.RemoveTicketPlaybook(ctx, params.ID, params.PlaybookID)
|
||||
return s.response(ctx, "RemoveTicketPlaybook", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) CompleteTask(ctx context.Context, params *tickets.CompleteTaskParams) *api.Response {
|
||||
return response(s.database.TaskComplete(ctx, params.ID, params.PlaybookID, params.TaskID, params.Data))
|
||||
i, err := s.database.TaskComplete(ctx, params.ID, params.PlaybookID, params.TaskID, params.Data)
|
||||
return s.response(ctx, "CompleteTask", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s Service) SetTask(ctx context.Context, params *tickets.SetTaskParams) *api.Response {
|
||||
return response(s.database.TaskUpdate(ctx, params.ID, params.PlaybookID, params.TaskID, params.Task))
|
||||
i, err := s.database.TaskUpdate(ctx, params.ID, params.PlaybookID, params.TaskID, params.Task)
|
||||
return s.response(ctx, "SetTask", ticketID(params.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) RunTask(ctx context.Context, params *tickets.RunTaskParams) *api.Response {
|
||||
return response(nil, s.database.TaskRun(ctx, params.ID, params.PlaybookID, params.TaskID))
|
||||
err := s.database.TaskRun(ctx, params.ID, params.PlaybookID, params.TaskID)
|
||||
return s.response(ctx, "RunTask", ticketID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
@@ -2,27 +2,40 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/tickettypes"
|
||||
)
|
||||
|
||||
func ticketTypeID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.TicketTypeCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) CreateTicketType(ctx context.Context, params *tickettypes.CreateTicketTypeParams) *api.Response {
|
||||
return response(s.database.TicketTypeCreate(ctx, params.Tickettype))
|
||||
ticketType, err := s.database.TicketTypeCreate(ctx, params.Tickettype)
|
||||
return s.response(ctx, "CreateTicketType", ticketTypeID(ticketType.ID), ticketType, err)
|
||||
}
|
||||
|
||||
func (s *Service) GetTicketType(ctx context.Context, params *tickettypes.GetTicketTypeParams) *api.Response {
|
||||
return response(s.database.TicketTypeGet(ctx, params.ID))
|
||||
ticketType, err := s.database.TicketTypeGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetTicketType", nil, ticketType, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateTicketType(ctx context.Context, params *tickettypes.UpdateTicketTypeParams) *api.Response {
|
||||
return response(s.database.TicketTypeUpdate(ctx, params.ID, params.Tickettype))
|
||||
ticketType, err := s.database.TicketTypeUpdate(ctx, params.ID, params.Tickettype)
|
||||
return s.response(ctx, "UpdateTicketType", ticketTypeID(ticketType.ID), ticketType, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteTicketType(ctx context.Context, params *tickettypes.DeleteTicketTypeParams) *api.Response {
|
||||
return response(nil, s.database.TicketTypeDelete(ctx, params.ID))
|
||||
err := s.database.TicketTypeDelete(ctx, params.ID)
|
||||
return s.response(ctx, "DeleteTicketType", ticketTypeID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListTicketTypes(ctx context.Context) *api.Response {
|
||||
return response(s.database.TicketTypeList(ctx))
|
||||
ticketTypes, err := s.database.TicketTypeList(ctx)
|
||||
return s.response(ctx, "ListTicketTypes", nil, ticketTypes, err)
|
||||
}
|
||||
|
||||
@@ -14,24 +14,24 @@ import (
|
||||
func (s *Service) GetSettings(ctx context.Context) *api.Response {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return response(nil, errors.New("no user in context"))
|
||||
return s.response(ctx, "GetSettings", nil, nil, errors.New("no user in context"))
|
||||
}
|
||||
|
||||
setting, err := s.database.UserDataGet(ctx, user.ID)
|
||||
if err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "GetSettings", nil, nil, err)
|
||||
}
|
||||
|
||||
settings := mergeSettings(s.settings, setting)
|
||||
|
||||
ticketTypeList, err := s.database.TicketTypeList(ctx)
|
||||
if err != nil {
|
||||
return response(nil, err)
|
||||
return s.response(ctx, "GetSettings", nil, nil, err)
|
||||
}
|
||||
|
||||
settings.TicketTypes = ticketTypeList
|
||||
|
||||
return response(settings, nil)
|
||||
return s.response(ctx, "GetSettings", nil, settings, nil)
|
||||
}
|
||||
|
||||
func mergeSettings(globalSettings *models.Settings, user *models.UserDataResponse) *models.Settings {
|
||||
|
||||
@@ -3,36 +3,49 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/users"
|
||||
)
|
||||
|
||||
func userID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.UserCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) GetUser(ctx context.Context, params *users.GetUserParams) *api.Response {
|
||||
return response(s.database.UserGet(ctx, params.ID))
|
||||
i, err := s.database.UserGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetUser", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListUsers(ctx context.Context) *api.Response {
|
||||
return response(s.database.UserList(ctx))
|
||||
i, err := s.database.UserList(ctx)
|
||||
return s.response(ctx, "ListUsers", nil, i, err)
|
||||
}
|
||||
|
||||
func (s *Service) CreateUser(ctx context.Context, params *users.CreateUserParams) *api.Response {
|
||||
return response(s.database.UserCreate(ctx, params.User))
|
||||
i, err := s.database.UserCreate(ctx, params.User)
|
||||
return s.response(ctx, "CreateUser", userID(i.ID), i, err)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteUser(ctx context.Context, params *users.DeleteUserParams) *api.Response {
|
||||
return response(nil, s.database.UserDelete(ctx, params.ID))
|
||||
err := s.database.UserDelete(ctx, params.ID)
|
||||
return s.response(ctx, "DeleteUser", userID(params.ID), nil, err)
|
||||
}
|
||||
|
||||
func (s *Service) CurrentUser(ctx context.Context) *api.Response {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return response(nil, errors.New("no user in context"))
|
||||
return s.response(ctx, "CurrentUser", nil, nil, errors.New("no user in context"))
|
||||
}
|
||||
return response(user, nil)
|
||||
return s.response(ctx, "CurrentUser", nil, user, nil)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateUser(ctx context.Context, params *users.UpdateUserParams) *api.Response {
|
||||
return response(s.database.UserUpdate(ctx, params.ID, params.User))
|
||||
i, err := s.database.UserUpdate(ctx, params.ID, params.User)
|
||||
return s.response(ctx, "UpdateUser", userID(i.ID), i, err)
|
||||
}
|
||||
|
||||
@@ -3,37 +3,50 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/restapi/operations/userdata"
|
||||
)
|
||||
|
||||
func userdataID(id string) []driver.DocumentID {
|
||||
return []driver.DocumentID{driver.DocumentID(fmt.Sprintf("%s/%s", database.UserDataCollectionName, id))}
|
||||
}
|
||||
|
||||
func (s *Service) GetUserData(ctx context.Context, params *userdata.GetUserDataParams) *api.Response {
|
||||
return response(s.database.UserDataGet(ctx, params.ID))
|
||||
userData, err := s.database.UserDataGet(ctx, params.ID)
|
||||
return s.response(ctx, "GetUserData", nil, userData, err)
|
||||
}
|
||||
|
||||
func (s *Service) ListUserData(ctx context.Context) *api.Response {
|
||||
return response(s.database.UserDataList(ctx))
|
||||
userData, err := s.database.UserDataList(ctx)
|
||||
return s.response(ctx, "ListUserData", nil, userData, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateUserData(ctx context.Context, params *userdata.UpdateUserDataParams) *api.Response {
|
||||
return response(s.database.UserDataUpdate(ctx, params.ID, params.Userdata))
|
||||
userData, err := s.database.UserDataUpdate(ctx, params.ID, params.Userdata)
|
||||
return s.response(ctx, "UpdateUserData", userdataID(userData.ID), userData, err)
|
||||
}
|
||||
|
||||
func (s *Service) CurrentUserData(ctx context.Context) *api.Response {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return response(nil, errors.New("no user in context"))
|
||||
return s.response(ctx, "CurrentUserData", userdataID(user.ID), nil, errors.New("no user in context"))
|
||||
}
|
||||
return s.GetUserData(ctx, &userdata.GetUserDataParams{ID: user.ID})
|
||||
userData, err := s.database.UserDataGet(ctx, user.ID)
|
||||
return s.response(ctx, "GetUserData", nil, userData, err)
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCurrentUserData(ctx context.Context, params *userdata.UpdateCurrentUserDataParams) *api.Response {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return response(nil, errors.New("no user in context"))
|
||||
return s.response(ctx, "UpdateCurrentUserData", userdataID(user.ID), nil, errors.New("no user in context"))
|
||||
}
|
||||
|
||||
return response(s.database.UserDataUpdate(ctx, user.ID, params.Userdata))
|
||||
userData, err := s.database.UserDataUpdate(ctx, user.ID, params.Userdata)
|
||||
return s.response(ctx, "UpdateCurrentUserData", userdataID(user.ID), userData, err)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ func SetupTestData(ctx context.Context, db *database.Database) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.LogCreate(ctx, "tickets/294511", "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim."); err != nil {
|
||||
if _, err := db.LogCreate(ctx, "manual", "tickets/294511", "Fail run account resist lend solve incident centre priority temperature. Cause change distribution examine location technique shape partner milk customer. Rail tea plate soil report cook railway interpretation breath action. Exercise dream accept park conclusion addition shoot assistance may answer. Gold writer link stop combine hear power name commitment operation. Determine lifespan support grow degree henry exclude detail set religion. Direct library policy convention chain retain discover ride walk student. Gather proposal select march aspect play noise avoid encourage employ. Assessment preserve transport combine wish influence income guess run stand. Charge limit crime ignore statement foundation study issue stop claim."); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -612,6 +612,12 @@ export interface LogEntry {
|
||||
* @memberof LogEntry
|
||||
*/
|
||||
reference: string;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof LogEntry
|
||||
*/
|
||||
type: string;
|
||||
}
|
||||
/**
|
||||
*
|
||||
@@ -2026,6 +2032,12 @@ export interface TicketWithTickets {
|
||||
* @memberof TicketWithTickets
|
||||
*/
|
||||
id: number;
|
||||
/**
|
||||
*
|
||||
* @type {Array<LogEntry>}
|
||||
* @memberof TicketWithTickets
|
||||
*/
|
||||
logs?: Array<LogEntry>;
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
|
||||
@@ -200,8 +200,15 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-textarea>
|
||||
<div v-for="(comment, id) in ticket.comments" :key="id" class="pb-2">
|
||||
<v-card elevation="0" color="cards">
|
||||
<div v-for="(comment, id) in logs(ticket)" :key="id" class="pb-2">
|
||||
<div v-if="'type' in comment && comment.message !== 'AddComment'" style="text-align: center">
|
||||
<span class="text--disabled" :title="comment.created">
|
||||
{{ comment.message }} ·
|
||||
<strong> {{ comment.creator }}</strong> ·
|
||||
{{ relDate(comment.created) }}
|
||||
</span>
|
||||
</div>
|
||||
<v-card v-else-if="!('type' in comment)" elevation="0" color="cards">
|
||||
<v-card-subtitle class="pb-0">
|
||||
<strong> {{ comment.creator }}</strong>
|
||||
<span class="text--disabled ml-3" :title="comment.created">
|
||||
@@ -791,7 +798,7 @@ import {
|
||||
Task,
|
||||
Type,
|
||||
TypeColorEnum,
|
||||
TaskResponse, PlaybookResponse, UserResponse, TaskTypeEnum
|
||||
TaskResponse, PlaybookResponse, UserResponse, TaskTypeEnum, TicketWithTickets,
|
||||
} from "../client";
|
||||
import {API} from "@/services/api";
|
||||
|
||||
@@ -1520,6 +1527,9 @@ export default Vue.extend({
|
||||
});
|
||||
}
|
||||
return relDate;
|
||||
},
|
||||
logs: function(ticket: TicketWithTickets) {
|
||||
return this.lodash.reverse(this.lodash.sortBy(this.lodash.union(ticket.comments, ticket.logs), ['created']))
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"net/http"
|
||||
"sync"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gobwas/ws"
|
||||
"github.com/gobwas/ws/wsutil"
|
||||
@@ -48,10 +47,10 @@ func handleWebSocket(catalystBus *bus.Bus) func(ctx *gin.Context) {
|
||||
broker := websocketBroker{clients: map[string]chan []byte{}}
|
||||
|
||||
// send all messages from bus to websocket
|
||||
err := catalystBus.SubscribeUpdate(func(ids []driver.DocumentID) {
|
||||
err := catalystBus.SubscribeDatabaseUpdate(func(msg *bus.DatabaseUpdateMsg) {
|
||||
b, err := json.Marshal(map[string]interface{}{
|
||||
"action": "update",
|
||||
"ids": ids,
|
||||
"ids": msg.IDs,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user