Skip to content

Commit 332d515

Browse files
authored
reporter api (#137)
1 parent 5922b25 commit 332d515

File tree

15 files changed

+1447
-141
lines changed

15 files changed

+1447
-141
lines changed
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
---
2+
title: Reporter API Description
3+
description: >
4+
Descriptions for the Reporter REST API endpoints
5+
categories: [API]
6+
tags: [protocol, http, rest, api]
7+
weight: 2
8+
date: 2024-05-1
9+
---
10+
11+
# Endpoint description
12+
13+
We will use HTTP status codes https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
14+
15+
16+
```plantuml
17+
@startuml
18+
protocol Reporter {
19+
GET /reporter
20+
GET /reporter/{execution-id}
21+
}
22+
@enduml
23+
```
24+
25+
26+
## /reporter
27+
The reporter endpoint is used to fetch information about ongoing playbook executions in SOARCA
28+
29+
### GET `/reporter`
30+
Get all execution IDs of currently ongoing executions.
31+
32+
#### Call payload
33+
None
34+
35+
#### Response
36+
200/OK with payload:
37+
38+
```plantuml
39+
@startjson
40+
[
41+
{
42+
"executions": [
43+
{"execution_id" : "1", "playbook_id" : "a", "started" : "<timestamp>", "..." : "..."},
44+
"..."]
45+
}
46+
]
47+
@endjson
48+
```
49+
#### Error
50+
400/BAD REQUEST with payload:
51+
General error
52+
53+
54+
55+
### GET `/reporter/{execution-id}`
56+
Get information about ongoing execution
57+
58+
#### Call payload
59+
None
60+
61+
#### Response
62+
63+
Response data model:
64+
65+
66+
|field |content |type | description |
67+
| ----------------- | --------------------- | ----------------- | ----------- |
68+
|type |"execution_status" |string |The type of this content
69+
|id |UUID |string |The id of the execution
70+
|execution_id |UUID |string |The id of the execution
71+
|playbook_id |UUID |string |The id of the CACAO playbook executed by the execution
72+
|started |timestamp |string |The time at which the execution of the playbook started
73+
|ended |timestamp |string |The time at which the execution of the playbook ended (if so)
74+
|status |execution-status-enum |string |The current [status](#execution-stataus) of the execution
75+
|status_text |explanation |string |A natural language explanation of the current status or related info
76+
|step_results |step_results |dictionary |Map of step-id to related [step execution data](#step-execution-data)
77+
|request_interval |seconds |integer |Suggests the polling interval for the next request (default suggested is 5 seconds).
78+
79+
80+
##### Step execution data
81+
|field |content |type | description |
82+
| ----------------- | --------------------- | ----------------- | ----------- |
83+
|step_id |UUID |string |The id of the step being executed
84+
|started |timestamp |string |The time at which the execution of the step started
85+
|ended |timestamp |string |The time at which the execution of the step ended (if so)
86+
|status |execution-status-enum |string |The current [status](#execution-stataus) of the execution of this step
87+
|status_text |explanation |string |A natural language explanation of the current status or related info
88+
|executed_by |entity-identifier |string |The entity executed the workflow step. This can be an organization, a team, a role, a defence component, etc.
89+
|commands_b64 |list of base64 |list of string |A list of Base64 encodings of the commands that were invoked during the execution of a workflow step, including any values stemming from variables. These are the actual commands executed.
90+
|error |error |string |Error raised along the execution of the step
91+
|variables |cacao variables |dictionary |Map of [cacao variables](https://docs.oasis-open.org/cacao/security-playbooks/v2.0/cs01/security-playbooks-v2.0-cs01.html#_Toc152256555) handled in the step (both in and out) with current values and definitions
92+
|automated_execution | boolean |string |This property identifies if the workflow step was executed manually or automatically. It is either true or false.
93+
94+
##### Execution stataus
95+
Table from [Cyentific RNI workflow Status](https://github.com/cyentific-rni/workflow-status/blob/main/README.md#21-refined-execution-status-enumeration)
96+
**Vocabulary Name:** `execution-status-enum`
97+
| Property Name | Description|
98+
| :--- | :--- |
99+
| successfully_executed | The workflow step was executed successfully (completed). |
100+
|failed| The workflow step failed. |
101+
|ongoing| The workflow step is in progress. |
102+
|server_side_error| A server-side error occurred. |
103+
|client_side_error| A client-side error occurred.|
104+
|timeout_error| A timeout error occurred. The timeout of a CACAO workflow step is specified in the “timeout” property. |
105+
|exception_condition_error| A exception condition error ocurred. A CACAO playbook can incorporate an exception condition at the playbook level and, in particular, with the "workflow_exception" property. |
106+
107+
108+
If the execution has completed and no further steps need to be executed
109+
110+
200/OK
111+
with payload:
112+
113+
```plantuml
114+
@startjson
115+
[
116+
{
117+
"type" : "execution-status",
118+
"id" : "<execution-id>",
119+
"execution_id" : "<execution-id>",
120+
"playbook_id" : "<playbook-id>",
121+
"started" : "<time-string>",
122+
"ended" : "<time-string>",
123+
"status" : "<status-enum-value>",
124+
"status_text": "<status description>",
125+
"errors" : ["error1", "..."],
126+
"step_results" : {
127+
"<step-id-1>" : {
128+
"execution_id": "<execution-id>",
129+
"step_id" : "<step-id>",
130+
"started" : "<time-string>",
131+
"ended" : "<time-string>",
132+
"status" : "<status-enum-value>",
133+
"status_text": "<status description>",
134+
"errors" : ["error1", "..."],
135+
"variables": {
136+
"<variable-name-1>" : {
137+
"type": "<type>",
138+
"name": "<variable-name>",
139+
"description": "<description>",
140+
"value": "<value>",
141+
"constant": "<true/false>",
142+
"external": "<true/false>"
143+
}
144+
}
145+
}
146+
},
147+
"request_interval" : "<n-seconds>"
148+
}
149+
]
150+
@endjson
151+
152+
The payload will include all information that the finished execution has created.
153+
154+
155+
If the execution is still ongoing:
156+
157+
206/Partial Content
158+
with payload equal to the 200 response, but impliclty not including all information from the execution, since the execution is still ongoing.
159+
160+
The step results object will list the steps that have been executed until the report request, and those that are being executed at the moment of the report request.
161+
162+
The "request_interval" suggests the polling interval for the next request (default suggested is 5 seconds).
163+
164+
#### Error
165+
400/BAD REQUEST with payload:
166+
General error
167+
168+
404/NOT FOUND
169+
No execution with the specified ID was found.
170+
171+

internal/controller/controller.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@ import (
2020
"soarca/internal/fin/protocol"
2121
"soarca/internal/guid"
2222
"soarca/internal/reporter"
23+
cache "soarca/internal/reporter/downstream_reporter/cache"
2324
"soarca/logger"
2425
"soarca/utils"
2526
httpUtil "soarca/utils/http"
2627
"soarca/utils/stix/expression/comparison"
28+
timeUtil "soarca/utils/time"
2729

2830
downstreamReporter "soarca/internal/reporter/downstream_reporter"
2931

3032
"github.com/gin-gonic/gin"
3133

3234
mongo "soarca/database/mongodb"
3335
playbookrepository "soarca/database/playbook"
34-
routes "soarca/routes"
36+
"soarca/routes"
3537
)
3638

3739
var log *logger.Log
@@ -49,6 +51,10 @@ type Controller struct {
4951

5052
var mainController = Controller{}
5153

54+
var mainCache = cache.Cache{}
55+
56+
const defaultCacheSize int = 10
57+
5258
func (controller *Controller) NewDecomposer() decomposer.IDecomposer {
5359
ssh := new(ssh.SshCapability)
5460
capabilities := map[string]capability.ICapability{ssh.GetType(): ssh}
@@ -76,7 +82,13 @@ func (controller *Controller) NewDecomposer() decomposer.IDecomposer {
7682
}
7783
}
7884

85+
// NOTE: Enrolling mainCache by default as reporter
7986
reporter := reporter.New([]downstreamReporter.IDownStreamReporter{})
87+
downstreamReporters := []downstreamReporter.IDownStreamReporter{&mainCache}
88+
err := reporter.RegisterReporters(downstreamReporters)
89+
if err != nil {
90+
log.Error("could not load main Cache as reporter for decomposer and executors")
91+
}
8092

8193
actionExecutor := action.New(capabilities, reporter)
8294
playbookActionExecutor := playbook_action.New(controller, controller, reporter)
@@ -129,6 +141,9 @@ func Initialize() error {
129141
}
130142
}
131143

144+
cacheSize, _ := strconv.Atoi(utils.GetEnv("MAX_EXECUTIONS", strconv.Itoa(defaultCacheSize)))
145+
mainCache = *cache.New(&timeUtil.Time{}, cacheSize)
146+
132147
errCore := initializeCore(app)
133148

134149
if errCore != nil {
@@ -171,6 +186,14 @@ func initializeCore(app *gin.Engine) error {
171186
}
172187
}
173188

189+
// NOTE: Assuming that the cache is the main information mediator for
190+
// the reporter API
191+
err = routes.Reporter(app, &mainCache)
192+
if err != nil {
193+
log.Error(err)
194+
return err
195+
}
196+
174197
routes.Logging(app)
175198
routes.Swagger(app)
176199

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package informer
2+
3+
import (
4+
"soarca/models/cache"
5+
6+
"github.com/google/uuid"
7+
)
8+
9+
type IExecutionInformer interface {
10+
GetExecutions() ([]cache.ExecutionEntry, error)
11+
GetExecutionReport(executionKey uuid.UUID) (cache.ExecutionEntry, error)
12+
}

0 commit comments

Comments
 (0)