diff --git a/.env.example b/.env.example index 5923bd11..6be96c18 100644 --- a/.env.example +++ b/.env.example @@ -18,6 +18,7 @@ ENABLE_FINS: false MQTT_BROKER: "localhost" MQTT_PORT: 1883 +CALDERA_URL: "" HTTP_SKIP_CERT_VALIDATION: false ### Integrations @@ -25,4 +26,4 @@ HTTP_SKIP_CERT_VALIDATION: false # The Hive THEHIVE_ACTIVATE: true THEHIVE_API_TOKEN: your_token -THEHIVE_API_BASE_URL: http://localhost:9000/api/v1/ \ No newline at end of file +THEHIVE_API_BASE_URL: http://localhost:9000/api/v1/ diff --git a/.gitignore b/.gitignore index 85c0365d..a29c0253 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,7 @@ bin/* swaggerdocs/* **.env test/cacao/flatfile-db-example.json -test/routes/__debug_bin2988553005 - +.idea docs/public docs/resources/ diff --git a/test/unittest/database/memory/memory_test.go b/database/memory/memory_test.go similarity index 96% rename from test/unittest/database/memory/memory_test.go rename to database/memory/memory_test.go index d74c8bcd..ee0c7343 100644 --- a/test/unittest/database/memory/memory_test.go +++ b/database/memory/memory_test.go @@ -1,4 +1,4 @@ -package memory_test +package memory import ( "encoding/json" @@ -6,7 +6,6 @@ import ( "fmt" "io" "os" - "soarca/database/memory" "soarca/models/cacao" "soarca/models/decoder" "sort" @@ -15,7 +14,7 @@ import ( "github.com/go-playground/assert/v2" ) -var PB_PATH string = "../../cacao/playbooks/" +var PB_PATH string = "../../test/playbooks/" func TestCreate(t *testing.T) { jsonFile, err := os.Open(PB_PATH + "playbook.json") @@ -33,7 +32,7 @@ func TestCreate(t *testing.T) { } var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() playbook, err := mem.Create(&byteValue) assert.Equal(t, err, nil) assert.Equal(t, playbook, workflow) @@ -57,7 +56,7 @@ func TestRead(t *testing.T) { var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() empty, err := mem.Read(workflow.ID) assert.Equal(t, err, errors.New("playbook is not in repository")) assert.Equal(t, empty, cacao.Playbook{}) @@ -87,7 +86,7 @@ func TestUpdate(t *testing.T) { var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() empty, err := mem.Update(workflow.ID, nil) assert.Equal(t, err, errors.New("playbook is not in repository")) assert.Equal(t, empty, cacao.Playbook{}) @@ -129,7 +128,7 @@ func TestDelete(t *testing.T) { var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() err = mem.Delete(workflow.ID) assert.Equal(t, err, nil) @@ -166,7 +165,7 @@ func TestGetAllPlaybooks(t *testing.T) { var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() list := []string{ "playbook--f47d4081-21ed-4f21-9d05-6b368d73da30", @@ -214,7 +213,7 @@ func TestGetAllPlaybookMetas(t *testing.T) { var workflow = decoder.DecodeValidate(byteValue) - mem := memory.New() + mem := New() list := []string{ "playbook--f47d4081-21ed-4f21-9d05-6b368d73da30", diff --git a/test/unittest/database/projections_test.go b/database/projections/projections_test.go similarity index 78% rename from test/unittest/database/projections_test.go rename to database/projections/projections_test.go index 0bd8dbff..315244a2 100644 --- a/test/unittest/database/projections_test.go +++ b/database/projections/projections_test.go @@ -1,10 +1,8 @@ -package database_test +package projections import ( "testing" - "soarca/database/projections" - "github.com/go-playground/assert/v2" "go.mongodb.org/mongo-driver/bson" ) @@ -20,7 +18,7 @@ func TestProjectionMeta(t *testing.T) { {Key: "labels", Value: 1}, } - validationMeta := projections.Meta.GetProjection() + validationMeta := Meta.GetProjection() assert.Equal(t, testMeta, validationMeta) } @@ -29,6 +27,6 @@ func TestProjectionID(t *testing.T) { {Key: "_id", Value: 1}, } - validationMeta := projections.Id.GetProjection() + validationMeta := Id.GetProjection() assert.Equal(t, testMeta, validationMeta) } diff --git a/docker/soarca/docker-compose.yml b/docker/soarca/docker-compose.yml index 3a8b2db5..917c6e38 100644 --- a/docker/soarca/docker-compose.yml +++ b/docker/soarca/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.7' services: mongodb_container: image: docker.io/mongo:latest @@ -13,6 +12,19 @@ services: source: mongodb_data_container target: /data/db + caldera: + image: soarca-caldera + build: https://github.com/mitre/caldera.git + networks: + - caldera-net + ports: + - "7010:7010" + - "7011:7011/udp" + - "7012:7012" + - "8888:8888" + profiles: + - caldera + mosquitto: image: docker.io/eclipse-mosquitto container_name: mosquitto @@ -59,6 +71,7 @@ services: MQTT_BROKER: "mosquitto" MQTT_PORT: 1883 HTTP_SKIP_CERT_VALIDATION: false + CALDERA_URL: "http://caldera:8888" # Integrations: # The Hive THEHIVE_ACTIVATE: false @@ -67,6 +80,7 @@ services: networks: - db-net - mqtt-net + - caldera-net ports: - 127.0.0.1:8080:8080 depends_on: @@ -76,7 +90,7 @@ services: networks: db-net: mqtt-net: - + caldera-net: volumes: mongodb_data_container: @@ -88,5 +102,3 @@ volumes: o: bind mosquitto_data: mosquitto_log: - - diff --git a/docs/content/en/docs/_index.md b/docs/content/en/docs/_index.md index 464f727b..59005fdf 100644 --- a/docs/content/en/docs/_index.md +++ b/docs/content/en/docs/_index.md @@ -41,8 +41,6 @@ SOARCA currently supports the following transport mechanisms: {{% card header="SSH - Native" %}} [![Ssh](/SOARCA/images/logos-external/ssh.svg)](/docs/soarca-extensions/native-capabilities/#ssh-capability) {{% /card %}} -{{< /cardpane >}} - {{% card header="PowerShell WinRM - Native" %}} [![PowerShell](/SOARCA/images/logos-external/powershell.svg)](/docs/soarca-extensions/native-capabilities/#powershell-capability) diff --git a/docs/content/en/docs/contribution-guidelines/_index.md b/docs/content/en/docs/contribution-guidelines/_index.md index dc24b4d1..1cfd45e6 100644 --- a/docs/content/en/docs/contribution-guidelines/_index.md +++ b/docs/content/en/docs/contribution-guidelines/_index.md @@ -52,7 +52,7 @@ The CI is configured to only allow for certain branch naming namely: The project has opted to select the [go style guide](https://google.github.io/styleguide/go/) with some exceptions: - Receiver name are not one letter https://google.github.io/styleguide/go/decisions#receiver-names so use `info` instead of `i` -- Initialisms are CamelCase https://google.github.io/styleguide/go/decisions#receiver-names so use `Xml` instead of `XML` +- Initialisms are CamelCase https://google.github.io/styleguide/go/decisions#initialisms so use `Xml` instead of `XML` ## Communication channels diff --git a/docs/content/en/docs/core-components/executer.md b/docs/content/en/docs/core-components/executer.md index 3124a226..16647280 100644 --- a/docs/content/en/docs/core-components/executer.md +++ b/docs/content/en/docs/core-components/executer.md @@ -66,6 +66,7 @@ class "If condition Executor" as condition class "Ssh" as ssh class "OpenC2" as openc2 class "HttpApi" as api +class "CalderaCmd" as calderacmd class "Fin" as fin @@ -106,10 +107,10 @@ The capability selector will select the implementation which is capable of execu * openc2-http * powershell * **Coming soon** + * caldera-cmd * manual * **Future (potentially)** * bash - * caldera-cmd * elastic * jupyter * kestrel @@ -210,4 +211,4 @@ Note only [Comparison Expression](http://docs.oasis-open.org/cti/stix/v2.0/cs01/ {{% /alert %}} ### Parallel step executor -The parallel executor will execute the parallel step. This wil be done in sequence to simplify implementation. As parallel steps must not be depended on each other sequential execution is possible. Later this will be changed. \ No newline at end of file +The parallel executor will execute the parallel step. This will be done in sequence to simplify implementation. As parallel steps must not depend on each other, sequential execution is possible. Later this will be changed. diff --git a/docs/content/en/docs/core-components/modules.md b/docs/content/en/docs/core-components/modules.md index 13d550e0..6fdf70dc 100644 --- a/docs/content/en/docs/core-components/modules.md +++ b/docs/content/en/docs/core-components/modules.md @@ -261,6 +261,63 @@ The result of the step is stored in the following output variables: } ``` +### Caldera capability + +This capability executes [Caldera Abilities](https://caldera.readthedocs.io/en/latest/Learning-the-terminology.html#abilities-and-adversaries) on the specified targets by creating an operation on a separate Caldera server. +The server is packaged in the docker build of SOARCA, but can also be provided separably as a stand-alone server. + +#### Success and failure + +The Caldera step is considered successful if a connection to the Caldera server can be established, the ability, if supplied as b64command, can be created on the server, an operation can be started on the specified group and adversary, and the operation finished without errors. + +In every other circumstance the step is considered to have failed. + +#### Variables + +This module does not define specific variables as input, but variable interpolation is supported in the command and target definitions. It has the following output variables: + +```json +{ + "__soarca_caldera_cmd_result__": { + "type": "string", + "value": "" + } +} +``` + +#### Example + +This example will start an operation that executes the ability with ID `36eecb80-ede3-442b-8774-956e906aff02` on the Caldera agent group `infiltrators`. +```json +{ + "workflow": { + "action--7777c6b6-e275-434e-9e0b-d68f72e691c1": { + "type": "action", + "agent": "soarca--00010001-1000-1000-a000-000100010001", + "targets": ["security-category--c7e6af1b-9e5a-4055-adeb-26b97e1c4db7"], + "commands": [ + { + "type": "caldera", + "command": "36eecb80-ede3-442b-8774-956e906aff02" + } + ] + } + }, + "agent_definitions": { + "soarca--00010001-1000-1000-a000-000100010001": { + "type": "soarca", + "name": "soarca-caldera-cmd" + } + }, + "target_definitions": { + "linux--c7e6af1b-9e5a-4055-adeb-26b97e1c4db7": { + "type": "security-category", + "name": "infiltrators" + "category": ["caldera"], + } + } +} +``` --- diff --git a/docs/content/en/docs/getting-started/_index.md b/docs/content/en/docs/getting-started/_index.md index 82a01ada..18088a21 100644 --- a/docs/content/en/docs/getting-started/_index.md +++ b/docs/content/en/docs/getting-started/_index.md @@ -30,7 +30,7 @@ make build && ./build/soarca wget https://github.com/COSSAS/SOARCA/releases/download/SOARCA_1.0.0/SOARCA_1.0.0_linux_amd64.tar.gz && tar -xvf SOARCA* && ./SOARCA {{< /tab >}} {{< tab header="Docker Compose" lang="sh" >}} -cd docker/soarca && sudo docker compose up -d +cd docker/soarca && docker compose up -d {{< /tab >}} {{< /tabpane >}} @@ -64,16 +64,31 @@ Example playbooks: {{< tabpane langEqualsHeader=false >}} {{< tab header="ssh" lang="sh" >}} # make sure an ssh server is running on adres 192.168.0.10 -curl -X POST -H "Content-Type: application/json" -d @./example/ssh-playbook.json localhost:8080/trigger/playbook +curl -X POST -H "Content-Type: application/json" -d @./example-playbooks/ssh-playbook.json localhost:8080/trigger/playbook {{< /tab >}} {{< tab header="http" lang="sh" >}} -curl -X POST -H "Content-Type: application/json" -d @./example/http-playbook.json localhost:8080/trigger/playbook +curl -X POST -H "Content-Type: application/json" -d @./example-playbooks/http-playbook.json localhost:8080/trigger/playbook {{< /tab >}} {{< tab header="openC2" lang="sh" >}} -curl -X POST -H "Content-Type: application/json" -d @./example/openc2-playbook.json localhost:8080/trigger/playbook +curl -X POST -H "Content-Type: application/json" -d @./example-playbooks/openc2-playbook.json localhost:8080/trigger/playbook {{< /tab >}} {{< /tabpane >}} +### Caldera setup + +SOARCA optionally comes packaged together with Caldera. To use the +[Caldera capability](/docs/soarca-extensions/native-capabilities#caldera-capability), simply make +sure you use the right Compose file when running: + +```diff +- cd docker/soarca && docker compose up -d ++ cd docker/soarca && docker compose --profile caldera up -d +``` + +{{% alert title="Warning" %}} +This only works when using Docker Compose to run SOARCA. When building SOARCA from scratch, +you should supply your own Caldera instance and [configure](#configuration) its URL manually. +{{% /alert %}} ## Configuration @@ -82,6 +97,8 @@ SOARCA reads its configuration from the environment variables or a `.env` file. {{< tabpane langEqualsHeader=false >}} {{< tab header="`.env`" lang="txt" >}} PORT: 8080 +SOARCA_ALLOWED_ORIGINS: "*" +GIN_MODE: "release" MONGODB_URI: "mongodb://localhost:27017" DATABASE_NAME: "soarca" DB_USERNAME: "root" @@ -98,24 +115,14 @@ LOG_FORMAT: "json" ENABLE_FINS: false MQTT_BROKER: "localhost" MQTT_PORT: 1883 -VALIDATION_SCHEMA_URL: "" -{{< /tab >}} -{{< /tabpane >}} - -### Docker hub -`docker pull cossas/soarca` +CALDERA_URL: "" -### Building from Source - -```bash -git clone https://github.com/COSSAS/SOARCA.git -make build -cp .env.example .env -./build/soarca -``` +HTTP_SKIP_CERT_VALIDATION: false +{{< /tab >}} +{{< /tabpane >}} -### Configuring SOARCA +The environment variables have the following meaning: |variable |content |description |---|---|---| @@ -133,4 +140,27 @@ cp .env.example .env |MQTT_BROKER | dns name or ip | The broker address for SOARCA to connect to, for communication with fins default is `localhost` |MQTT_PORT | port | The broker address for SOARCA to connect to, for communication with fins default is `1883` |ENABLE_FINS| true \| false | Enable fins in SOARCA defaults to `false` +|CALDERA_URL| url | Instance URL which the [Caldera capability](/docs/soarca-extensions/native-capabilities#caldera-capability) may use; leaving this empty will disable the Caldera capability |VALIDATION_SCHEMA_URL|url| Set a custom validation schema to be used to validate playbooks defaul is `""` to use internal. NOTE: changing this heavily impacts performance. + +## Obtaining + +There are several ways to obtain a copy of the SOARCA software. + +### Docker Hub + +A prebuilt image can be pulled from the +[Docker Hub](https://hub.docker.com/r/cossas/soarca): + +```bash +docker pull cossas/soarca +``` + +### Building from source + +```bash +git clone https://github.com/COSSAS/SOARCA.git +make build +cp .env.example .env +./build/soarca +``` diff --git a/docs/content/en/docs/soarca-extensions/_index.md b/docs/content/en/docs/soarca-extensions/_index.md index 95c632e9..27ba62c4 100644 --- a/docs/content/en/docs/soarca-extensions/_index.md +++ b/docs/content/en/docs/soarca-extensions/_index.md @@ -10,7 +10,7 @@ date: 2023-01-05 {{% alert title="Warning" color="warning" %}} -SOARCA V.1.0.X implements currently the following native capalities: **HTTP capability**, **OpenC2 capability**, and **SSH capability**. Other core capabilities are part of our milestones which can be found [here](https://github.com/COSSAS/SOARCA/milestones). +SOARCA V.1.0.X implements currently the following native capalities: **HTTP capability**, **OpenC2 capability**, **SSH capability**, and **Caldera capability**. Other core capabilities are part of our milestones which can be found [here](https://github.com/COSSAS/SOARCA/milestones). {{% /alert %}} SOARCA features a set of [native capabilities](/docs/soarca-extensions/native-capabilities). The HTTP, OpenC2 HTTP, and SSH transport mechanisms are supported by the first release of SOARCA. SOARCA's capabilities can be extended with custom implementations, which is further discussed on this page. diff --git a/docs/content/en/docs/soarca-extensions/native-capabilities.md b/docs/content/en/docs/soarca-extensions/native-capabilities.md index 91d8ca37..8a15a09a 100644 --- a/docs/content/en/docs/soarca-extensions/native-capabilities.md +++ b/docs/content/en/docs/soarca-extensions/native-capabilities.md @@ -33,4 +33,10 @@ CACAO documentation: [SSH Command](https://docs.oasis-open.org/cacao/security-pl The PowerShell capability allows executing commands on systems running an WinRM server. -CACAO documentation: [PowerShell Command](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256499) \ No newline at end of file +CACAO documentation: [PowerShell Command](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256499) + +## Caldera capability + +The Caldera capability allows for interoperability between SOARCA and [Caldera](https://caldera.mitre.org/). + +Caldera documentation: [caldera Command](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256493) diff --git a/example-playbooks/caldera/basic-step.json b/example-playbooks/caldera/basic-step.json new file mode 100644 index 00000000..e898eba5 --- /dev/null +++ b/example-playbooks/caldera/basic-step.json @@ -0,0 +1,54 @@ +{ + "type": "playbook", + "spec_version": "cacao-2.0", + "id": "playbook--77bbe093-7e90-400c-a7c4-7b3a9396af15", + "name": "Caldera example playbook of a basic Caldera step", + "description": "This is a SOARCA TNO Read teaming example playbook.", + "created_by": "identity--0fc44117-48d3-41b8-8bd4-b8dc334f500d", + "created": "2024-10-08T07:49:16.348Z", + "modified": "2024-10-08T07:49:16.349Z", + "revoked": false, + "derived_from": [ + "playbook--879932d9-fea9-40c1-a5a4-3b3d2eec9835" + ], + "workflow_start": "start--025c407e-422e-4deb-8863-b3d4a8890f60", + "workflow": { + "start--025c407e-422e-4deb-8863-b3d4a8890f60": { + "on_completion": "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1", + "type": "start" + }, + "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1": { + "name": "Run some Caldera command", + "on_completion": "end--080de9ac-65c7-49f0-acd2-b21e92e34036", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 80879fa1-765e-48c2-bcd3-6fa3b4b2e7a7" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "end--080de9ac-65c7-49f0-acd2-b21e92e34036": { + "type": "end" + } + }, + "agent_definitions": { + "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c": { + "type": "soarca", + "name": "soarca-caldera-cmd" + } + }, + "target_definitions": { + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e": { + "type": "security-category", + "name": "djnsbg", + "category": [ + "caldera" + ] + } + } +} \ No newline at end of file diff --git a/example-playbooks/caldera/consecutive-steps.json b/example-playbooks/caldera/consecutive-steps.json new file mode 100644 index 00000000..97d66a19 --- /dev/null +++ b/example-playbooks/caldera/consecutive-steps.json @@ -0,0 +1,69 @@ +{ + "type": "playbook", + "spec_version": "cacao-2.0", + "id": "playbook--77bbe093-7e90-400c-a7c4-7b3a9396af15", + "name": "Caldera example playbook of two consecutive caldera steps being executed", + "description": "This is a SOARCA TNO Read teaming example playbook.", + "created_by": "identity--0fc44117-48d3-41b8-8bd4-b8dc334f500d", + "created": "2024-10-08T07:49:16.348Z", + "modified": "2024-10-08T07:49:16.349Z", + "revoked": false, + "derived_from": [ + "playbook--879932d9-fea9-40c1-a5a4-3b3d2eec9835" + ], + "workflow_start": "start--025c407e-422e-4deb-8863-b3d4a8890f60", + "workflow": { + "start--025c407e-422e-4deb-8863-b3d4a8890f60": { + "on_completion": "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1", + "type": "start" + }, + "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1": { + "name": "Run some Caldera command", + "on_completion": "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 80879fa1-765e-48c2-bcd3-6fa3b4b2e7a7" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266": { + "name": "Run another Caldera command", + "on_completion": "end--080de9ac-65c7-49f0-acd2-b21e92e34036", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 36eecb80-ede3-442b-8774-956e906aff02" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "end--080de9ac-65c7-49f0-acd2-b21e92e34036": { + "type": "end" + } + }, + "agent_definitions": { + "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c": { + "type": "soarca", + "name": "soarca-caldera-cmd" + } + }, + "target_definitions": { + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e": { + "type": "security-category", + "name": "djnsbg", + "category": [ + "caldera" + ] + } + } +} \ No newline at end of file diff --git a/example-playbooks/caldera/flow-control.json b/example-playbooks/caldera/flow-control.json new file mode 100644 index 00000000..cff19fbc --- /dev/null +++ b/example-playbooks/caldera/flow-control.json @@ -0,0 +1,121 @@ +{ + "type": "playbook", + "spec_version": "cacao-2.0", + "id": "playbook--a92fc24f-4adb-4ac2-8846-31968c23699a", + "name": "Caldera example playbook of control flow steps being used alongside Calders steps", + "description": "This is a SOARCA TNO Read teaming example playbook.", + "created_by": "identity--7f497236-2aa5-431b-b704-d7b26b319163", + "created": "2024-11-08T09:44:35.226Z", + "modified": "2024-11-08T09:44:53.904Z", + "revoked": false, + "derived_from": [ + "playbook--879932d9-fea9-40c1-a5a4-3b3d2eec9835", + "playbook--77bbe093-7e90-400c-a7c4-7b3a9396af15" + ], + "playbook_variables": { + "__ifStepVariable__": { + "type": "bool", + "description": "Variable used by the if-step", + "value": "true", + "constant": false, + "external": false + }, + "__whileStepVariable__": { + "type": "integer", + "description": "Variable used by the while-step", + "value": "0", + "constant": false, + "external": false + }, + "__switchStepVariable__": { + "type": "integer", + "description": "Variable used by the switch-step", + "value": "0", + "constant": false, + "external": false + } + }, + "workflow_start": "start--025c407e-422e-4deb-8863-b3d4a8890f60", + "workflow": { + "start--025c407e-422e-4deb-8863-b3d4a8890f60": { + "on_completion": "if-condition--f00f0acb-a2ad-4832-b7c2-27d12506c6d7", + "type": "start" + }, + "if-condition--f00f0acb-a2ad-4832-b7c2-27d12506c6d7": { + "on_completion": "while-condition--8c0872af-a071-48af-9bf9-a8ad7e137289", + "type": "if-condition", + "condition": "__ifStepVariable__:value", + "on_true": "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1", + "on_false": "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266" + }, + "while-condition--8c0872af-a071-48af-9bf9-a8ad7e137289": { + "on_completion": "switch-condition--33ba061e-193d-41db-b40b-0e8373997dc9", + "type": "while-condition", + "condition": "__whileStepVariable__:value <= 10", + "on_true": "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266" + }, + "switch-condition--33ba061e-193d-41db-b40b-0e8373997dc9": { + "on_completion": "end--48d7d487-3c8a-4651-bbc2-40c519e2b9f7", + "type": "switch-condition", + "switch": "__switchStepVariable__:value", + "cases": { + "0": "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266", + "default": "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1" + } + }, + "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1": { + "name": "Run some Caldera command", + "on_completion": "end--080de9ac-65c7-49f0-acd2-b21e92e34036", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 80879fa1-765e-48c2-bcd3-6fa3b4b2e7a7" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266": { + "name": "Run another Caldera command", + "on_completion": "end--32964690-69a0-4fb3-8124-0ce63c0e09b9", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 36eecb80-ede3-442b-8774-956e906aff02" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "end--080de9ac-65c7-49f0-acd2-b21e92e34036": { + "type": "end" + }, + "end--48d7d487-3c8a-4651-bbc2-40c519e2b9f7": { + "type": "end" + }, + "end--32964690-69a0-4fb3-8124-0ce63c0e09b9": { + "type": "end" + } + }, + "agent_definitions": { + "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c": { + "type": "soarca", + "name": "soarca-caldera-cmd" + } + }, + "target_definitions": { + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e": { + "type": "security-category", + "name": "djnsbg", + "category": [ + "caldera" + ] + } + } +} diff --git a/example-playbooks/caldera/used-response.json b/example-playbooks/caldera/used-response.json new file mode 100644 index 00000000..130bf35e --- /dev/null +++ b/example-playbooks/caldera/used-response.json @@ -0,0 +1,84 @@ +{ + "type": "playbook", + "spec_version": "cacao-2.0", + "id": "playbook--77bbe093-7e90-400c-a7c4-7b3a9396af15", + "name": "Caldera example playbook", + "description": "This is a SOARCA TNO Read teaming example playbook.", + "created_by": "identity--0fc44117-48d3-41b8-8bd4-b8dc334f500d", + "created": "2024-10-08T07:49:16.348Z", + "modified": "2024-10-08T07:49:16.349Z", + "revoked": false, + "derived_from": [ + "playbook--879932d9-fea9-40c1-a5a4-3b3d2eec9835" + ], + "playbook_variables": { + "__ifStepVariable__": { + "type": "bool", + "description": "Variable used by the if-step", + "value": "false", + "constant": false, + "external": false + } + }, + "workflow_start": "start--025c407e-422e-4deb-8863-b3d4a8890f60", + "workflow": { + "start--025c407e-422e-4deb-8863-b3d4a8890f60": { + "on_completion": "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1", + "type": "start" + }, + "action--623a0a80-a4ac-4989-b1da-5e3660b2e4f1": { + "name": "Run some Caldera command", + "on_completion": "if-condition--f00f0acb-a2ad-4832-b7c2-27d12506c6d7", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 80879fa1-765e-48c2-bcd3-6fa3b4b2e7a7" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "if-condition--f00f0acb-a2ad-4832-b7c2-27d12506c6d7": { + "type": "if-condition", + "on_completion": "end--080de9ac-65c7-49f0-acd2-b21e92e34036", + "condition": "__ifStepVariable__:value", + "on_true": "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266" + }, + "action--3ad2d927-9480-4d05-bcbb-7d40b4da2266": { + "name": "Run another Caldera command", + "on_completion": "end--080de9ac-65c7-49f0-acd2-b21e92e34036", + "type": "action", + "commands": [ + { + "type": "caldera-cmd", + "command": "id: 36eecb80-ede3-442b-8774-956e906aff02" + } + ], + "agent": "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c", + "targets": [ + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e" + ] + }, + "end--080de9ac-65c7-49f0-acd2-b21e92e34036": { + "type": "end" + } + }, + "agent_definitions": { + "caldera--4801fe91-cd09-4da3-a67d-3d69cd9fec7c": { + "type": "soarca", + "name": "soarca-caldera-cmd" + } + }, + "target_definitions": { + "security-category--b1ead715-d565-48f8-a6a4-0d5c4a3e643e": { + "type": "security-category", + "name": "djnsbg", + "category": [ + "caldera" + ] + } + } +} \ No newline at end of file diff --git a/example/http-playbook.json b/example-playbooks/http-playbook.json similarity index 100% rename from example/http-playbook.json rename to example-playbooks/http-playbook.json diff --git a/example/openc2-playbook.json b/example-playbooks/openc2-playbook.json similarity index 100% rename from example/openc2-playbook.json rename to example-playbooks/openc2-playbook.json diff --git a/example/powershell-playbook.json b/example-playbooks/powershell-playbook.json similarity index 100% rename from example/powershell-playbook.json rename to example-playbooks/powershell-playbook.json diff --git a/example/ssh-playbook.json b/example-playbooks/ssh-playbook.json similarity index 100% rename from example/ssh-playbook.json rename to example-playbooks/ssh-playbook.json diff --git a/test/unittest/capability/controller/controller_test.go b/internal/capability/controller/controller_test.go similarity index 93% rename from test/unittest/capability/controller/controller_test.go rename to internal/capability/controller/controller_test.go index 823df29e..ed33ad80 100644 --- a/test/unittest/capability/controller/controller_test.go +++ b/internal/capability/controller/controller_test.go @@ -1,8 +1,7 @@ -package controller_test +package controller import ( "encoding/json" - "soarca/internal/capability/controller" "soarca/models/fin" "soarca/test/unittest/mocks/mock_mqtt" "testing" @@ -16,7 +15,7 @@ func TestGetRegisteredc(t *testing.T) { mqtt := new(mock_mqtt.Mock_MqttClient) token := mock_mqtt.Mock_MqttToken{} token2 := mock_mqtt.Mock_MqttToken{} - capabiltyController := controller.New(mqtt) + capabiltyController := New(mqtt) fins := capabiltyController.GetRegisteredCapabilities() assert.Equal(t, len(fins), 0) @@ -68,7 +67,7 @@ func TestGetRegisteredc(t *testing.T) { func TestConnectAndSubsribe(t *testing.T) { mqtt := new(mock_mqtt.Mock_MqttClient) token := mock_mqtt.Mock_MqttToken{} - capabiltyController := controller.New(mqtt) + capabiltyController := New(mqtt) token.On("Wait").Return(true) token.On("Error").Return(nil) diff --git a/test/unittest/capability/fin/fin_test.go b/internal/capability/fin/fin_test.go similarity index 95% rename from test/unittest/capability/fin/fin_test.go rename to internal/capability/fin/fin_test.go index aaefb017..81d2a165 100644 --- a/test/unittest/capability/fin/fin_test.go +++ b/internal/capability/fin/fin_test.go @@ -1,7 +1,6 @@ -package fin_test +package fin import ( - "soarca/internal/capability/fin" "soarca/models/cacao" "soarca/models/execution" model "soarca/models/fin" @@ -15,7 +14,7 @@ import ( func TestFinExecution(t *testing.T) { mockFinProtocol := new(mock_finprotocol.MockFinProtocol) //mockGuid := new(mock_guid.Mock_Guid) - finCapability := fin.New(mockFinProtocol) + finCapability := New(mockFinProtocol) var executionId, _ = uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") var playbookId, _ = uuid.Parse("d09351a2-a075-40c8-8054-0b7c423db83f") diff --git a/test/unittest/capability/http/http_test.go b/internal/capability/http/http_test.go similarity index 95% rename from test/unittest/capability/http/http_test.go rename to internal/capability/http/http_test.go index da9cf972..d587b8bd 100644 --- a/test/unittest/capability/http/http_test.go +++ b/internal/capability/http/http_test.go @@ -1,11 +1,11 @@ -package http_test +package http // Build http capability with New() using mock http Request // test correct parsing of HttpOptions fields and errors handling import ( "errors" - "soarca/internal/capability/http" + "soarca/models/cacao" "soarca/models/execution" mock_request "soarca/test/unittest/mocks/mock_utils/http" @@ -18,7 +18,7 @@ import ( func TestHTTPOptionsCorrectlyGenerated(t *testing.T) { mock_http_request := new(mock_request.MockHttpRequest) - httpCapability := http.New(mock_http_request) + httpCapability := New(mock_http_request) var oauth2_info = cacao.AuthenticationInformation{ ID: "6ba7b810-9dad-11d1-80b4-00c04fd430c9", @@ -74,7 +74,7 @@ func TestHTTPOptionsCorrectlyGenerated(t *testing.T) { func TestHTTPOptionsEmptyAuth(t *testing.T) { mock_http_request := &mock_request.MockHttpRequest{} - httpCapability := http.New(mock_http_request) + httpCapability := New(mock_http_request) target := cacao.AgentTarget{Address: map[cacao.NetAddressType][]string{ "url": {"https://httpbin.org/post"}, @@ -125,7 +125,7 @@ func TestHTTPOptionsEmptyAuth(t *testing.T) { func TestHTTPOptionsEmptyCommand(t *testing.T) { mock_http_request := &mock_request.MockHttpRequest{} - httpCapability := http.New(mock_http_request) + httpCapability := New(mock_http_request) target := cacao.AgentTarget{Address: map[cacao.NetAddressType][]string{ "url": {"https://httpbin.org/post"}, diff --git a/test/unittest/capability/openc2/openc2_test.go b/internal/capability/openc2/openc2_test.go similarity index 94% rename from test/unittest/capability/openc2/openc2_test.go rename to internal/capability/openc2/openc2_test.go index 92cd3df0..143e77f5 100644 --- a/test/unittest/capability/openc2/openc2_test.go +++ b/internal/capability/openc2/openc2_test.go @@ -1,9 +1,8 @@ -package openc2_test +package openc2 import ( "testing" - openc2 "soarca/internal/capability/openc2" "soarca/models/cacao" "soarca/models/execution" mockRequest "soarca/test/unittest/mocks/mock_utils/http" @@ -15,7 +14,7 @@ import ( func TestOpenC2Request(t *testing.T) { mockHttp := &mockRequest.MockHttpRequest{} - openc2 := openc2.New(mockHttp) + openc2 := New(mockHttp) authId, _ := uuid.Parse("6aa7b810-9dad-11d1-81b4-00c04fd430c8") executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") diff --git a/test/unittest/capability/ssh/ssh_test.go b/internal/capability/ssh/ssh_test.go similarity index 78% rename from test/unittest/capability/ssh/ssh_test.go rename to internal/capability/ssh/ssh_test.go index 25d85d3d..3b517c22 100644 --- a/test/unittest/capability/ssh/ssh_test.go +++ b/internal/capability/ssh/ssh_test.go @@ -1,8 +1,7 @@ -package ssh_test +package ssh import ( "errors" - "soarca/internal/capability/ssh" "soarca/models/cacao" "testing" @@ -11,66 +10,66 @@ import ( func TestStripSshPrependWithPrepend(t *testing.T) { command := "ssh ls -la" - result := ssh.StripSshPrepend(command) + result := StripSshPrepend(command) assert.Equal(t, result, "ls -la") } func TestStripSshPrependWithoutPrepend(t *testing.T) { command := "ls -la" - result := ssh.StripSshPrepend(command) + result := StripSshPrepend(command) assert.Equal(t, result, "ls -la") } func TestAuthenticationValidationUserAuth(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "user-auth", Username: "root", Password: "password"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) assert.Equal(t, result, nil) } func TestAuthenticationValidationUserAuthMissingPassword(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "user-auth", Username: "root"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("password is empty") assert.Equal(t, result, err) } func TestAuthenticationValidationUserAuthSpacesAsPassword(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "user-auth", Username: "root", Password: " "} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("password is empty") assert.Equal(t, result, err) } func TestAuthenticationValidationUserAuthSpacesAsUser(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "user-auth", Username: " ", Password: "password"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("username is empty") assert.Equal(t, result, err) } func TestAuthenticationValidationPrivateKeyAuth(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "private-key", Username: "root", PrivateKey: "someprivatekey"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) assert.Equal(t, result, nil) } func TestAuthenticationValidationPrivateKeyAuthMissingKey(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "private-key", Username: "root"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("private key is not set") assert.Equal(t, result, err) } func TestAuthenticationValidationPrivateKeyAuthSpacesAsKey(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "private-key", Username: "root", PrivateKey: " "} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("private key is not set") assert.Equal(t, result, err) } func TestAuthenticationValidationPrivateKeyAuthSpacesAsUser(t *testing.T) { auth := cacao.AuthenticationInformation{Type: "private-key", Username: " ", PrivateKey: "someprivatekey"} - result := ssh.CheckSshAuthenticationInfo(auth) + result := CheckSshAuthenticationInfo(auth) err := errors.New("username is empty") assert.Equal(t, result, err) } @@ -79,14 +78,14 @@ func TestAddressAndPortCombination(t *testing.T) { ipv4 := map[cacao.NetAddressType][]string{"ipv4": {"134.221.49.62"}} port := "22" expectedFqdn := "134.221.49.62:22" - result := ssh.CombinePortAndAddress(ipv4, port) + result := CombinePortAndAddress(ipv4, port) assert.Equal(t, result, expectedFqdn) } func TestAddressAndPortCombinationNoPort(t *testing.T) { ipv4 := map[cacao.NetAddressType][]string{"ipv4": {"134.221.49.62"}} port := "" expectedFqdn := "134.221.49.62:22" - result := ssh.CombinePortAndAddress(ipv4, port) + result := CombinePortAndAddress(ipv4, port) assert.Equal(t, result, expectedFqdn) } @@ -94,13 +93,13 @@ func TestAddressAndPortCombinationNoAddress(t *testing.T) { ipv4 := map[cacao.NetAddressType][]string{} port := "22" expectedFqdn := "" - result := ssh.CombinePortAndAddress(ipv4, port) + result := CombinePortAndAddress(ipv4, port) assert.Equal(t, result, expectedFqdn) } func TestAddressAndPortCombinationNoIpv4Address(t *testing.T) { - ipv4 := map[cacao.NetAddressType][]string{"invallid": {"feed::0001"}} + ipv4 := map[cacao.NetAddressType][]string{"invalid": {"feed::0001"}} port := "22" expectedFqdn := "" - result := ssh.CombinePortAndAddress(ipv4, port) + result := CombinePortAndAddress(ipv4, port) assert.Equal(t, result, expectedFqdn) } diff --git a/test/unittest/decomposer/decomposer_test.go b/internal/decomposer/decomposer_test.go similarity index 98% rename from test/unittest/decomposer/decomposer_test.go rename to internal/decomposer/decomposer_test.go index fe7e0f19..cf915d1a 100644 --- a/test/unittest/decomposer/decomposer_test.go +++ b/internal/decomposer/decomposer_test.go @@ -1,4 +1,4 @@ -package decomposer_test +package decomposer import ( "errors" @@ -6,7 +6,6 @@ import ( "testing" "time" - "soarca/internal/decomposer" "soarca/internal/executors/action" "soarca/models/cacao" "soarca/models/execution" @@ -40,7 +39,7 @@ func TestExecutePlaybook(t *testing.T) { Value: "testing", } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -160,7 +159,7 @@ func TestExecutePlaybookMultiStep(t *testing.T) { Value: "testing2", } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -315,7 +314,7 @@ func TestExecuteEmptyMultiStep(t *testing.T) { Name: "soarca-ssh", } - decomposer2 := decomposer.New(mock_action_executor2, + decomposer2 := New(mock_action_executor2, mock_playbook_action_executor2, mock_condition_executor, uuid_mock2, @@ -403,7 +402,7 @@ func TestFailingStepResultsInFailingPlaybook(t *testing.T) { Value: "testing2", } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -566,7 +565,7 @@ func TestExecuteIllegalMultiStep(t *testing.T) { Value: "testing", } - decomposer2 := decomposer.New(mock_action_executor2, + decomposer2 := New(mock_action_executor2, mock_playbook_action_executor2, mock_condition_executor, uuid_mock2, @@ -625,7 +624,7 @@ func TestExecutePlaybookAction(t *testing.T) { Value: "testing", } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -721,7 +720,7 @@ func TestExecuteIfCondition(t *testing.T) { Name: "soarca-ssh", } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -901,7 +900,7 @@ func TestDelayStepExecution(t *testing.T) { Delay: 10, } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, @@ -955,7 +954,7 @@ func TestDelayStepNegativeTimeExecution(t *testing.T) { Delay: -10, } - decomposer := decomposer.New(mock_action_executor, + decomposer := New(mock_action_executor, mock_playbook_action_executor, mock_condition_executor, uuid_mock, diff --git a/test/unittest/executor/action/action_executor_test.go b/internal/executors/action/action_executor_test.go similarity index 95% rename from test/unittest/executor/action/action_executor_test.go rename to internal/executors/action/action_executor_test.go index a4e5a058..4e58d72d 100644 --- a/test/unittest/executor/action/action_executor_test.go +++ b/internal/executors/action/action_executor_test.go @@ -1,4 +1,4 @@ -package action_executor_test +package action import ( "errors" @@ -6,7 +6,6 @@ import ( "time" "soarca/internal/capability" - "soarca/internal/executors/action" "soarca/models/cacao" "soarca/models/execution" "soarca/test/unittest/mocks/mock_capability" @@ -25,7 +24,7 @@ func TestExecuteStep(t *testing.T) { capabilities := map[string]capability.ICapability{"mock-ssh": mock_ssh, "http-api": mock_http} - executerObject := action.New(capabilities, mock_reporter, mock_time) + executerObject := New(capabilities, mock_reporter, mock_time) executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") playbookId := "playbook--d09351a2-a075-40c8-8054-0b7c423db83f" stepId := "step--81eff59f-d084-4324-9e0a-59e353dbd28f" @@ -70,7 +69,7 @@ func TestExecuteStep(t *testing.T) { Targets: []string{"target1"}, } - actionMetadata := action.PlaybookStepMetadata{ + actionMetadata := PlaybookStepMetadata{ Step: step, Targets: map[string]cacao.AgentTarget{expectedTarget.ID: expectedTarget}, Auth: map[string]cacao.AuthenticationInformation{expectedAuth.ID: expectedAuth}, @@ -112,7 +111,7 @@ func TestExecuteActionStep(t *testing.T) { capabilities := map[string]capability.ICapability{"ssh": mock_ssh, "http-api": mock_http} - executerObject := action.New(capabilities, mock_reporter, mock_time) + executerObject := New(capabilities, mock_reporter, mock_time) executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") playbookId := "playbook--d09351a2-a075-40c8-8054-0b7c423db83f" stepId := "step--81eff59f-d084-4324-9e0a-59e353dbd28f" @@ -172,7 +171,7 @@ func TestNonExistingCapabilityStep(t *testing.T) { capabilities := map[string]capability.ICapability{"ssh": mock_ssh, "http-api": mock_http} - executerObject := action.New(capabilities, new(mock_reporter.Mock_Reporter), mock_time) + executerObject := New(capabilities, new(mock_reporter.Mock_Reporter), mock_time) executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") playbookId := "playbook--d09351a2-a075-40c8-8054-0b7c423db83f" stepId := "step--81eff59f-d084-4324-9e0a-59e353dbd28f" @@ -221,7 +220,7 @@ func TestVariableInterpolation(t *testing.T) { capabilities := map[string]capability.ICapability{"cap1": mock_capability1} - executerObject := action.New(capabilities, new(mock_reporter.Mock_Reporter), mock_time) + executerObject := New(capabilities, new(mock_reporter.Mock_Reporter), mock_time) executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") playbookId := "playbook--d09351a2-a075-40c8-8054-0b7c423db83f" stepId := "step--81eff59f-d084-4324-9e0a-59e353dbd28f" diff --git a/test/unittest/executor/condition/condition_executor_test.go b/internal/executors/condition/condition_executor_test.go similarity index 92% rename from test/unittest/executor/condition/condition_executor_test.go rename to internal/executors/condition/condition_executor_test.go index 5bc53b1e..efd5b371 100644 --- a/test/unittest/executor/condition/condition_executor_test.go +++ b/internal/executors/condition/condition_executor_test.go @@ -1,8 +1,7 @@ -package condition_test +package condition import ( "errors" - "soarca/internal/executors/condition" "soarca/models/cacao" "soarca/models/execution" "soarca/test/unittest/mocks/mock_reporter" @@ -20,7 +19,7 @@ func TestExecuteConditionTrue(t *testing.T) { mock_reporter := new(mock_reporter.Mock_Reporter) mock_time := new(mock_time.MockTime) - conditionExecutior := condition.New(mock_stix, mock_reporter, mock_time) + conditionExecutior := New(mock_stix, mock_reporter, mock_time) executionId := uuid.New() @@ -58,7 +57,7 @@ func TestExecuteConditionFalse(t *testing.T) { mock_reporter := new(mock_reporter.Mock_Reporter) mock_time := new(mock_time.MockTime) - conditionExecutior := condition.New(mock_stix, mock_reporter, mock_time) + conditionExecutior := New(mock_stix, mock_reporter, mock_time) executionId := uuid.New() @@ -96,7 +95,7 @@ func TestExecuteConditionError(t *testing.T) { mock_reporter := new(mock_reporter.Mock_Reporter) mock_time := new(mock_time.MockTime) - conditionExecutior := condition.New(mock_stix, mock_reporter, mock_time) + conditionExecutior := New(mock_stix, mock_reporter, mock_time) executionId := uuid.New() diff --git a/test/unittest/executor/playbook_action/playbook_action_executor_test.go b/internal/executors/playbook_action/playbook_action_executor_test.go similarity index 94% rename from test/unittest/executor/playbook_action/playbook_action_executor_test.go rename to internal/executors/playbook_action/playbook_action_executor_test.go index 911a99c0..2e180383 100644 --- a/test/unittest/executor/playbook_action/playbook_action_executor_test.go +++ b/internal/executors/playbook_action/playbook_action_executor_test.go @@ -1,11 +1,10 @@ -package playbook_action_executor_test +package playbook_action import ( "testing" "time" "soarca/internal/decomposer" - "soarca/internal/executors/playbook_action" mock_database_controller "soarca/test/unittest/mocks/mock_controller/database" mock_decomposer_controller "soarca/test/unittest/mocks/mock_controller/decomposer" "soarca/test/unittest/mocks/mock_decomposer" @@ -30,7 +29,7 @@ func TestExecutePlaybook(t *testing.T) { controller := new(mock_decomposer_controller.Mock_Controller) database := new(mock_database_controller.Mock_Controller) - executerObject := playbook_action.New(controller, database, mock_reporter, mock_time) + executerObject := New(controller, database, mock_reporter, mock_time) executionId, _ := uuid.Parse("6ba7b810-9dad-11d1-80b4-00c04fd430c8") playbookId := "playbook--d09351a2-a075-40c8-8054-0b7c423db83f" stepId := "step--81eff59f-d084-4324-9e0a-59e353dbd28f" diff --git a/test/unittest/finprotocol/finprotocol_test.go b/internal/fin/protocol/finprotocol_test.go similarity index 89% rename from test/unittest/finprotocol/finprotocol_test.go rename to internal/fin/protocol/finprotocol_test.go index 73e09bb0..bc5d65ad 100644 --- a/test/unittest/finprotocol/finprotocol_test.go +++ b/internal/fin/protocol/finprotocol_test.go @@ -1,10 +1,9 @@ -package finprotocol_test +package protocol import ( "encoding/json" "errors" "fmt" - "soarca/internal/fin/protocol" "soarca/internal/guid" "soarca/models/cacao" "soarca/models/fin" @@ -22,7 +21,7 @@ func TestSubscribe(t *testing.T) { mock_token := mock_mqtt.Mock_MqttToken{} guid := new(guid.Guid) - prot := protocol.FinProtocol{Guid: guid, Topic: protocol.Topic("testing"), Broker: "localhost", Port: 1883} + prot := FinProtocol{Guid: guid, Topic: Topic("testing"), Broker: "localhost", Port: 1883} mock_token.On("Wait").Return(true) mock_client.On("Subscribe", "testing", uint8(1), mock.Anything).Return(&mock_token) @@ -35,7 +34,7 @@ func TestTimeoutAndCallbackTimerElaspsed(t *testing.T) { mock_token := mock_mqtt.Mock_MqttToken{} guid := new(guid.Guid) - prot := protocol.FinProtocol{Guid: guid, Topic: protocol.Topic("testing"), Broker: "localhost", Port: 1883} + prot := FinProtocol{Guid: guid, Topic: Topic("testing"), Broker: "localhost", Port: 1883} mock_token.On("Wait").Return(true) mock_client.On("Subscribe", "testing", uint8(1), mock.Anything).Return(&mock_token) @@ -58,7 +57,7 @@ func TestTimeoutAndCallbackHandlerCalled(t *testing.T) { guid := new(guid.Guid) - prot := protocol.New(guid, "testing", "localhost", 1883) + prot := New(guid, "testing", "localhost", 1883) mock_token.On("Wait").Return(true) mock_client.On("Subscribe", "testing", uint8(1), mock.Anything).Return(&mock_token) @@ -83,7 +82,7 @@ func TestTimeoutAndCallbackHandlerCalled(t *testing.T) { } // Helper for TestTimeoutAndCallbackHandlerCalled -func helper(prot *protocol.FinProtocol) { +func helper(prot *FinProtocol) { time.Sleep(1 * time.Millisecond) client := mock_mqtt.Mock_MqttClient{} message := mock_mqtt.Mock_MqttMessage{} diff --git a/test/unittest/reporters/downstream_reporter/cache_test.go b/internal/reporter/downstream_reporter/cache/cache_test.go similarity index 98% rename from test/unittest/reporters/downstream_reporter/cache_test.go rename to internal/reporter/downstream_reporter/cache/cache_test.go index 3f449306..34613dc4 100644 --- a/test/unittest/reporters/downstream_reporter/cache_test.go +++ b/internal/reporter/downstream_reporter/cache/cache_test.go @@ -1,9 +1,8 @@ -package cache_test +package cache import ( b64 "encoding/base64" "errors" - "soarca/internal/reporter/downstream_reporter/cache" "soarca/models/cacao" cache_model "soarca/models/cache" mock_time "soarca/test/unittest/mocks/mock_utils/time" @@ -17,7 +16,7 @@ import ( func TestReportWorkflowStartFirst(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "ssh", @@ -149,7 +148,7 @@ func TestReportWorkflowStartFirst(t *testing.T) { func TestReportWorkflowStartFifo(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 3) + cacheReporter := New(mock_time, 3) expectedCommand := cacao.Command{ Type: "ssh", @@ -295,7 +294,7 @@ func TestReportWorkflowStartFifo(t *testing.T) { func TestReportWorkflowEnd(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "ssh", @@ -398,7 +397,7 @@ func TestReportWorkflowEnd(t *testing.T) { func TestReportStepStartAndEnd(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "ssh", @@ -522,7 +521,7 @@ func TestReportStepStartAndEnd(t *testing.T) { func TestReportStepStartCommandsEncoding(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand1 := cacao.Command{ Type: "manual", @@ -662,7 +661,7 @@ func TestReportStepStartCommandsEncoding(t *testing.T) { func TestReportStepStartManualCommand(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "manual", @@ -792,7 +791,7 @@ func TestReportStepStartManualCommand(t *testing.T) { func TestInvalidStepReportAfterStepEnd(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "ssh", @@ -882,7 +881,7 @@ func TestInvalidStepReportAfterStepEnd(t *testing.T) { func TestAcceptedStepReportAfterExecutionEnd(t *testing.T) { mock_time := new(mock_time.MockTime) - cacheReporter := cache.New(mock_time, 10) + cacheReporter := New(mock_time, 10) expectedCommand := cacao.Command{ Type: "ssh", diff --git a/test/unittest/reporters/reporter/reporter_test.go b/internal/reporter/reporter_test.go similarity index 94% rename from test/unittest/reporters/reporter/reporter_test.go rename to internal/reporter/reporter_test.go index d32aff28..a809b738 100644 --- a/test/unittest/reporters/reporter/reporter_test.go +++ b/internal/reporter/reporter_test.go @@ -1,8 +1,7 @@ -package reporter_test +package reporter import ( "errors" - "soarca/internal/reporter" ds_reporter "soarca/internal/reporter/downstream_reporter" "soarca/models/cacao" "soarca/test/unittest/mocks/mock_reporter" @@ -20,7 +19,7 @@ import ( func TestRegisterReporter(t *testing.T) { mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{}) + reporter := New([]ds_reporter.IDownStreamReporter{}) err := reporter.RegisterReporters([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) if err != nil { t.Fail() @@ -28,13 +27,13 @@ func TestRegisterReporter(t *testing.T) { } func TestRegisterTooManyReporters(t *testing.T) { - too_many_reporters := make([]ds_reporter.IDownStreamReporter, reporter.MaxReporters+1) + too_many_reporters := make([]ds_reporter.IDownStreamReporter, MaxReporters+1) mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{} for i := range too_many_reporters { too_many_reporters[i] = &mock_ds_reporter } - reporter := reporter.New([]ds_reporter.IDownStreamReporter{}) + reporter := New([]ds_reporter.IDownStreamReporter{}) err := reporter.RegisterReporters(too_many_reporters) expected_err := errors.New("attempting to register too many reporters") @@ -44,7 +43,7 @@ func TestRegisterTooManyReporters(t *testing.T) { func TestReportWorkflowStart(t *testing.T) { var wg sync.WaitGroup mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) + reporter := New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) mock_time := new(mock_time.MockTime) expectedCommand := cacao.Command{ @@ -123,7 +122,7 @@ func TestReportWorkflowStart(t *testing.T) { func TestReportWorkflowEnd(t *testing.T) { var wg sync.WaitGroup mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) + reporter := New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) mock_time := new(mock_time.MockTime) expectedCommand := cacao.Command{ @@ -202,7 +201,7 @@ func TestReportWorkflowEnd(t *testing.T) { func TestReportStepStart(t *testing.T) { var wg sync.WaitGroup mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) + reporter := New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) mock_time := new(mock_time.MockTime) expectedCommand := cacao.Command{ @@ -246,7 +245,7 @@ func TestReportStepStart(t *testing.T) { func TestReportStepEnd(t *testing.T) { var wg sync.WaitGroup mock_ds_reporter := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) + reporter := New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter}) mock_time := new(mock_time.MockTime) expectedCommand := cacao.Command{ @@ -292,7 +291,7 @@ func TestMultipleDownstreamReporters(t *testing.T) { var wg sync.WaitGroup mock_ds_reporter1 := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} mock_ds_reporter2 := mock_reporter.Mock_Downstream_Reporter{Wg: &wg} - reporter := reporter.New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter1, &mock_ds_reporter2}) + reporter := New([]ds_reporter.IDownStreamReporter{&mock_ds_reporter1, &mock_ds_reporter2}) mock_time := new(mock_time.MockTime) expectedCommand := cacao.Command{ diff --git a/makefile b/makefile index 6f2682ea..6f16d9d2 100644 --- a/makefile +++ b/makefile @@ -20,8 +20,12 @@ lint: swagger build: swagger CGO_ENABLED=0 go build -o ./build/soarca $(GOFLAGS) main.go -test: - go test ./test/unittest/... -v +test: swagger + go test ./models/... -v + go test ./internal/... -v + go test ./routes/... -v + go test ./logger/... -v + go test ./database/... -v integration-test: swagger go test ./test/integration/... -v @@ -47,7 +51,7 @@ sbom: CGO_ENABLED=0 GOOS=windows GOARCH=amd64 cyclonedx-gomod app -json -licenses -output bin/${BINARY_NAME}-${VERSION}-windows-amd64.bom.json pre-docker-build: swagger - GOOS=linux GOARCH=amd64 go build -o bin/${BINARY_NAME}-${VERSION}-linux-amd64 $(GOFLAGS) main.go + CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/${BINARY_NAME}-${VERSION}-linux-amd64 $(GOFLAGS) main.go docker: pre-docker-build docker build --no-cache -t soarca:${VERSION} --build-arg="VERSION=${VERSION}" . diff --git a/test/unittest/cacao/variables_test.go b/models/cacao/variables_test.go similarity index 72% rename from test/unittest/cacao/variables_test.go rename to models/cacao/variables_test.go index 987dc8d3..abb00090 100644 --- a/test/unittest/cacao/variables_test.go +++ b/models/cacao/variables_test.go @@ -1,26 +1,25 @@ -package cacao_test +package cacao import ( - "soarca/models/cacao" "testing" "github.com/go-playground/assert/v2" ) func TestNewVariables(t *testing.T) { - variable := cacao.Variable{ + variable := Variable{ Type: "string", Name: "variable 1", Value: "value 1", } - variables := cacao.NewVariables(variable) - expected := cacao.Variables{"variable 1": variable} + variables := NewVariables(variable) + expected := Variables{"variable 1": variable} assert.Equal(t, variables, expected) } func TestVariablesFind(t *testing.T) { - variables := make(cacao.Variables) - inserted := cacao.Variable{ + variables := make(Variables) + inserted := Variable{ Name: "__var0__", Value: "value", } @@ -31,8 +30,8 @@ func TestVariablesFind(t *testing.T) { } func TestVariablesInsertNew(t *testing.T) { - vars := cacao.NewVariables() - inserted := vars.Insert(cacao.Variable{ + vars := NewVariables() + inserted := vars.Insert(Variable{ Name: "__var0__", Value: "value", }) @@ -42,11 +41,11 @@ func TestVariablesInsertNew(t *testing.T) { } func TestVariablesInsertExisting(t *testing.T) { - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "old", }) - inserted := vars.Insert(cacao.Variable{ + inserted := vars.Insert(Variable{ Name: "__var0__", Value: "new", }) @@ -56,11 +55,11 @@ func TestVariablesInsertExisting(t *testing.T) { } func TestVariablesInsertOrReplace(t *testing.T) { - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "old", }) - replaced := vars.InsertOrReplace(cacao.Variable{ + replaced := vars.InsertOrReplace(Variable{ Name: "__var0__", Value: "new", }) @@ -70,14 +69,14 @@ func TestVariablesInsertOrReplace(t *testing.T) { } func TestVariablesInsertRange(t *testing.T) { - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "old", }) - otherRange := cacao.NewVariables(cacao.Variable{ + otherRange := NewVariables(Variable{ Name: "__var0__", Value: "new", - }, cacao.Variable{ + }, Variable{ Name: "__var1__", Value: "new2", }) @@ -88,12 +87,12 @@ func TestVariablesInsertRange(t *testing.T) { } func TestVariablesMerge(t *testing.T) { - base := cacao.NewVariables(cacao.Variable{ + base := NewVariables(Variable{ Name: "__var0__", Value: "OLD", }) - new := cacao.NewVariables(cacao.Variable{ + new := NewVariables(Variable{ Name: "__var1__", Value: "NEW", }) @@ -107,12 +106,12 @@ func TestVariablesMerge(t *testing.T) { } func TestVariablesMergeWithUpdate(t *testing.T) { - base := cacao.NewVariables(cacao.Variable{ + base := NewVariables(Variable{ Name: "__var0__", Value: "OLD", }) - new := cacao.NewVariables(cacao.Variable{ + new := NewVariables(Variable{ Name: "__var0__", Value: "NEW", }) @@ -125,7 +124,7 @@ func TestVariablesMergeWithUpdate(t *testing.T) { func TestVariablesStringInterpolation(t *testing.T) { original := "__var0__:value is __var0__:value" - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", }) @@ -137,7 +136,7 @@ func TestVariablesStringInterpolation(t *testing.T) { func TestVariablesStringInterpolationEmptyString(t *testing.T) { original := "" - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", }) @@ -149,10 +148,10 @@ func TestVariablesStringInterpolationEmptyString(t *testing.T) { func TestVariablesStringInterpolateMultiple(t *testing.T) { original := "__var0__:value is __var1__:value" - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", - }, cacao.Variable{ + }, Variable{ Name: "__var1__", Value: "COOL", }) @@ -164,10 +163,10 @@ func TestVariablesStringInterpolateMultiple(t *testing.T) { func TestVariablesStringInterpolateMultipleAndUnkown(t *testing.T) { original := "__var0__:value is __var1_unknown__:value" - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", - }, cacao.Variable{ + }, Variable{ Name: "__var1__", Value: "COOL", }) @@ -177,31 +176,31 @@ func TestVariablesStringInterpolateMultipleAndUnkown(t *testing.T) { } func TestVariablesSelect(t *testing.T) { - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", - }, cacao.Variable{ + }, Variable{ Name: "__var1__", Value: "COOL", }) filteredVars := vars.Select([]string{"__var0__", "__unknown__"}) - assert.Equal(t, filteredVars, cacao.NewVariables(cacao.Variable{ + assert.Equal(t, filteredVars, NewVariables(Variable{ Name: "__var0__", Value: "GO", })) } func TestInsertIntoEmptyMap(t *testing.T) { - vars := cacao.NewVariables(cacao.Variable{ + vars := NewVariables(Variable{ Name: "__var0__", Value: "GO", - }, cacao.Variable{ + }, Variable{ Name: "__var1__", Value: "COOL", }) - playbook := cacao.NewPlaybook() + playbook := NewPlaybook() playbook.PlaybookVariables.Merge(vars) } diff --git a/models/decoder/cacao.go b/models/decoder/decoder.go similarity index 100% rename from models/decoder/cacao.go rename to models/decoder/decoder.go diff --git a/test/unittest/cacao/cacao_test.go b/models/decoder/decoder_test.go similarity index 98% rename from test/unittest/cacao/cacao_test.go rename to models/decoder/decoder_test.go index 8b0e613d..bb1eb60e 100644 --- a/test/unittest/cacao/cacao_test.go +++ b/models/decoder/decoder_test.go @@ -1,10 +1,9 @@ -package cacao_test +package decoder import ( "fmt" "io" "os" - "soarca/models/decoder" "testing" "time" @@ -16,7 +15,7 @@ import ( // The schemas are CDS01 compatible as they have the following properties renamed: // - "agents" from CDS01 instead of "agent_definitions" from CDS03+ // - "targets" from CDS01 instead of "target_definitions" from CDS03+ -var PB_PATH string = "playbooks/" +var PB_PATH string = "../../test/playbooks/" func getTime(data string) time.Time { res, _ := time.Parse(time.RFC3339, data) @@ -41,7 +40,7 @@ func TestCacaoDecode(t *testing.T) { return } - var workflow = decoder.DecodeValidate(byteValue) + var workflow = DecodeValidate(byteValue) // fmt.Println(workflow) diff --git a/test/unittest/finmodel/finmodel_test.go b/models/fin/finmodel_test.go similarity index 86% rename from test/unittest/finmodel/finmodel_test.go rename to models/fin/finmodel_test.go index b1884544..fe9606e7 100644 --- a/test/unittest/finmodel/finmodel_test.go +++ b/models/fin/finmodel_test.go @@ -1,7 +1,6 @@ -package finmodel_test +package fin import ( - "soarca/models/fin" "testing" "time" @@ -9,9 +8,9 @@ import ( ) func TestFinCommandCreation(t *testing.T) { - command := fin.NewCommand() + command := NewCommand() // Check if set - assert.Equal(t, command.Type, fin.MessageTypeCommand) + assert.Equal(t, command.Type, MessageTypeCommand) assert.Equal(t, command.CommandSubstructure.Context.Timeout, 1) assert.Equal(t, time.Time.IsZero(command.CommandSubstructure.Context.GeneratedOn), true) diff --git a/test/unittest/cacao/validators_test.go b/models/validator/validators_test.go similarity index 86% rename from test/unittest/cacao/validators_test.go rename to models/validator/validators_test.go index dc1d3fae..0a8ce006 100644 --- a/test/unittest/cacao/validators_test.go +++ b/models/validator/validators_test.go @@ -1,4 +1,4 @@ -package cacao_test +package validator import ( "encoding/json" @@ -7,13 +7,14 @@ import ( "io" "os" "soarca/models/cacao" - "soarca/models/validator" "strings" "testing" "github.com/go-playground/assert/v2" ) +var PB_PATH string = "../../test/playbooks/" + func TestNotValidCacaoJsonInvalidAgentTargetType(t *testing.T) { jsonFile, err := os.Open(PB_PATH + "invalid_playbook.json") if err != nil { @@ -22,7 +23,7 @@ func TestNotValidCacaoJsonInvalidAgentTargetType(t *testing.T) { } defer jsonFile.Close() byteValue, _ := io.ReadAll(jsonFile) - errValid := validator.IsValidCacaoJson(byteValue) + errValid := IsValidCacaoJson(byteValue) if errValid == nil { t.Fail() } @@ -41,7 +42,7 @@ func TestValidCacaoJson(t *testing.T) { } defer jsonFile.Close() byteValue, _ := io.ReadAll(jsonFile) - errValidation := validator.IsValidCacaoJson(byteValue) + errValidation := IsValidCacaoJson(byteValue) if errValidation != nil { fmt.Println(err) t.Fail() @@ -62,7 +63,7 @@ func TestValidWorkflow(t *testing.T) { if err := json.Unmarshal(data, &playbook); err != nil { t.Fail() } - errSafeWorkflow := validator.IsSafeCacaoWorkflow(&playbook) + errSafeWorkflow := IsSafeCacaoWorkflow(&playbook) assert.Equal(t, errSafeWorkflow, nil) } @@ -81,7 +82,7 @@ func TestIsSafeCacaoWorkflowFailMissingStep(t *testing.T) { t.Fail() } - errSafeWorkflow := validator.IsSafeCacaoWorkflow(&playbook) + errSafeWorkflow := IsSafeCacaoWorkflow(&playbook) expected := errors.New( "step end--6b23c237-ade8-4d00-9aa1-75999738d558 does not exist") @@ -105,7 +106,7 @@ func TestIsSafeCacaoWorkflowFailInfinite(t *testing.T) { t.Fail() } - errSafeWorkflow := validator.IsSafeCacaoWorkflow(&playbook) + errSafeWorkflow := IsSafeCacaoWorkflow(&playbook) expected := "worflow seems to loop on branch sequence" @@ -127,7 +128,7 @@ func TestIsSafeCacaoWorkflowFailAgentEmail(t *testing.T) { t.Fail() } - errSafeWorkflow := validator.IsSafeCacaoWorkflow(&playbook) + errSafeWorkflow := IsSafeCacaoWorkflow(&playbook) fmt.Println(errSafeWorkflow) expected := "invalid email" @@ -147,7 +148,7 @@ func TestIsSafeCacaoWorkflow(t *testing.T) { if err := json.Unmarshal(data, &playbook); err != nil { t.Fail() } - errSafeWorkflow := validator.IsSafeCacaoWorkflow(&playbook) + errSafeWorkflow := IsSafeCacaoWorkflow(&playbook) assert.Equal(t, errSafeWorkflow, nil) diff --git a/test/unittest/routes/playbook.json b/test/integration/api/routes/playbook.json similarity index 100% rename from test/unittest/routes/playbook.json rename to test/integration/api/routes/playbook.json diff --git a/test/unittest/routes/playbook_api/playbook_api_test.go b/test/integration/api/routes/playbook_api/playbook_api_test.go similarity index 100% rename from test/unittest/routes/playbook_api/playbook_api_test.go rename to test/integration/api/routes/playbook_api/playbook_api_test.go diff --git a/test/unittest/routes/reporter_api/reporter_api_invocation_test.go b/test/integration/api/routes/reporter_api/reporter_api_invocation_test.go similarity index 100% rename from test/unittest/routes/reporter_api/reporter_api_invocation_test.go rename to test/integration/api/routes/reporter_api/reporter_api_invocation_test.go diff --git a/test/unittest/routes/reporter_api/reporter_api_test.go b/test/integration/api/routes/reporter_api/reporter_api_test.go similarity index 100% rename from test/unittest/routes/reporter_api/reporter_api_test.go rename to test/integration/api/routes/reporter_api/reporter_api_test.go diff --git a/test/unittest/routes/trigger_api/tigger_api_test.go b/test/integration/api/routes/trigger_api/tigger_api_test.go similarity index 100% rename from test/unittest/routes/trigger_api/tigger_api_test.go rename to test/integration/api/routes/trigger_api/tigger_api_test.go diff --git a/test/unittest/logger/log_test.go b/test/manual/logger/log_test.go similarity index 100% rename from test/unittest/logger/log_test.go rename to test/manual/logger/log_test.go diff --git a/test/unittest/cacao/playbooks/changed-playbook.json b/test/playbooks/changed-playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/changed-playbook.json rename to test/playbooks/changed-playbook.json diff --git a/test/unittest/cacao/playbooks/infinite_playbook.json b/test/playbooks/infinite_playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/infinite_playbook.json rename to test/playbooks/infinite_playbook.json diff --git a/test/unittest/cacao/playbooks/invalid_email_playbook.json b/test/playbooks/invalid_email_playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/invalid_email_playbook.json rename to test/playbooks/invalid_email_playbook.json diff --git a/test/unittest/cacao/playbooks/invalid_playbook.json b/test/playbooks/invalid_playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/invalid_playbook.json rename to test/playbooks/invalid_playbook.json diff --git a/test/unittest/cacao/playbooks/missing_step_playbook.json b/test/playbooks/missing_step_playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/missing_step_playbook.json rename to test/playbooks/missing_step_playbook.json diff --git a/test/unittest/cacao/playbooks/parallels_playbook.json b/test/playbooks/parallels_playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/parallels_playbook.json rename to test/playbooks/parallels_playbook.json diff --git a/test/unittest/cacao/playbooks/playbook.json b/test/playbooks/playbook.json similarity index 100% rename from test/unittest/cacao/playbooks/playbook.json rename to test/playbooks/playbook.json diff --git a/test/unittest/utils/http/http_test.go b/utils/http/http_test.go similarity index 92% rename from test/unittest/utils/http/http_test.go rename to utils/http/http_test.go index cc0d2a00..449d8714 100644 --- a/test/unittest/utils/http/http_test.go +++ b/utils/http/http_test.go @@ -1,4 +1,4 @@ -package ssh_test +package http import ( "encoding/base64" @@ -9,7 +9,6 @@ import ( b64 "encoding/base64" "soarca/models/cacao" - http "soarca/utils/http" "github.com/go-playground/assert/v2" ) @@ -36,7 +35,7 @@ type httpBinResponseBody struct { // Test general http options, we do not check responses body, as these are variable for the general connection tests func TestHttpGetConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ @@ -48,7 +47,7 @@ func TestHttpGetConnection(t *testing.T) { Command: "GET / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -64,7 +63,7 @@ func TestHttpGetConnection(t *testing.T) { } func TestHttpPostConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ @@ -76,7 +75,7 @@ func TestHttpPostConnection(t *testing.T) { Command: "POST / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -92,7 +91,7 @@ func TestHttpPostConnection(t *testing.T) { } func TestHttpPutConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ "url": {"https://httpbin.org/put"}, @@ -103,7 +102,7 @@ func TestHttpPutConnection(t *testing.T) { Command: "PUT / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -118,7 +117,7 @@ func TestHttpPutConnection(t *testing.T) { } func TestHttpDeleteConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ "url": {"https://httpbin.org/delete"}, @@ -129,7 +128,7 @@ func TestHttpDeleteConnection(t *testing.T) { Command: "DELETE / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -146,7 +145,7 @@ func TestHttpDeleteConnection(t *testing.T) { // test status codes handling func TestHttpStatus200(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ "url": {"https://httpbin.org/status/200"}, @@ -157,7 +156,7 @@ func TestHttpStatus200(t *testing.T) { Command: "GET / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -172,7 +171,7 @@ func TestHttpStatus200(t *testing.T) { func TestHttpBearerToken(t *testing.T) { bearerToken := "test_token" - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ @@ -190,7 +189,7 @@ func TestHttpBearerToken(t *testing.T) { Command: "GET / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, Auth: &auth, @@ -217,7 +216,7 @@ func TestHttpBasicAuth(t *testing.T) { user_id := "test" password := "password" url := fmt.Sprintf("https://httpbin.org/basic-auth/%s/%s", user_id, password) - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} target := cacao.AgentTarget{ Address: map[cacao.NetAddressType][]string{ @@ -238,7 +237,7 @@ func TestHttpBasicAuth(t *testing.T) { Command: "GET / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, Auth: &auth, @@ -262,7 +261,7 @@ func TestHttpBasicAuth(t *testing.T) { } func TestHttpPostWithContentConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} testJsonObj := testJson{Id: "28818819", User: "test", Description: "very interesting description"} requestBody, err := json.Marshal(testJsonObj) @@ -286,7 +285,7 @@ func TestHttpPostWithContentConnection(t *testing.T) { Headers: map[string][]string{"accept": {"application/json"}}, Content: body, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -308,7 +307,7 @@ func TestHttpPostWithContentConnection(t *testing.T) { } func TestHttpPostWithBase64ContentConnection(t *testing.T) { - httpRequest := http.HttpRequest{} + httpRequest := HttpRequest{} testJsonObj := testJson{Id: "28818819", User: "test", Description: "very interesting description"} requestBody, err := json.Marshal(testJsonObj) @@ -332,7 +331,7 @@ func TestHttpPostWithBase64ContentConnection(t *testing.T) { Headers: map[string][]string{"accept": {"application/json"}}, ContentB64: base64EncodedBody, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Command: &command, Target: &target, } @@ -368,7 +367,7 @@ func TestHttpPathDnameParser(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -390,7 +389,7 @@ func TestHttpPathDnamePortParser(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -412,7 +411,7 @@ func TestHttpPathDnameRandomPortParser(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -434,7 +433,7 @@ func TestHttpPathIpv4Parser(t *testing.T) { Command: "POST / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -458,7 +457,7 @@ func TestHttpPathParser(t *testing.T) { Command: "POST / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -482,7 +481,7 @@ func TestHttpPathUrlComposition(t *testing.T) { Command: "POST /isp/cst HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -508,7 +507,7 @@ func TestHttpPathBreakingParser(t *testing.T) { Command: "POST / HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -526,7 +525,7 @@ func TestMethodExtract(t *testing.T) { Command: "POST /api1/newObject HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - method, err := http.GetMethodFrom(&command) + method, err := GetMethodFrom(&command) if err != nil { t.Error("failed test because: ", err) } @@ -539,7 +538,7 @@ func TestPathExtract(t *testing.T) { Command: "POST /api1/newObject HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - path, err := http.GetPathFrom(&command) + path, err := GetPathFrom(&command) if err != nil { t.Error("failed test because: ", err) } @@ -552,7 +551,7 @@ func TestVersionExtract(t *testing.T) { Command: "POST /api1/newObject HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - version, err := http.GetVersionFrom(&command) + version, err := GetVersionFrom(&command) if err != nil { t.Error("failed test because: ", err) } @@ -565,7 +564,7 @@ func TestCommandFailedExtract(t *testing.T) { Command: "POST /api1/newObject", Headers: map[string][]string{"accept": {"application/json"}}, } - version, err := http.GetVersionFrom(&command) + version, err := GetVersionFrom(&command) if err == nil { t.Error("should give error as only 2 values are provided") } @@ -582,7 +581,7 @@ func TestDnameWithInvalidPathParser(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -604,7 +603,7 @@ func TestHttpPathIpv4WithRandomPort(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -626,7 +625,7 @@ func TestInvalidDname(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } @@ -649,7 +648,7 @@ func TestInvalidIpv4(t *testing.T) { Command: "POST /url HTTP/1.1", Headers: map[string][]string{"accept": {"application/json"}}, } - httpOptions := http.HttpOptions{ + httpOptions := HttpOptions{ Target: &target, Command: &command, } diff --git a/test/unittest/utils/stix/expression/comparison/comparison_test.go b/utils/stix/expression/comparison/comparison_test.go similarity index 97% rename from test/unittest/utils/stix/expression/comparison/comparison_test.go rename to utils/stix/expression/comparison/comparison_test.go index ef4b9591..f9d99adf 100644 --- a/test/unittest/utils/stix/expression/comparison/comparison_test.go +++ b/utils/stix/expression/comparison/comparison_test.go @@ -1,9 +1,8 @@ -package comparison_test +package comparison import ( "errors" "soarca/models/cacao" - "soarca/utils/stix/expression/comparison" "testing" "github.com/go-playground/assert/v2" @@ -11,7 +10,7 @@ import ( func TestStringEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeString} var1.Value = "a" @@ -55,7 +54,7 @@ func TestStringEquals(t *testing.T) { } func TestIntEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeLong} var1.Value = "1000" @@ -102,7 +101,7 @@ func TestIntEquals(t *testing.T) { } func TestFloatEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeFloat} var1.Value = "1000.0" @@ -158,7 +157,7 @@ func TestFloatEquals(t *testing.T) { } func TestIp4AddressEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeIpv4Address} var1.Value = "10.0.0.30" var1.Name = "__var1__" @@ -182,7 +181,7 @@ func TestIp4AddressEquals(t *testing.T) { } func TestIp6AddressEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeIpv6Address} var1.Value = "2001:db8::1" var1.Name = "__var1__" @@ -206,7 +205,7 @@ func TestIp6AddressEquals(t *testing.T) { } func TestMacAddressEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeMacAddress} var1.Value = "BC-24-11-00-00-01" var1.Name = "__var1__" @@ -240,7 +239,7 @@ func TestMacAddressEquals(t *testing.T) { } func TestHashEquals(t *testing.T) { - stix := comparison.New() + stix := New() md5 := cacao.Variable{Type: cacao.VariableTypeMd5Has} md5.Value = "d41d8cd98f00b204e9800998ecf8427e" md5.Name = "__md5__" @@ -294,7 +293,7 @@ func TestHashEquals(t *testing.T) { } func TestUriEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeUri} var1.Value = "https://google.com" @@ -316,7 +315,7 @@ func TestUriEquals(t *testing.T) { } func TestUuidEquals(t *testing.T) { - stix := comparison.New() + stix := New() var1 := cacao.Variable{Type: cacao.VariableTypeUuid} var1.Value = "ec887691-9a21-4ccf-8fae-360c13a819d1"