mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2026-03-28 13:32:51 +01:00
refactor: remove pocketbase (#1138)
This commit is contained in:
222
testing/api_comment_test.go
Normal file
222
testing/api_comment_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestCommentsCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListComments",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/comments?ticket=test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateComment",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/comments",
|
||||
Body: s(map[string]any{
|
||||
"author": "u_bob_analyst",
|
||||
"message": "new",
|
||||
"ticket": "test-ticket",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetComment",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/comments/c_test_comment",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"c_test_comment"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"c_test_comment"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateComment",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/comments/c_test_comment",
|
||||
Body: s(map[string]any{"message": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"c_test_comment"`,
|
||||
`"message":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"c_test_comment"`,
|
||||
`"message":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteComment",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/comments/c_test_comment",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
61
testing/api_feature_test.go
Normal file
61
testing/api_feature_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestFeaturesConfig(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "Config",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/config",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "NoAuth",
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
151
testing/api_file_test.go
Normal file
151
testing/api_file_test.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestFilesCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListFiles",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/files?ticket=test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{"X-Total-Count": "1"},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{"X-Total-Count": "1"},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateFile",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/files",
|
||||
Body: s(map[string]any{
|
||||
"ticket": "test-ticket",
|
||||
"name": "new.txt",
|
||||
"size": 3,
|
||||
"blob": "data:text/plain;base64,bmV3",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"ticket":"test-ticket"`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetFile",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/files/b_test_file",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"id":"b_test_file"`},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"id":"b_test_file"`},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteFile",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/files/b_test_file",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
222
testing/api_link_test.go
Normal file
222
testing/api_link_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestLinksCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListLinks",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/links?ticket=test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateLink",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/links",
|
||||
Body: s(map[string]any{
|
||||
"ticket": "test-ticket",
|
||||
"name": "new",
|
||||
"url": "https://example.com/new",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetLink",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/links/l_test_link",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"l_test_link"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"l_test_link"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateLink",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/links/l_test_link",
|
||||
Body: s(map[string]any{"name": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"l_test_link"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"l_test_link"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteLink",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/links/l_test_link",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@ package testing
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestReactionsCollection(t *testing.T) {
|
||||
@@ -10,41 +12,37 @@ func TestReactionsCollection(t *testing.T) {
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "ListReactions",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/collections/reactions/records",
|
||||
URL: "/api/reactions",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"totalItems":0`,
|
||||
`"items":[]`,
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"totalItems":3`,
|
||||
`"id":"r_reaction"`,
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
NotExpectedContent: []string{
|
||||
`"items":[]`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"totalItems":3`,
|
||||
`"id":"r_reaction"`,
|
||||
`"id":"r-test-webhook"`,
|
||||
},
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "3",
|
||||
},
|
||||
NotExpectedContent: []string{
|
||||
`"items":[]`,
|
||||
@@ -54,11 +52,11 @@ func TestReactionsCollection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateReaction",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/collections/reactions/records",
|
||||
URL: "/api/reactions",
|
||||
Body: s(map[string]any{
|
||||
"name": "test",
|
||||
"trigger": "webhook",
|
||||
@@ -67,34 +65,25 @@ func TestReactionsCollection(t *testing.T) {
|
||||
"actiondata": map[string]any{"script": "print('Hello, World!')"},
|
||||
}),
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusBadRequest,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"message":"Failed to create record."`,
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"name":"test"`,
|
||||
},
|
||||
NotExpectedContent: []string{
|
||||
`"items":[]`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterCreate": 1,
|
||||
"OnModelBeforeCreate": 1,
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"name":"test"`,
|
||||
@@ -103,8 +92,8 @@ func TestReactionsCollection(t *testing.T) {
|
||||
`"items":[]`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterCreate": 1,
|
||||
"OnModelBeforeCreate": 1,
|
||||
// "OnModelAfterCreate": 1,
|
||||
// "OnModelBeforeCreate": 1,
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
@@ -112,82 +101,74 @@ func TestReactionsCollection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "GetReaction",
|
||||
Method: http.MethodGet,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/collections/reactions/records/r_reaction",
|
||||
URL: "/api/reactions/r-test-webhook",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusNotFound,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"message":"The requested resource wasn't found."`,
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"id":"r_reaction"`,
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"r_reaction"`,
|
||||
`"id":"r-test-webhook"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateReaction",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/collections/reactions/records/r_reaction",
|
||||
URL: "/api/reactions/r-test-webhook",
|
||||
Body: s(map[string]any{"name": "update"}),
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusNotFound,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"message":"The requested resource wasn't found."`,
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"id":"r_reaction"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterUpdate": 1,
|
||||
"OnModelBeforeUpdate": 1,
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"r_reaction"`,
|
||||
`"id":"r-test-webhook"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterUpdate": 1,
|
||||
"OnModelBeforeUpdate": 1,
|
||||
// "OnModelAfterUpdate": 1,
|
||||
// "OnModelBeforeUpdate": 1,
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
@@ -195,37 +176,34 @@ func TestReactionsCollection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteReaction",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/collections/reactions/records/r_reaction",
|
||||
URL: "/api/reactions/r-test-webhook",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusNotFound,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"message":"The requested resource wasn't found."`,
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterDelete": 1,
|
||||
"OnModelBeforeDelete": 1,
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterDelete": 1,
|
||||
"OnModelBeforeDelete": 1,
|
||||
// "OnModelAfterDelete": 1,
|
||||
// "OnModelBeforeDelete": 1,
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
@@ -233,6 +211,7 @@ func TestReactionsCollection(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -3,6 +3,8 @@ package testing
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func Test_Routes(t *testing.T) {
|
||||
@@ -10,56 +12,56 @@ func Test_Routes(t *testing.T) {
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "Root",
|
||||
Method: http.MethodGet,
|
||||
URL: "/",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusFound,
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusFound,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "Config",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/config",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
Name: "NoAuth",
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":[]`,
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":[]`,
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: adminEmail,
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"flags":[]`,
|
||||
`"flags":`,
|
||||
},
|
||||
},
|
||||
},
|
||||
223
testing/api_task_test.go
Normal file
223
testing/api_task_test.go
Normal file
@@ -0,0 +1,223 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestTasksCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListTasks",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/tasks?ticket=test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateTask",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/tasks",
|
||||
Body: s(map[string]any{
|
||||
"ticket": "test-ticket",
|
||||
"name": "new",
|
||||
"open": true,
|
||||
"owner": "u_bob_analyst",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetTask",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/tasks/k_test_task",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"k_test_task"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"k_test_task"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateTask",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/tasks/k_test_task",
|
||||
Body: s(map[string]any{"name": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"k_test_task"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"k_test_task"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteTask",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/tasks/k_test_task",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
134
testing/api_test.go
Normal file
134
testing/api_test.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
type request struct {
|
||||
Method string
|
||||
URL string
|
||||
Body []byte
|
||||
}
|
||||
|
||||
func TestAPI(t *testing.T) { //nolint:cyclop
|
||||
t.Parallel()
|
||||
|
||||
requests := [][]request{
|
||||
{
|
||||
{"GET", "/ui/login", nil},
|
||||
{"GET", "/api/config", nil},
|
||||
},
|
||||
{
|
||||
{"POST", "/auth/local/login", []byte(`{"email":"admin@catalyst-soar.com","password":"password123"}`)},
|
||||
},
|
||||
{
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/api/sidebar", nil},
|
||||
{"GET", "/ui/groups", nil},
|
||||
{"GET", "/api/tickets", nil},
|
||||
{"GET", "/api/tickets", nil},
|
||||
{"GET", "/api/tasks", nil},
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/api/sidebar", nil},
|
||||
{"GET", "/api/groups", nil},
|
||||
{"GET", "/api/config", nil},
|
||||
},
|
||||
{
|
||||
{"POST", "/api/groups", []byte(`{"name":"playwright-59537c9d-772f-45f0-a8f0-bb99656fa7ed","permissions":["ticket:read"]}`)},
|
||||
},
|
||||
{
|
||||
{"GET", "/api/groups/ID", nil},
|
||||
{"GET", "/api/groups", nil},
|
||||
{"GET", "/api/config", nil},
|
||||
},
|
||||
{
|
||||
{"GET", "/api/groups/ID/parents", nil},
|
||||
{"GET", "/api/groups/ID/permissions", nil},
|
||||
{"GET", "/api/groups/ID/children", nil},
|
||||
{"GET", "/api/groups/ID/users", nil},
|
||||
{"GET", "/api/users", nil},
|
||||
},
|
||||
{
|
||||
{"GET", "/ui/login", nil},
|
||||
{"GET", "/api/config", nil},
|
||||
},
|
||||
{
|
||||
{"POST", "/auth/local/login", []byte(`{"email":"admin@catalyst-soar.com","password":"password123"}`)},
|
||||
},
|
||||
{
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/api/sidebar", nil},
|
||||
{"GET", "/ui/groups", nil},
|
||||
{"GET", "/api/tickets", nil},
|
||||
{"GET", "/api/tickets", nil},
|
||||
{"GET", "/api/tasks", nil},
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/auth/user", nil},
|
||||
{"GET", "/api/sidebar", nil},
|
||||
{"GET", "/api/groups", nil},
|
||||
{"GET", "/api/config", nil},
|
||||
},
|
||||
{
|
||||
{"POST", "/api/groups", []byte(`{"name":"playwright-c9bdcbf8-6aba-4974-9c12-f77fa7f15b34","permissions":["ticket:read"]}`)},
|
||||
},
|
||||
}
|
||||
|
||||
app, cleanup, _ := App(t)
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
id, token := "", ""
|
||||
|
||||
for _, batch := range requests {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(len(batch))
|
||||
|
||||
for _, req := range batch {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
url := req.URL
|
||||
if strings.Contains(url, "ID") {
|
||||
url = strings.ReplaceAll(url, "ID", id)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(t.Context(), time.Second*10)
|
||||
defer cancel()
|
||||
|
||||
r, err := http.NewRequestWithContext(ctx, req.Method, url, bytes.NewReader(req.Body))
|
||||
assert.NoError(t, err)
|
||||
|
||||
if token != "" {
|
||||
r.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
app.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, 200, w.Code, "expected status code 200: %s for %s %s", w.Body.String(), req.Method, url)
|
||||
|
||||
if w.Code == 200 && req.Method == http.MethodPost && gjson.Get(w.Body.String(), "id").Exists() {
|
||||
id = gjson.Get(w.Body.String(), "id").String()
|
||||
}
|
||||
|
||||
if w.Code == 200 && req.Method == http.MethodPost && gjson.Get(w.Body.String(), "token").Exists() {
|
||||
token = gjson.Get(w.Body.String(), "token").String()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
226
testing/api_ticket_test.go
Normal file
226
testing/api_ticket_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestTicketsCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListTickets",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/tickets",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateTicket",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/tickets",
|
||||
Body: s(map[string]any{
|
||||
"name": "new",
|
||||
"type": "incident",
|
||||
"description": "test",
|
||||
"open": true,
|
||||
"owner": "u_bob_analyst",
|
||||
"resolution": "",
|
||||
"schema": map[string]any{},
|
||||
"state": map[string]any{},
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"name":"new"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"name":"new"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetTicket",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/tickets/test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateTicket",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/tickets/test-ticket",
|
||||
Body: s(map[string]any{"name": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-ticket"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-ticket"`,
|
||||
`"name":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteTicket",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/tickets/test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
222
testing/api_timeline_test.go
Normal file
222
testing/api_timeline_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestTimelineCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListTimeline",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/timeline?ticket=test-ticket",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "1",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateTimeline",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/timeline",
|
||||
Body: s(map[string]any{
|
||||
"ticket": "test-ticket",
|
||||
"message": "new",
|
||||
"time": "2023-01-01T00:00:00Z",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"ticket":"test-ticket"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetTimeline",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/timeline/h_test_timeline",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"h_test_timeline"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"h_test_timeline"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateTimeline",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/timeline/h_test_timeline",
|
||||
Body: s(map[string]any{"message": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"h_test_timeline"`,
|
||||
`"message":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"h_test_timeline"`,
|
||||
`"message":"update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteTimeline",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/timeline/h_test_timeline",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
213
testing/api_type_test.go
Normal file
213
testing/api_type_test.go
Normal file
@@ -0,0 +1,213 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestTypesCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListTypes",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/types",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "4",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{
|
||||
"X-Total-Count": "4",
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordsListRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateType",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/types",
|
||||
Body: s(map[string]any{
|
||||
"singular": "Example",
|
||||
"plural": "Examples",
|
||||
"icon": "Bug",
|
||||
"schema": map[string]any{},
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"singular":"Example"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetType",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/types/test-type",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-type"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-type"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateType",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/types/test-type",
|
||||
Body: s(map[string]any{"singular": "Update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"id":"test-type"`,
|
||||
`"singular":"Update"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteType",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/types/test-type",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"invalid bearer token"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{
|
||||
`"missing required scopes"`,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestWebhookReactions(t *testing.T) {
|
||||
@@ -21,13 +23,13 @@ func TestWebhookReactions(t *testing.T) {
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "TriggerWebhookReaction",
|
||||
Method: http.MethodGet,
|
||||
RequestHeaders: map[string]string{"Authorization": "Bearer 1234567890"},
|
||||
URL: "/reaction/test",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusOK,
|
||||
@@ -36,12 +38,12 @@ func TestWebhookReactions(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "TriggerWebhookReaction2",
|
||||
Method: http.MethodGet,
|
||||
URL: "/reaction/test2",
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusOK,
|
||||
@@ -78,16 +80,17 @@ func TestHookReactions(t *testing.T) {
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: BaseTest{
|
||||
baseTest: baseTest{
|
||||
Name: "TriggerHookReaction",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/collections/tickets/records",
|
||||
URL: "/api/tickets",
|
||||
Body: s(map[string]any{
|
||||
"type": "alert",
|
||||
"name": "test",
|
||||
}),
|
||||
},
|
||||
userTests: []UserTest{
|
||||
userTests: []userTest{
|
||||
// {
|
||||
// Name: "Unauthorized",
|
||||
// ExpectedStatus: http.StatusOK,
|
||||
@@ -95,15 +98,14 @@ func TestHookReactions(t *testing.T) {
|
||||
// },
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: analystEmail,
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{
|
||||
`"collectionName":"tickets"`,
|
||||
`"name":"test"`,
|
||||
},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnModelAfterCreate": 1,
|
||||
"OnModelBeforeCreate": 1,
|
||||
// "OnModelAfterCreate": 1,
|
||||
// "OnModelBeforeCreate": 1,
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
182
testing/api_webhook_test.go
Normal file
182
testing/api_webhook_test.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestWebhooksCollection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testSets := []catalystTest{
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "ListWebhooks",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/webhooks",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedHeaders: map[string]string{"X-Total-Count": "1"},
|
||||
ExpectedContent: []string{`"id":"w_test_webhook"`},
|
||||
ExpectedEvents: map[string]int{},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "CreateWebhook",
|
||||
Method: http.MethodPost,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/webhooks",
|
||||
Body: s(map[string]any{
|
||||
"name": "new",
|
||||
"collection": "tickets",
|
||||
"destination": "https://example.com/new",
|
||||
}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"name":"new"`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterCreateRequest": 1,
|
||||
"OnRecordBeforeCreateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "GetWebhook",
|
||||
Method: http.MethodGet,
|
||||
URL: "/api/webhooks/w_test_webhook",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"id":"w_test_webhook"`},
|
||||
ExpectedEvents: map[string]int{"OnRecordViewRequest": 1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "UpdateWebhook",
|
||||
Method: http.MethodPatch,
|
||||
RequestHeaders: map[string]string{"Content-Type": "application/json"},
|
||||
URL: "/api/webhooks/w_test_webhook",
|
||||
Body: s(map[string]any{"name": "update"}),
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusOK,
|
||||
ExpectedContent: []string{`"id":"w_test_webhook"`, `"name":"update"`},
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterUpdateRequest": 1,
|
||||
"OnRecordBeforeUpdateRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
baseTest: baseTest{
|
||||
Name: "DeleteWebhook",
|
||||
Method: http.MethodDelete,
|
||||
URL: "/api/webhooks/w_test_webhook",
|
||||
},
|
||||
userTests: []userTest{
|
||||
{
|
||||
Name: "Unauthorized",
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"invalid bearer token"`},
|
||||
},
|
||||
{
|
||||
Name: "Analyst",
|
||||
AuthRecord: data.AnalystEmail,
|
||||
ExpectedStatus: http.StatusUnauthorized,
|
||||
ExpectedContent: []string{`"missing required scopes"`},
|
||||
},
|
||||
{
|
||||
Name: "Admin",
|
||||
Admin: data.AdminEmail,
|
||||
ExpectedStatus: http.StatusNoContent,
|
||||
ExpectedEvents: map[string]int{
|
||||
"OnRecordAfterDeleteRequest": 1,
|
||||
"OnRecordBeforeDeleteRequest": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testSet := range testSets {
|
||||
t.Run(testSet.baseTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, userTest := range testSet.userTests {
|
||||
t.Run(userTest.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runMatrixTest(t, testSet.baseTest, userTest)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package testing
|
||||
|
||||
import "sync"
|
||||
|
||||
type Counter struct {
|
||||
mux sync.Mutex
|
||||
counts map[string]int
|
||||
}
|
||||
|
||||
func NewCounter() *Counter {
|
||||
return &Counter{
|
||||
counts: make(map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Counter) Increment(name string) {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
if _, ok := c.counts[name]; !ok {
|
||||
c.counts[name] = 0
|
||||
}
|
||||
|
||||
c.counts[name]++
|
||||
}
|
||||
|
||||
func (c *Counter) Count(name string) int {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
if _, ok := c.counts[name]; !ok {
|
||||
return 0
|
||||
}
|
||||
|
||||
return c.counts[name]
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCounter(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type args struct {
|
||||
name string
|
||||
repeat int
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want int
|
||||
}{
|
||||
{
|
||||
name: "Test Counter",
|
||||
args: args{name: "test", repeat: 5},
|
||||
want: 5,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := NewCounter()
|
||||
|
||||
for range tt.args.repeat {
|
||||
c.Increment(tt.args.name)
|
||||
}
|
||||
|
||||
assert.Equal(t, tt.want, c.Count(tt.args.name))
|
||||
})
|
||||
}
|
||||
}
|
||||
BIN
testing/data/v0.14.1/data.db
Normal file
BIN
testing/data/v0.14.1/data.db
Normal file
Binary file not shown.
@@ -1,29 +1,46 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type RecordingServer struct {
|
||||
server *echo.Echo
|
||||
server chi.Router
|
||||
|
||||
Entries []string
|
||||
}
|
||||
|
||||
func NewRecordingServer() *RecordingServer {
|
||||
e := echo.New()
|
||||
e := chi.NewRouter()
|
||||
|
||||
e.GET("/health", func(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, map[string]any{
|
||||
e.Get("/health", func(w http.ResponseWriter, _ *http.Request) {
|
||||
b, err := json.Marshal(map[string]any{
|
||||
"status": "ok",
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, "failed to marshal response", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
_, _ = w.Write(b)
|
||||
})
|
||||
e.Any("/*", func(c echo.Context) error {
|
||||
return c.JSON(http.StatusOK, map[string]any{
|
||||
e.HandleFunc("/*", func(w http.ResponseWriter, _ *http.Request) {
|
||||
b, err := json.Marshal(map[string]any{
|
||||
"test": true,
|
||||
})
|
||||
if err != nil {
|
||||
http.Error(w, "failed to marshal response", http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
|
||||
_, _ = w.Write(b)
|
||||
})
|
||||
|
||||
return &RecordingServer{
|
||||
|
||||
25
testing/test_all.sh
Executable file
25
testing/test_all.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
reset_catalyst_data() {
|
||||
if [ -d "catalyst_data" ]; then
|
||||
rm -rf catalyst_data
|
||||
fi
|
||||
mkdir -p catalyst_data
|
||||
}
|
||||
|
||||
# function to run playwright tests
|
||||
run_playwright_tests() {
|
||||
cd ui
|
||||
bun test:e2e
|
||||
cd ..
|
||||
}
|
||||
|
||||
run_upgradetest() {
|
||||
# iterate over all folders in ./testing/data
|
||||
for dir in ./testing/data/*/; do
|
||||
echo "Running tests with data from $dir"
|
||||
reset_catalyst_data
|
||||
cp "$dir"/data.db catalyst_data/data.db
|
||||
run_playwright_tests
|
||||
done
|
||||
}
|
||||
|
||||
run_upgradetest
|
||||
@@ -1,164 +1,47 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/tokens"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app"
|
||||
"github.com/SecurityBrewery/catalyst/migrations"
|
||||
"github.com/SecurityBrewery/catalyst/app/counter"
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
"github.com/SecurityBrewery/catalyst/app/hook"
|
||||
)
|
||||
|
||||
func App(t *testing.T) (*pocketbase.PocketBase, *Counter, func()) {
|
||||
func App(t *testing.T) (*app.App, func(), *counter.Counter) {
|
||||
t.Helper()
|
||||
|
||||
temp, err := os.MkdirTemp("", "catalyst_test_data")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
dir := t.TempDir()
|
||||
|
||||
baseApp, err := app.App(temp, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
catalyst, cleanup, err := app.New(t.Context(), dir)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := baseApp.Bootstrap(); err != nil {
|
||||
t.Fatal(fmt.Errorf("failed to bootstrap: %w", err))
|
||||
}
|
||||
data.DefaultTestData(t, dir, catalyst.Queries)
|
||||
|
||||
baseApp.Settings().Logs.MaxDays = 0
|
||||
|
||||
defaultTestData(t, baseApp)
|
||||
|
||||
counter := countEvents(baseApp)
|
||||
|
||||
return baseApp, counter, func() { _ = os.RemoveAll(temp) }
|
||||
return catalyst, cleanup, countEvents(catalyst.Hooks)
|
||||
}
|
||||
|
||||
func generateAdminToken(t *testing.T, baseApp core.App, email string) (string, error) {
|
||||
t.Helper()
|
||||
func countEvents(hooks *hook.Hooks) *counter.Counter {
|
||||
c := counter.NewCounter()
|
||||
|
||||
admin, err := baseApp.Dao().FindAdminByEmail(email)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find admin: %w", err)
|
||||
}
|
||||
|
||||
return tokens.NewAdminAuthToken(baseApp, admin)
|
||||
}
|
||||
|
||||
func generateRecordToken(t *testing.T, baseApp core.App, email string) (string, error) {
|
||||
t.Helper()
|
||||
|
||||
record, err := baseApp.Dao().FindAuthRecordByEmail(migrations.UserCollectionName, email)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to find record: %w", err)
|
||||
}
|
||||
|
||||
return tokens.NewRecordAuthToken(baseApp, record)
|
||||
}
|
||||
|
||||
func countEvents(t *pocketbase.PocketBase) *Counter {
|
||||
c := NewCounter()
|
||||
|
||||
t.OnBeforeApiError().Add(count[*core.ApiErrorEvent](c, "OnBeforeApiError"))
|
||||
t.OnBeforeApiError().Add(count[*core.ApiErrorEvent](c, "OnBeforeApiError"))
|
||||
t.OnAfterApiError().Add(count[*core.ApiErrorEvent](c, "OnAfterApiError"))
|
||||
t.OnModelBeforeCreate().Add(count[*core.ModelEvent](c, "OnModelBeforeCreate"))
|
||||
t.OnModelAfterCreate().Add(count[*core.ModelEvent](c, "OnModelAfterCreate"))
|
||||
t.OnModelBeforeUpdate().Add(count[*core.ModelEvent](c, "OnModelBeforeUpdate"))
|
||||
t.OnModelAfterUpdate().Add(count[*core.ModelEvent](c, "OnModelAfterUpdate"))
|
||||
t.OnModelBeforeDelete().Add(count[*core.ModelEvent](c, "OnModelBeforeDelete"))
|
||||
t.OnModelAfterDelete().Add(count[*core.ModelEvent](c, "OnModelAfterDelete"))
|
||||
t.OnRecordsListRequest().Add(count[*core.RecordsListEvent](c, "OnRecordsListRequest"))
|
||||
t.OnRecordViewRequest().Add(count[*core.RecordViewEvent](c, "OnRecordViewRequest"))
|
||||
t.OnRecordBeforeCreateRequest().Add(count[*core.RecordCreateEvent](c, "OnRecordBeforeCreateRequest"))
|
||||
t.OnRecordAfterCreateRequest().Add(count[*core.RecordCreateEvent](c, "OnRecordAfterCreateRequest"))
|
||||
t.OnRecordBeforeUpdateRequest().Add(count[*core.RecordUpdateEvent](c, "OnRecordBeforeUpdateRequest"))
|
||||
t.OnRecordAfterUpdateRequest().Add(count[*core.RecordUpdateEvent](c, "OnRecordAfterUpdateRequest"))
|
||||
t.OnRecordBeforeDeleteRequest().Add(count[*core.RecordDeleteEvent](c, "OnRecordBeforeDeleteRequest"))
|
||||
t.OnRecordAfterDeleteRequest().Add(count[*core.RecordDeleteEvent](c, "OnRecordAfterDeleteRequest"))
|
||||
t.OnRecordAuthRequest().Add(count[*core.RecordAuthEvent](c, "OnRecordAuthRequest"))
|
||||
t.OnRecordBeforeAuthWithPasswordRequest().Add(count[*core.RecordAuthWithPasswordEvent](c, "OnRecordBeforeAuthWithPasswordRequest"))
|
||||
t.OnRecordAfterAuthWithPasswordRequest().Add(count[*core.RecordAuthWithPasswordEvent](c, "OnRecordAfterAuthWithPasswordRequest"))
|
||||
t.OnRecordBeforeAuthWithOAuth2Request().Add(count[*core.RecordAuthWithOAuth2Event](c, "OnRecordBeforeAuthWithOAuth2Request"))
|
||||
t.OnRecordAfterAuthWithOAuth2Request().Add(count[*core.RecordAuthWithOAuth2Event](c, "OnRecordAfterAuthWithOAuth2Request"))
|
||||
t.OnRecordBeforeAuthRefreshRequest().Add(count[*core.RecordAuthRefreshEvent](c, "OnRecordBeforeAuthRefreshRequest"))
|
||||
t.OnRecordAfterAuthRefreshRequest().Add(count[*core.RecordAuthRefreshEvent](c, "OnRecordAfterAuthRefreshRequest"))
|
||||
t.OnRecordBeforeRequestPasswordResetRequest().Add(count[*core.RecordRequestPasswordResetEvent](c, "OnRecordBeforeRequestPasswordResetRequest"))
|
||||
t.OnRecordAfterRequestPasswordResetRequest().Add(count[*core.RecordRequestPasswordResetEvent](c, "OnRecordAfterRequestPasswordResetRequest"))
|
||||
t.OnRecordBeforeConfirmPasswordResetRequest().Add(count[*core.RecordConfirmPasswordResetEvent](c, "OnRecordBeforeConfirmPasswordResetRequest"))
|
||||
t.OnRecordAfterConfirmPasswordResetRequest().Add(count[*core.RecordConfirmPasswordResetEvent](c, "OnRecordAfterConfirmPasswordResetRequest"))
|
||||
t.OnRecordBeforeRequestVerificationRequest().Add(count[*core.RecordRequestVerificationEvent](c, "OnRecordBeforeRequestVerificationRequest"))
|
||||
t.OnRecordAfterRequestVerificationRequest().Add(count[*core.RecordRequestVerificationEvent](c, "OnRecordAfterRequestVerificationRequest"))
|
||||
t.OnRecordBeforeConfirmVerificationRequest().Add(count[*core.RecordConfirmVerificationEvent](c, "OnRecordBeforeConfirmVerificationRequest"))
|
||||
t.OnRecordAfterConfirmVerificationRequest().Add(count[*core.RecordConfirmVerificationEvent](c, "OnRecordAfterConfirmVerificationRequest"))
|
||||
t.OnRecordBeforeRequestEmailChangeRequest().Add(count[*core.RecordRequestEmailChangeEvent](c, "OnRecordBeforeRequestEmailChangeRequest"))
|
||||
t.OnRecordAfterRequestEmailChangeRequest().Add(count[*core.RecordRequestEmailChangeEvent](c, "OnRecordAfterRequestEmailChangeRequest"))
|
||||
t.OnRecordBeforeConfirmEmailChangeRequest().Add(count[*core.RecordConfirmEmailChangeEvent](c, "OnRecordBeforeConfirmEmailChangeRequest"))
|
||||
t.OnRecordAfterConfirmEmailChangeRequest().Add(count[*core.RecordConfirmEmailChangeEvent](c, "OnRecordAfterConfirmEmailChangeRequest"))
|
||||
t.OnRecordListExternalAuthsRequest().Add(count[*core.RecordListExternalAuthsEvent](c, "OnRecordListExternalAuthsRequest"))
|
||||
t.OnRecordBeforeUnlinkExternalAuthRequest().Add(count[*core.RecordUnlinkExternalAuthEvent](c, "OnRecordBeforeUnlinkExternalAuthRequest"))
|
||||
t.OnRecordAfterUnlinkExternalAuthRequest().Add(count[*core.RecordUnlinkExternalAuthEvent](c, "OnRecordAfterUnlinkExternalAuthRequest"))
|
||||
t.OnMailerBeforeAdminResetPasswordSend().Add(count[*core.MailerAdminEvent](c, "OnMailerBeforeAdminResetPasswordSend"))
|
||||
t.OnMailerAfterAdminResetPasswordSend().Add(count[*core.MailerAdminEvent](c, "OnMailerAfterAdminResetPasswordSend"))
|
||||
t.OnMailerBeforeRecordResetPasswordSend().Add(count[*core.MailerRecordEvent](c, "OnMailerBeforeRecordResetPasswordSend"))
|
||||
t.OnMailerAfterRecordResetPasswordSend().Add(count[*core.MailerRecordEvent](c, "OnMailerAfterRecordResetPasswordSend"))
|
||||
t.OnMailerBeforeRecordVerificationSend().Add(count[*core.MailerRecordEvent](c, "OnMailerBeforeRecordVerificationSend"))
|
||||
t.OnMailerAfterRecordVerificationSend().Add(count[*core.MailerRecordEvent](c, "OnMailerAfterRecordVerificationSend"))
|
||||
t.OnMailerBeforeRecordChangeEmailSend().Add(count[*core.MailerRecordEvent](c, "OnMailerBeforeRecordChangeEmailSend"))
|
||||
t.OnMailerAfterRecordChangeEmailSend().Add(count[*core.MailerRecordEvent](c, "OnMailerAfterRecordChangeEmailSend"))
|
||||
t.OnRealtimeConnectRequest().Add(count[*core.RealtimeConnectEvent](c, "OnRealtimeConnectRequest"))
|
||||
t.OnRealtimeDisconnectRequest().Add(count[*core.RealtimeDisconnectEvent](c, "OnRealtimeDisconnectRequest"))
|
||||
t.OnRealtimeBeforeMessageSend().Add(count[*core.RealtimeMessageEvent](c, "OnRealtimeBeforeMessageSend"))
|
||||
t.OnRealtimeAfterMessageSend().Add(count[*core.RealtimeMessageEvent](c, "OnRealtimeAfterMessageSend"))
|
||||
t.OnRealtimeBeforeSubscribeRequest().Add(count[*core.RealtimeSubscribeEvent](c, "OnRealtimeBeforeSubscribeRequest"))
|
||||
t.OnRealtimeAfterSubscribeRequest().Add(count[*core.RealtimeSubscribeEvent](c, "OnRealtimeAfterSubscribeRequest"))
|
||||
t.OnSettingsListRequest().Add(count[*core.SettingsListEvent](c, "OnSettingsListRequest"))
|
||||
t.OnSettingsBeforeUpdateRequest().Add(count[*core.SettingsUpdateEvent](c, "OnSettingsBeforeUpdateRequest"))
|
||||
t.OnSettingsAfterUpdateRequest().Add(count[*core.SettingsUpdateEvent](c, "OnSettingsAfterUpdateRequest"))
|
||||
t.OnCollectionsListRequest().Add(count[*core.CollectionsListEvent](c, "OnCollectionsListRequest"))
|
||||
t.OnCollectionViewRequest().Add(count[*core.CollectionViewEvent](c, "OnCollectionViewRequest"))
|
||||
t.OnCollectionBeforeCreateRequest().Add(count[*core.CollectionCreateEvent](c, "OnCollectionBeforeCreateRequest"))
|
||||
t.OnCollectionAfterCreateRequest().Add(count[*core.CollectionCreateEvent](c, "OnCollectionAfterCreateRequest"))
|
||||
t.OnCollectionBeforeUpdateRequest().Add(count[*core.CollectionUpdateEvent](c, "OnCollectionBeforeUpdateRequest"))
|
||||
t.OnCollectionAfterUpdateRequest().Add(count[*core.CollectionUpdateEvent](c, "OnCollectionAfterUpdateRequest"))
|
||||
t.OnCollectionBeforeDeleteRequest().Add(count[*core.CollectionDeleteEvent](c, "OnCollectionBeforeDeleteRequest"))
|
||||
t.OnCollectionAfterDeleteRequest().Add(count[*core.CollectionDeleteEvent](c, "OnCollectionAfterDeleteRequest"))
|
||||
t.OnCollectionsBeforeImportRequest().Add(count[*core.CollectionsImportEvent](c, "OnCollectionsBeforeImportRequest"))
|
||||
t.OnCollectionsAfterImportRequest().Add(count[*core.CollectionsImportEvent](c, "OnCollectionsAfterImportRequest"))
|
||||
t.OnAdminsListRequest().Add(count[*core.AdminsListEvent](c, "OnAdminsListRequest"))
|
||||
t.OnAdminViewRequest().Add(count[*core.AdminViewEvent](c, "OnAdminViewRequest"))
|
||||
t.OnAdminBeforeCreateRequest().Add(count[*core.AdminCreateEvent](c, "OnAdminBeforeCreateRequest"))
|
||||
t.OnAdminAfterCreateRequest().Add(count[*core.AdminCreateEvent](c, "OnAdminAfterCreateRequest"))
|
||||
t.OnAdminBeforeUpdateRequest().Add(count[*core.AdminUpdateEvent](c, "OnAdminBeforeUpdateRequest"))
|
||||
t.OnAdminAfterUpdateRequest().Add(count[*core.AdminUpdateEvent](c, "OnAdminAfterUpdateRequest"))
|
||||
t.OnAdminBeforeDeleteRequest().Add(count[*core.AdminDeleteEvent](c, "OnAdminBeforeDeleteRequest"))
|
||||
t.OnAdminAfterDeleteRequest().Add(count[*core.AdminDeleteEvent](c, "OnAdminAfterDeleteRequest"))
|
||||
t.OnAdminAuthRequest().Add(count[*core.AdminAuthEvent](c, "OnAdminAuthRequest"))
|
||||
t.OnAdminBeforeAuthWithPasswordRequest().Add(count[*core.AdminAuthWithPasswordEvent](c, "OnAdminBeforeAuthWithPasswordRequest"))
|
||||
t.OnAdminAfterAuthWithPasswordRequest().Add(count[*core.AdminAuthWithPasswordEvent](c, "OnAdminAfterAuthWithPasswordRequest"))
|
||||
t.OnAdminBeforeAuthRefreshRequest().Add(count[*core.AdminAuthRefreshEvent](c, "OnAdminBeforeAuthRefreshRequest"))
|
||||
t.OnAdminAfterAuthRefreshRequest().Add(count[*core.AdminAuthRefreshEvent](c, "OnAdminAfterAuthRefreshRequest"))
|
||||
t.OnAdminBeforeRequestPasswordResetRequest().Add(count[*core.AdminRequestPasswordResetEvent](c, "OnAdminBeforeRequestPasswordResetRequest"))
|
||||
t.OnAdminAfterRequestPasswordResetRequest().Add(count[*core.AdminRequestPasswordResetEvent](c, "OnAdminAfterRequestPasswordResetRequest"))
|
||||
t.OnAdminBeforeConfirmPasswordResetRequest().Add(count[*core.AdminConfirmPasswordResetEvent](c, "OnAdminBeforeConfirmPasswordResetRequest"))
|
||||
t.OnAdminAfterConfirmPasswordResetRequest().Add(count[*core.AdminConfirmPasswordResetEvent](c, "OnAdminAfterConfirmPasswordResetRequest"))
|
||||
t.OnFileDownloadRequest().Add(count[*core.FileDownloadEvent](c, "OnFileDownloadRequest"))
|
||||
t.OnFileBeforeTokenRequest().Add(count[*core.FileTokenEvent](c, "OnFileBeforeTokenRequest"))
|
||||
t.OnFileAfterTokenRequest().Add(count[*core.FileTokenEvent](c, "OnFileAfterTokenRequest"))
|
||||
t.OnFileAfterTokenRequest().Add(count[*core.FileTokenEvent](c, "OnFileAfterTokenRequest"))
|
||||
hooks.OnRecordsListRequest.Subscribe(count(c, "OnRecordsListRequest"))
|
||||
hooks.OnRecordViewRequest.Subscribe(count(c, "OnRecordViewRequest"))
|
||||
hooks.OnRecordBeforeCreateRequest.Subscribe(count(c, "OnRecordBeforeCreateRequest"))
|
||||
hooks.OnRecordAfterCreateRequest.Subscribe(count(c, "OnRecordAfterCreateRequest"))
|
||||
hooks.OnRecordBeforeUpdateRequest.Subscribe(count(c, "OnRecordBeforeUpdateRequest"))
|
||||
hooks.OnRecordAfterUpdateRequest.Subscribe(count(c, "OnRecordAfterUpdateRequest"))
|
||||
hooks.OnRecordBeforeDeleteRequest.Subscribe(count(c, "OnRecordBeforeDeleteRequest"))
|
||||
hooks.OnRecordAfterDeleteRequest.Subscribe(count(c, "OnRecordAfterDeleteRequest"))
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func count[T any](c *Counter, name string) func(_ T) error {
|
||||
return func(_ T) error {
|
||||
func count(c *counter.Counter, name string) func(ctx context.Context, table string, record any) {
|
||||
return func(_ context.Context, _ string, _ any) {
|
||||
c.Increment(name)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/migrations"
|
||||
)
|
||||
|
||||
const (
|
||||
adminEmail = "admin@catalyst-soar.com"
|
||||
analystEmail = "analyst@catalyst-soar.com"
|
||||
)
|
||||
|
||||
func defaultTestData(t *testing.T, app core.App) {
|
||||
t.Helper()
|
||||
|
||||
adminTestData(t, app)
|
||||
userTestData(t, app)
|
||||
ticketTestData(t, app)
|
||||
reactionTestData(t, app)
|
||||
}
|
||||
|
||||
func adminTestData(t *testing.T, app core.App) {
|
||||
t.Helper()
|
||||
|
||||
admin := &models.Admin{Email: adminEmail}
|
||||
|
||||
if err := admin.SetPassword("password"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := app.Dao().SaveAdmin(admin); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func userTestData(t *testing.T, app core.App) {
|
||||
t.Helper()
|
||||
|
||||
collection, err := app.Dao().FindCollectionByNameOrId(migrations.UserCollectionName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record := models.NewRecord(collection)
|
||||
record.SetId("u_bob_analyst")
|
||||
_ = record.SetUsername("u_bob_analyst")
|
||||
_ = record.SetPassword("password")
|
||||
record.Set("name", "Bob Analyst")
|
||||
record.Set("email", analystEmail)
|
||||
_ = record.SetVerified(true)
|
||||
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ticketTestData(t *testing.T, app core.App) {
|
||||
t.Helper()
|
||||
|
||||
collection, err := app.Dao().FindCollectionByNameOrId(migrations.TicketCollectionName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record := models.NewRecord(collection)
|
||||
record.SetId("t_test")
|
||||
|
||||
record.Set("name", "Test Ticket")
|
||||
record.Set("type", "incident")
|
||||
record.Set("description", "This is a test ticket.")
|
||||
record.Set("open", true)
|
||||
record.Set("schema", `{"type":"object","properties":{"tlp":{"title":"TLP","type":"string"}}}`)
|
||||
record.Set("state", `{"tlp":"AMBER"}`)
|
||||
record.Set("owner", "u_bob_analyst")
|
||||
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func reactionTestData(t *testing.T, app core.App) {
|
||||
t.Helper()
|
||||
|
||||
collection, err := app.Dao().FindCollectionByNameOrId(migrations.ReactionCollectionName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record := models.NewRecord(collection)
|
||||
record.SetId("r_reaction")
|
||||
record.Set("name", "Reaction")
|
||||
record.Set("trigger", "webhook")
|
||||
record.Set("triggerdata", `{"token":"1234567890","path":"test"}`)
|
||||
record.Set("action", "python")
|
||||
record.Set("actiondata", `{"requirements":"requests","script":"print('Hello, World!')"}`)
|
||||
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record = models.NewRecord(collection)
|
||||
record.SetId("r_reaction_webhook")
|
||||
record.Set("name", "Reaction")
|
||||
record.Set("trigger", "webhook")
|
||||
record.Set("triggerdata", `{"path":"test2"}`)
|
||||
record.Set("action", "webhook")
|
||||
record.Set("actiondata", `{"headers":{"Content-Type":"application/json"},"url":"http://127.0.0.1:12345/webhook"}`)
|
||||
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
record = models.NewRecord(collection)
|
||||
record.SetId("r_reaction_hook")
|
||||
record.Set("name", "Hook")
|
||||
record.Set("trigger", "hook")
|
||||
record.Set("triggerdata", `{"collections":["tickets"],"events":["create"]}`)
|
||||
record.Set("action", "python")
|
||||
record.Set("actiondata", `{"requirements":"requests","script":"import requests\nrequests.post('http://127.0.0.1:12346/test', json={'test':True})"}`)
|
||||
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,17 @@ package testing
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/auth"
|
||||
)
|
||||
|
||||
type BaseTest struct {
|
||||
type baseTest struct {
|
||||
Name string
|
||||
Method string
|
||||
RequestHeaders map[string]string
|
||||
@@ -21,36 +21,28 @@ type BaseTest struct {
|
||||
Body string
|
||||
}
|
||||
|
||||
type UserTest struct {
|
||||
type userTest struct {
|
||||
Name string
|
||||
AuthRecord string
|
||||
Admin string
|
||||
ExpectedStatus int
|
||||
ExpectedHeaders map[string]string
|
||||
ExpectedContent []string
|
||||
NotExpectedContent []string
|
||||
ExpectedEvents map[string]int
|
||||
}
|
||||
|
||||
type catalystTest struct {
|
||||
baseTest BaseTest
|
||||
userTests []UserTest
|
||||
baseTest baseTest
|
||||
userTests []userTest
|
||||
}
|
||||
|
||||
func runMatrixTest(t *testing.T, baseTest BaseTest, userTest UserTest) {
|
||||
func runMatrixTest(t *testing.T, baseTest baseTest, userTest userTest) {
|
||||
t.Helper()
|
||||
|
||||
baseApp, counter, baseAppCleanup := App(t)
|
||||
defer baseAppCleanup()
|
||||
baseApp, cleanup, counter := App(t)
|
||||
|
||||
server, err := apis.InitApi(baseApp)
|
||||
require.NoError(t, err)
|
||||
|
||||
if err := baseApp.OnBeforeServe().Trigger(&core.ServeEvent{
|
||||
App: baseApp,
|
||||
Router: server,
|
||||
}); err != nil {
|
||||
t.Fatal(fmt.Errorf("failed to trigger OnBeforeServe: %w", err))
|
||||
}
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
body := bytes.NewBufferString(baseTest.Body)
|
||||
@@ -61,26 +53,42 @@ func runMatrixTest(t *testing.T, baseTest BaseTest, userTest UserTest) {
|
||||
}
|
||||
|
||||
if userTest.AuthRecord != "" {
|
||||
token, err := generateRecordToken(t, baseApp, userTest.AuthRecord)
|
||||
user, err := baseApp.Queries.UserByEmail(t.Context(), &userTest.AuthRecord)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", token)
|
||||
permissions, err := baseApp.Queries.ListUserPermissions(t.Context(), user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
loginToken, err := auth.CreateAccessToken(t.Context(), &user, permissions, time.Hour, baseApp.Queries)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+loginToken)
|
||||
}
|
||||
|
||||
if userTest.Admin != "" {
|
||||
token, err := generateAdminToken(t, baseApp, userTest.Admin)
|
||||
user, err := baseApp.Queries.UserByEmail(t.Context(), &userTest.Admin)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", token)
|
||||
permissions, err := baseApp.Queries.ListUserPermissions(t.Context(), user.ID)
|
||||
require.NoError(t, err)
|
||||
|
||||
loginToken, err := auth.CreateAccessToken(t.Context(), &user, permissions, time.Hour, baseApp.Queries)
|
||||
require.NoError(t, err)
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+loginToken)
|
||||
}
|
||||
|
||||
server.ServeHTTP(recorder, req)
|
||||
baseApp.ServeHTTP(recorder, req)
|
||||
|
||||
res := recorder.Result()
|
||||
defer res.Body.Close()
|
||||
|
||||
assert.Equal(t, userTest.ExpectedStatus, res.StatusCode)
|
||||
|
||||
for k, v := range userTest.ExpectedHeaders {
|
||||
assert.Equal(t, v, res.Header.Get(k))
|
||||
}
|
||||
|
||||
for _, expectedContent := range userTest.ExpectedContent {
|
||||
assert.Contains(t, recorder.Body.String(), expectedContent)
|
||||
}
|
||||
@@ -90,7 +98,7 @@ func runMatrixTest(t *testing.T, baseTest BaseTest, userTest UserTest) {
|
||||
}
|
||||
|
||||
for event, count := range userTest.ExpectedEvents {
|
||||
assert.Equal(t, count, counter.Count(event))
|
||||
assert.Equalf(t, count, counter.Count(event), "expected %d events for %s, got %d", count, event, counter.Count(event))
|
||||
}
|
||||
}
|
||||
|
||||
67
testing/upgrade_test.go
Normal file
67
testing/upgrade_test.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app"
|
||||
)
|
||||
|
||||
func TestUpgrades(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dirEntries, err := os.ReadDir("data")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, entry := range dirEntries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(entry.Name(), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, err := copyDatabase(t, entry.Name())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
pb, cleanup, err := app.New(t.Context(), db)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
ValidateUpgradeTestData(t, pb.Queries)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func copyDatabase(t *testing.T, directory string) (string, error) {
|
||||
t.Helper()
|
||||
|
||||
dest := t.TempDir()
|
||||
|
||||
dstDB, err := os.Create(filepath.Join(dest, "data.db"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer dstDB.Close()
|
||||
|
||||
srcDB, err := os.Open(filepath.Join("data", directory, "data.db"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer srcDB.Close()
|
||||
|
||||
if _, err := dstDB.ReadFrom(srcDB); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return dest, nil
|
||||
}
|
||||
21
testing/upgradetest_test.go
Normal file
21
testing/upgradetest_test.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
)
|
||||
|
||||
func TestUpgradeTestData(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
app, cleanup, _ := App(t)
|
||||
|
||||
t.Cleanup(cleanup)
|
||||
|
||||
require.NoError(t, data.GenerateUpgradeTestData(t.Context(), app.Queries))
|
||||
|
||||
ValidateUpgradeTestData(t, app.Queries)
|
||||
}
|
||||
99
testing/validate.go
Normal file
99
testing/validate.go
Normal file
@@ -0,0 +1,99 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tidwall/gjson"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/app/data"
|
||||
"github.com/SecurityBrewery/catalyst/app/database/sqlc"
|
||||
)
|
||||
|
||||
func ValidateUpgradeTestData(t *testing.T, queries *sqlc.Queries) {
|
||||
t.Helper()
|
||||
|
||||
// users
|
||||
userRecord, err := queries.UserByUserName(t.Context(), "u_test")
|
||||
require.NoError(t, err, "failed to find user by username")
|
||||
|
||||
assert.Equal(t, "u_test", userRecord.ID, "user ID does not match expected value")
|
||||
assert.Equal(t, "u_test", userRecord.Username, "username does not match expected value")
|
||||
assert.Equal(t, "Test User", *userRecord.Name, "name does not match expected value")
|
||||
assert.Equal(t, "user@catalyst-soar.com", *userRecord.Email, "email does not match expected value")
|
||||
assert.True(t, userRecord.Active, "user should be verified")
|
||||
require.NoError(t, bcrypt.CompareHashAndPassword([]byte(userRecord.Passwordhash), []byte("1234567890")), "password hash does not match expected value")
|
||||
|
||||
for id := range data.CreateUpgradeTestDataTickets() {
|
||||
ticket, err := queries.Ticket(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find ticket")
|
||||
|
||||
assert.Equal(t, "phishing-123", ticket.Name)
|
||||
assert.Equal(t, "Phishing email reported by several employees.", ticket.Description)
|
||||
assert.True(t, ticket.Open)
|
||||
assert.Equal(t, "alert", ticket.Type)
|
||||
assert.Equal(t, "u_test", *ticket.Owner)
|
||||
assert.JSONEq(t, `{"type":"object","properties":{"tlp":{"title":"TLP","type":"string"}}}`, string(ticket.Schema))
|
||||
assert.JSONEq(t, `{"severity":"Medium"}`, string(ticket.State))
|
||||
}
|
||||
|
||||
for id := range data.CreateUpgradeTestDataComments() {
|
||||
comment, err := queries.GetComment(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find comment")
|
||||
|
||||
assert.Equal(t, "This is a test comment.", comment.Message)
|
||||
}
|
||||
|
||||
for id := range data.CreateUpgradeTestDataTimeline() {
|
||||
timeline, err := queries.GetTimeline(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find timeline")
|
||||
|
||||
assert.Equal(t, "This is a test timeline message.", timeline.Message)
|
||||
}
|
||||
|
||||
for id := range data.CreateUpgradeTestDataTasks() {
|
||||
task, err := queries.GetTask(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find task")
|
||||
|
||||
assert.Equal(t, "This is a test task.", task.Name)
|
||||
}
|
||||
|
||||
for id := range data.CreateUpgradeTestDataLinks() {
|
||||
link, err := queries.GetLink(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find link")
|
||||
|
||||
assert.Equal(t, "https://www.example.com", link.Url)
|
||||
assert.Equal(t, "This is a test link.", link.Name)
|
||||
}
|
||||
|
||||
for id := range data.CreateUpgradeTestDataReaction() {
|
||||
reaction, err := queries.GetReaction(t.Context(), id)
|
||||
require.NoError(t, err, "failed to find reaction")
|
||||
|
||||
assert.Equal(t, "Create New Ticket", reaction.Name)
|
||||
assert.Equal(t, "schedule", reaction.Trigger)
|
||||
assert.JSONEq(t, "{\"expression\":\"12 * * * *\"}", string(reaction.Triggerdata))
|
||||
assert.Equal(t, "python", reaction.Action)
|
||||
assert.Equal(t, "pocketbase", gjson.GetBytes(reaction.Actiondata, "requirements").String())
|
||||
equalWithoutSpace(t, data.Script, gjson.GetBytes(reaction.Actiondata, "script").String())
|
||||
}
|
||||
}
|
||||
|
||||
func equalWithoutSpace(t *testing.T, expected, actual string) {
|
||||
t.Helper()
|
||||
|
||||
assert.Equal(t, removeAllWhitespace(expected), removeAllWhitespace(actual))
|
||||
}
|
||||
|
||||
func removeAllWhitespace(s string) string {
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r == ' ' || r == '\t' || r == '\n' || r == '\r' {
|
||||
return -1 // remove whitespace characters
|
||||
}
|
||||
|
||||
return r // keep other characters
|
||||
}, s)
|
||||
}
|
||||
Reference in New Issue
Block a user