mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-08 00:02:49 +01:00
Compare commits
5 Commits
v0.13.8-rc
...
v0.13.8-rc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97d0cd3428 | ||
|
|
baba5b7a45 | ||
|
|
d1cf75ab79 | ||
|
|
38a89f2c94 | ||
|
|
8c36ea5243 |
@@ -16,8 +16,10 @@ dockers:
|
|||||||
dockerfile: docker/Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
image_templates:
|
image_templates:
|
||||||
- "ghcr.io/securitybrewery/catalyst:main"
|
- "ghcr.io/securitybrewery/catalyst:main"
|
||||||
- "ghcr.io/securitybrewery/catalyst:latest"
|
- "{{if not .Prerelease}}ghcr.io/securitybrewery/catalyst:latest{{end}}"
|
||||||
- "ghcr.io/securitybrewery/catalyst:{{.Tag}}"
|
- "ghcr.io/securitybrewery/catalyst:{{.Tag}}"
|
||||||
|
extra_files:
|
||||||
|
- docker/entrypoint.sh
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- format: tar.gz
|
- format: tar.gz
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -60,18 +60,16 @@ dev:
|
|||||||
@echo "Running..."
|
@echo "Running..."
|
||||||
rm -rf catalyst_data
|
rm -rf catalyst_data
|
||||||
go run . admin create admin@catalyst-soar.com 1234567890
|
go run . admin create admin@catalyst-soar.com 1234567890
|
||||||
go run . set-feature-flags dev
|
|
||||||
go run . fake-data
|
go run . fake-data
|
||||||
go run . serve
|
go run . serve --app-url http://localhost:8090 --flags dev
|
||||||
|
|
||||||
.PHONY: dev-10000
|
.PHONY: dev-10000
|
||||||
dev-10000:
|
dev-10000:
|
||||||
@echo "Running..."
|
@echo "Running..."
|
||||||
rm -rf catalyst_data
|
rm -rf catalyst_data
|
||||||
go run . admin create admin@catalyst-soar.com 1234567890
|
go run . admin create admin@catalyst-soar.com 1234567890
|
||||||
go run . set-feature-flags dev
|
|
||||||
go run . fake-data --users 100 --tickets 10000
|
go run . fake-data --users 100 --tickets 10000
|
||||||
go run . serve
|
go run . serve --app-url http://localhost:8090 --flags dev
|
||||||
|
|
||||||
.PHONY: serve-ui
|
.PHONY: serve-ui
|
||||||
serve-ui:
|
serve-ui:
|
||||||
|
|||||||
46
app/app.go
46
app/app.go
@@ -23,31 +23,47 @@ func App(dir string, test bool) (*pocketbase.PocketBase, error) {
|
|||||||
DefaultDataDir: dir,
|
DefaultDataDir: dir,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var appURL string
|
||||||
|
|
||||||
|
app.RootCmd.PersistentFlags().StringVar(&appURL, "app-url", "", "the app's URL")
|
||||||
|
|
||||||
|
var flags []string
|
||||||
|
|
||||||
|
app.RootCmd.PersistentFlags().StringSliceVar(&flags, "flags", nil, "feature flags")
|
||||||
|
|
||||||
|
_ = app.RootCmd.ParseFlags(os.Args[1:])
|
||||||
|
|
||||||
|
app.RootCmd.AddCommand(fakeDataCmd(app))
|
||||||
|
|
||||||
webhook.BindHooks(app)
|
webhook.BindHooks(app)
|
||||||
reaction.BindHooks(app, test)
|
reaction.BindHooks(app, test)
|
||||||
|
|
||||||
app.OnBeforeServe().Add(addRoutes())
|
|
||||||
|
|
||||||
app.OnAfterBootstrap().Add(func(e *core.BootstrapEvent) error {
|
app.OnAfterBootstrap().Add(func(e *core.BootstrapEvent) error {
|
||||||
|
if err := MigrateDBs(e.App); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := SetFlags(e.App, flags); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if HasFlag(e.App, "demo") {
|
if HasFlag(e.App, "demo") {
|
||||||
bindDemoHooks(e.App)
|
bindDemoHooks(e.App)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if appURL != "" {
|
||||||
|
s := e.App.Settings()
|
||||||
|
s.Meta.AppUrl = appURL
|
||||||
|
|
||||||
|
if err := e.App.Dao().SaveSettings(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return e.App.RefreshSettings()
|
||||||
})
|
})
|
||||||
|
|
||||||
// Register additional commands
|
app.OnBeforeServe().Add(addRoutes())
|
||||||
app.RootCmd.AddCommand(fakeDataCmd(app))
|
|
||||||
app.RootCmd.AddCommand(setFeatureFlagsCmd(app))
|
|
||||||
app.RootCmd.AddCommand(setAppURL(app))
|
|
||||||
|
|
||||||
if err := app.Bootstrap(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := MigrateDBs(app); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return app, nil
|
return app, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,8 @@ func fakeDataCmd(app core.App) *cobra.Command {
|
|||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "fake-data",
|
Use: "fake-data",
|
||||||
Run: func(_ *cobra.Command, _ []string) {
|
RunE: func(_ *cobra.Command, _ []string) error {
|
||||||
if err := fakedata.Generate(app, userCount, ticketCount); err != nil {
|
return fakedata.Generate(app, userCount, ticketCount)
|
||||||
app.Logger().Error(err.Error())
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
33
app/flags.go
33
app/flags.go
@@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
"github.com/spf13/cobra"
|
|
||||||
|
|
||||||
"github.com/SecurityBrewery/catalyst/migrations"
|
"github.com/SecurityBrewery/catalyst/migrations"
|
||||||
)
|
)
|
||||||
@@ -85,35 +84,3 @@ func SetFlags(app core.App, args []string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setFeatureFlagsCmd(app core.App) *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "set-feature-flags",
|
|
||||||
Run: func(_ *cobra.Command, args []string) {
|
|
||||||
if err := SetFlags(app, args); err != nil {
|
|
||||||
app.Logger().Error(err.Error())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setAppURL(app core.App) *cobra.Command {
|
|
||||||
return &cobra.Command{
|
|
||||||
Use: "set-app-url",
|
|
||||||
Run: func(_ *cobra.Command, args []string) {
|
|
||||||
if len(args) != 1 {
|
|
||||||
app.Logger().Error("missing app url")
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
settings := app.Settings()
|
|
||||||
|
|
||||||
settings.Meta.AppUrl = args[0]
|
|
||||||
|
|
||||||
if err := app.Dao().SaveSettings(settings); err != nil {
|
|
||||||
app.Logger().Error(err.Error())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ VOLUME /usr/local/bin/catalyst_data
|
|||||||
HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
|
HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
|
||||||
CMD curl -f http://localhost:8080/health || exit 1
|
CMD curl -f http://localhost:8080/health || exit 1
|
||||||
|
|
||||||
CMD ["/usr/local/bin/catalyst", "serve", "--http", "0.0.0.0:8080"]
|
COPY docker/entrypoint.sh /entrypoint.sh
|
||||||
|
|
||||||
|
CMD ["/entrypoint.sh"]
|
||||||
15
docker/entrypoint.sh
Normal file
15
docker/entrypoint.sh
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Set the flags
|
||||||
|
FLAGS=""
|
||||||
|
if [ -n "$CATALYST_FLAGS" ]; then
|
||||||
|
FLAGS="$CATALYST_FLAGS"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set the app url
|
||||||
|
APP_URL=""
|
||||||
|
if [ -n "$CATALYST_APP_URL" ]; then
|
||||||
|
APP_URL="$CATALYST_APP_URL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/local/bin/catalyst serve --http 0.0.0.0:8080 --flags "$FLAGS" --app-url "$APP_URL"
|
||||||
@@ -248,6 +248,28 @@ func linkRecords(dao *daos.Dao, created time.Time, record *models.Record) []*mod
|
|||||||
return records
|
return records
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createTicketPy = `import sys
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import os
|
||||||
|
|
||||||
|
from pocketbase import PocketBase
|
||||||
|
|
||||||
|
# Connect to the PocketBase server
|
||||||
|
client = PocketBase(os.environ["CATALYST_APP_URL"])
|
||||||
|
client.auth_store.save(token=os.environ["CATALYST_TOKEN"])
|
||||||
|
|
||||||
|
newtickets = client.collection("tickets").get_list(1, 200, {"filter": 'name = "New Ticket"'})
|
||||||
|
for ticket in newtickets.items:
|
||||||
|
client.collection("tickets").delete(ticket.id)
|
||||||
|
|
||||||
|
# Create a new ticket
|
||||||
|
client.collection("tickets").create({
|
||||||
|
"name": "New Ticket",
|
||||||
|
"type": "alert",
|
||||||
|
"open": True,
|
||||||
|
})`
|
||||||
|
|
||||||
const alertIngestPy = `import sys
|
const alertIngestPy = `import sys
|
||||||
import json
|
import json
|
||||||
import random
|
import random
|
||||||
@@ -294,8 +316,9 @@ client.collection("tickets").update(ticket["record"]["id"], {
|
|||||||
})`
|
})`
|
||||||
|
|
||||||
const (
|
const (
|
||||||
triggerWebhook = `{"token":"1234567890","path":"webhook"}`
|
triggerSchedule = `{"expression":"12 * * * *"}`
|
||||||
triggerHook = `{"collections":["tickets"],"events":["create"]}`
|
triggerWebhook = `{"token":"1234567890","path":"webhook"}`
|
||||||
|
triggerHook = `{"collections":["tickets"],"events":["create"]}`
|
||||||
)
|
)
|
||||||
|
|
||||||
func reactionRecords(dao *daos.Dao) []*models.Record {
|
func reactionRecords(dao *daos.Dao) []*models.Record {
|
||||||
@@ -306,6 +329,24 @@ func reactionRecords(dao *daos.Dao) []*models.Record {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
createTicketActionData, err := json.Marshal(map[string]interface{}{
|
||||||
|
"requirements": "pocketbase",
|
||||||
|
"script": createTicketPy,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
record := models.NewRecord(collection)
|
||||||
|
record.SetId("w_" + security.PseudorandomString(10))
|
||||||
|
record.Set("name", "Create New Ticket")
|
||||||
|
record.Set("trigger", "schedule")
|
||||||
|
record.Set("triggerdata", triggerSchedule)
|
||||||
|
record.Set("action", "python")
|
||||||
|
record.Set("actiondata", string(createTicketActionData))
|
||||||
|
|
||||||
|
records = append(records, record)
|
||||||
|
|
||||||
alertIngestActionData, err := json.Marshal(map[string]interface{}{
|
alertIngestActionData, err := json.Marshal(map[string]interface{}{
|
||||||
"requirements": "pocketbase",
|
"requirements": "pocketbase",
|
||||||
"script": alertIngestPy,
|
"script": alertIngestPy,
|
||||||
@@ -314,7 +355,7 @@ func reactionRecords(dao *daos.Dao) []*models.Record {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
record := models.NewRecord(collection)
|
record = models.NewRecord(collection)
|
||||||
record.SetId("w_" + security.PseudorandomString(10))
|
record.SetId("w_" + security.PseudorandomString(10))
|
||||||
record.Set("name", "Alert Ingest Webhook")
|
record.Set("name", "Alert Ingest Webhook")
|
||||||
record.Set("trigger", "webhook")
|
record.Set("trigger", "webhook")
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ func App(t *testing.T) (*pocketbase.PocketBase, *Counter, func()) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := baseApp.Bootstrap(); err != nil {
|
||||||
|
t.Fatal(fmt.Errorf("failed to bootstrap: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
baseApp.Settings().Logs.MaxDays = 0
|
baseApp.Settings().Logs.MaxDays = 0
|
||||||
|
|
||||||
defaultTestData(t, baseApp)
|
defaultTestData(t, baseApp)
|
||||||
|
|||||||
Reference in New Issue
Block a user