From ea9f3be1c86b328e1d3751736692ab6e3854dda8 Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Tue, 17 Dec 2024 15:24:16 +0100 Subject: [PATCH 1/8] Add create/get/patch case actions --- Sekoia.io/action_create_case.json | 561 ++++++++++++++++++ Sekoia.io/action_get_case.json | 492 +++++++++++++++ Sekoia.io/action_update_case.json | 556 +++++++++++++++++ Sekoia.io/main.py | 6 + .../sekoiaio/operation_center/__init__.py | 16 +- 5 files changed, 1623 insertions(+), 8 deletions(-) create mode 100644 Sekoia.io/action_create_case.json create mode 100644 Sekoia.io/action_get_case.json create mode 100644 Sekoia.io/action_update_case.json diff --git a/Sekoia.io/action_create_case.json b/Sekoia.io/action_create_case.json new file mode 100644 index 000000000..7a0536cd7 --- /dev/null +++ b/Sekoia.io/action_create_case.json @@ -0,0 +1,561 @@ +{ + "arguments": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "title": { + "description": "title of the case", + "type": "string", + "in": "body" + }, + "description": { + "description": "description of the case", + "type": "string", + "in": "body" + }, + "status_uuid": { + "description": "identifier of case’s status", + "type": "string", + "in": "body" + }, + "priority": { + "description": "priority of the case", + "type": "string", + "in": "body", + "enum": [ + "low", + "medium", + "high" + ] + }, + "tags": { + "description": "tags to associate to the case", + "type": "array", + "in": "body", + "items": { + "type": "string" + } + }, + "subscribers": { + "description": "avatars to associate to the case", + "type": "array", + "in": "body", + "items": { + "type": "object", + "properties": { + "avatar_uuid": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "community_uuid": { + "description": "the identifier of the community to which the case is associated", + "type": "string", + "in": "body" + }, + "verdict_uuid": { + "description": "Verdict of the case", + "type": "string", + "in": "body" + }, + "custom_status_uuid": { + "description": "Custom status of the case", + "type": "string", + "in": "body" + }, + "custom_priority_uuid": { + "description": "Custom priority of the case", + "type": "string", + "in": "body" + } + }, + "required": [ + "title", + "description", + "status_uuid", + "priority", + "tags", + "subscribers" + ], + "title": "Arguments", + "type": "object" + }, + "description": "Creates a new case", + "docker_parameters": "create_case", + "name": "Create case", + "results": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "default": "medium", + "description": "low|medium|high" + }, + "status": { + "type": "string" + }, + "status_uuid": { + "type": "string", + "format": "uuid" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "subscribers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "avatar_uuid": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string" + } + }, + "required": [ + "avatar_uuid", + "type" + ] + } + }, + "tags": { + "type": "array", + "description": "List of tags associated to the case", + "items": { + "type": "string" + } + }, + "number_of_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the first case event" + }, + "last_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the last case event" + }, + "manual": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that the case was created manually" + }, + "is_supplied": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that alerts can be automatically added to the case" + }, + "verdict_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the verdict associated to the case" + }, + "verdict": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_status_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the custom status associated to the case" + }, + "custom_status": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_priority_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the priority associated to the case" + }, + "custom_priority": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "color": { + "type": "string" + } + }, + "required": [ + "color", + "description", + "label", + "level" + ] + }, + "number_of_alerts": { + "type": "integer" + }, + "alerts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "title": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "integer" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "entity": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "uuid" + ] + }, + "urgency": { + "description": " The alert urgency can have two different representations in the api: a numerical and a textual representation. | Urgency | Value | | Low | [0-20[ | | Moderate | [20-40[ | | High | [40-60[ | | Major | [60-80[ | | Urgent | [80-100] |", + "type": "object", + "properties": { + "current_value": { + "type": "integer" + }, + "value": { + "type": "integer" + }, + "severity": { + "type": "integer" + }, + "criticity": { + "type": "integer" + }, + "display": { + "type": "string" + } + } + }, + "alert_type": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "category": { + "type": "string" + } + } + }, + "status": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "rule": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "severity": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "name", + "pattern", + "uuid" + ] + }, + "detection_type": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "similar": { + "type": "integer" + }, + "details": { + "type": "string" + }, + "ttps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "adversaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "stix": { + "type": "object" + }, + "kill_chain_short_id": { + "type": "string" + }, + "number_of_unseen_comments": { + "type": "integer" + }, + "number_of_total_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time" + }, + "last_seen_at": { + "type": "string", + "format": "date-time" + }, + "assets": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "time_to_ingest": { + "type": "integer" + }, + "time_to_detect": { + "type": "integer" + }, + "time_to_acknowledge": { + "type": "integer" + }, + "time_to_respond": { + "type": "integer" + }, + "time_to_resolve": { + "type": "integer" + }, + "intake_uuids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "cases": { + "type": "array", + "items": { + "type": "object", + "properties": { + "short_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "is_supplied": { + "type": "boolean" + }, + "manual": { + "type": "boolean" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + }, + "required": [ + "community_uuid", + "created_at", + "created_by", + "created_by_type", + "short_id", + "status", + "status_uuid", + "title", + "uuid" + ] + }, + "uuid": "0ccabc04-43b4-4564-b9b2-08b80e0e1ecf" +} \ No newline at end of file diff --git a/Sekoia.io/action_get_case.json b/Sekoia.io/action_get_case.json new file mode 100644 index 000000000..c61af5939 --- /dev/null +++ b/Sekoia.io/action_get_case.json @@ -0,0 +1,492 @@ +{ + "arguments": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "uuid": { + "description": "UUID of the case", + "type": "string", + "in": "path" + } + }, + "required": [ + "uuid" + ], + "title": "Arguments", + "type": "object" + }, + "description": "Retrieve the properties of a case", + "docker_parameters": "get_case", + "name": "Get case", + "results": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "default": "medium", + "description": "low|medium|high" + }, + "status": { + "type": "string" + }, + "status_uuid": { + "type": "string", + "format": "uuid" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "subscribers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "avatar_uuid": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string" + } + }, + "required": [ + "avatar_uuid", + "type" + ] + } + }, + "tags": { + "type": "array", + "description": "List of tags associated to the case", + "items": { + "type": "string" + } + }, + "number_of_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the first case event" + }, + "last_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the last case event" + }, + "manual": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that the case was created manually" + }, + "is_supplied": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that alerts can be automatically added to the case" + }, + "verdict_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the verdict associated to the case" + }, + "verdict": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_status_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the custom status associated to the case" + }, + "custom_status": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_priority_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the priority associated to the case" + }, + "custom_priority": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "color": { + "type": "string" + } + }, + "required": [ + "color", + "description", + "label", + "level" + ] + }, + "number_of_alerts": { + "type": "integer" + }, + "alerts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "title": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "integer" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "entity": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "uuid" + ] + }, + "urgency": { + "description": " The alert urgency can have two different representations in the api: a numerical and a textual representation. | Urgency | Value | | Low | [0-20[ | | Moderate | [20-40[ | | High | [40-60[ | | Major | [60-80[ | | Urgent | [80-100] |", + "type": "object", + "properties": { + "current_value": { + "type": "integer" + }, + "value": { + "type": "integer" + }, + "severity": { + "type": "integer" + }, + "criticity": { + "type": "integer" + }, + "display": { + "type": "string" + } + } + }, + "alert_type": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "category": { + "type": "string" + } + } + }, + "status": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "rule": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "severity": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "name", + "pattern", + "uuid" + ] + }, + "detection_type": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "similar": { + "type": "integer" + }, + "details": { + "type": "string" + }, + "ttps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "adversaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "stix": { + "type": "object" + }, + "kill_chain_short_id": { + "type": "string" + }, + "number_of_unseen_comments": { + "type": "integer" + }, + "number_of_total_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time" + }, + "last_seen_at": { + "type": "string", + "format": "date-time" + }, + "assets": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "time_to_ingest": { + "type": "integer" + }, + "time_to_detect": { + "type": "integer" + }, + "time_to_acknowledge": { + "type": "integer" + }, + "time_to_respond": { + "type": "integer" + }, + "time_to_resolve": { + "type": "integer" + }, + "intake_uuids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "cases": { + "type": "array", + "items": { + "type": "object", + "properties": { + "short_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "is_supplied": { + "type": "boolean" + }, + "manual": { + "type": "boolean" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + }, + "required": [ + "community_uuid", + "created_at", + "created_by", + "created_by_type", + "short_id", + "status", + "status_uuid", + "title", + "uuid" + ] + }, + "uuid": "0ecabc04-43b4-4564-b9b2-08b80e0e1ecf" +} \ No newline at end of file diff --git a/Sekoia.io/action_update_case.json b/Sekoia.io/action_update_case.json new file mode 100644 index 000000000..a81d2c7e8 --- /dev/null +++ b/Sekoia.io/action_update_case.json @@ -0,0 +1,556 @@ +{ + "arguments": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "uuid": { + "description": "UUID of the case", + "type": "string", + "in": "path" + }, + "title": { + "description": "title of the case", + "type": "string", + "in": "body" + }, + "description": { + "description": "description of the case", + "type": "string", + "in": "body" + }, + "status_uuid": { + "description": "identifier of case’s status", + "type": "string", + "in": "body" + }, + "priority": { + "description": "priority of the case", + "type": "string", + "in": "body", + "enum": [ + "low", + "medium", + "high" + ] + }, + "tags": { + "description": "tags to associate to the case", + "type": "array", + "in": "body", + "items": { + "type": "string" + } + }, + "subscribers": { + "description": "avatars to associate to the case", + "type": "array", + "in": "body", + "items": { + "type": "object", + "properties": { + "avatar_uuid": { + "type": "string" + }, + "type": { + "type": "string" + } + } + } + }, + "verdict_uuid": { + "description": "Verdict of the case", + "type": "string", + "in": "body" + }, + "custom_status_uuid": { + "description": "Custom status of the case", + "type": "string", + "in": "body" + }, + "custom_priority_uuid": { + "description": "Custom priority of the case", + "type": "string", + "in": "body" + } + }, + "required": [ + "uuid" + ], + "title": "Arguments", + "type": "object" + }, + "description": "Edit the properties of a case", + "docker_parameters": "update_case", + "name": "Edit case", + "results": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "priority": { + "default": "medium", + "description": "low|medium|high" + }, + "status": { + "type": "string" + }, + "status_uuid": { + "type": "string", + "format": "uuid" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "subscribers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "avatar_uuid": { + "type": "string", + "format": "uuid" + }, + "type": { + "type": "string" + } + }, + "required": [ + "avatar_uuid", + "type" + ] + } + }, + "tags": { + "type": "array", + "description": "List of tags associated to the case", + "items": { + "type": "string" + } + }, + "number_of_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the first case event" + }, + "last_seen_at": { + "type": "string", + "format": "date-time", + "x-nullable": true, + "description": "Date and time of the last case event" + }, + "manual": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that the case was created manually" + }, + "is_supplied": { + "type": "boolean", + "x-nullable": true, + "description": "if True, indicates that alerts can be automatically added to the case" + }, + "verdict_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the verdict associated to the case" + }, + "verdict": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_status_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the custom status associated to the case" + }, + "custom_status": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "stage": { + "type": "string" + } + }, + "required": [ + "description", + "label", + "level", + "stage" + ] + }, + "custom_priority_uuid": { + "type": "string", + "format": "uuid", + "x-nullable": true, + "description": "UUID of the priority associated to the case" + }, + "custom_priority": { + "x-nullable": true, + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "label": { + "type": "string" + }, + "level": { + "type": "integer" + }, + "color": { + "type": "string" + } + }, + "required": [ + "color", + "description", + "label", + "level" + ] + }, + "number_of_alerts": { + "type": "integer" + }, + "alerts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "title": { + "type": "string" + }, + "created_at": { + "type": "integer" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "integer" + }, + "updated_by": { + "type": "string" + }, + "updated_by_type": { + "type": "string" + }, + "community_uuid": { + "type": "string", + "format": "uuid" + }, + "short_id": { + "type": "string" + }, + "entity": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name", + "uuid" + ] + }, + "urgency": { + "description": " The alert urgency can have two different representations in the api: a numerical and a textual representation. | Urgency | Value | | Low | [0-20[ | | Moderate | [20-40[ | | High | [40-60[ | | Major | [60-80[ | | Urgent | [80-100] |", + "type": "object", + "properties": { + "current_value": { + "type": "integer" + }, + "value": { + "type": "integer" + }, + "severity": { + "type": "integer" + }, + "criticity": { + "type": "integer" + }, + "display": { + "type": "string" + } + } + }, + "alert_type": { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "category": { + "type": "string" + } + } + }, + "status": { + "type": "object", + "properties": { + "uuid": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + } + }, + "rule": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string" + }, + "severity": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "pattern": { + "type": "string" + } + }, + "required": [ + "name", + "pattern", + "uuid" + ] + }, + "detection_type": { + "type": "string" + }, + "source": { + "type": "string" + }, + "target": { + "type": "string" + }, + "similar": { + "type": "integer" + }, + "details": { + "type": "string" + }, + "ttps": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "adversaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "id", + "name", + "type" + ] + } + }, + "stix": { + "type": "object" + }, + "kill_chain_short_id": { + "type": "string" + }, + "number_of_unseen_comments": { + "type": "integer" + }, + "number_of_total_comments": { + "type": "integer" + }, + "first_seen_at": { + "type": "string", + "format": "date-time" + }, + "last_seen_at": { + "type": "string", + "format": "date-time" + }, + "assets": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "time_to_ingest": { + "type": "integer" + }, + "time_to_detect": { + "type": "integer" + }, + "time_to_acknowledge": { + "type": "integer" + }, + "time_to_respond": { + "type": "integer" + }, + "time_to_resolve": { + "type": "integer" + }, + "intake_uuids": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + }, + "cases": { + "type": "array", + "items": { + "type": "object", + "properties": { + "short_id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "is_supplied": { + "type": "boolean" + }, + "manual": { + "type": "boolean" + }, + "status": { + "type": "string" + } + } + } + } + } + } + } + }, + "required": [ + "community_uuid", + "created_at", + "created_by", + "created_by_type", + "short_id", + "status", + "status_uuid", + "title", + "uuid" + ] + }, + "uuid": "0dcabc04-43b4-4564-b9b2-08b80e0e1ecf" +} \ No newline at end of file diff --git a/Sekoia.io/main.py b/Sekoia.io/main.py index 594a03a41..33fce9e25 100644 --- a/Sekoia.io/main.py +++ b/Sekoia.io/main.py @@ -40,6 +40,9 @@ GetIntake, GetEntity, AddEventsToACase, + CreateCase, + UpdatesCase, + GetCase, ) from sekoiaio.operation_center.get_asset import GetAsset from sekoiaio.operation_center.get_aggregation_query import GetAggregationQuery @@ -104,6 +107,9 @@ module.register(GetEntity, "get-entities/{uuid}") module.register(GetCommunity, "get-communities/{uuid}") module.register(AddEventsToACase, "add_events_to_a_case") + module.register(CreateCase, "create_case") + module.register(UpdateCase, "update_case") + module.register(GetCase, "get_case") # Operation Center Triggers module.register(SecurityAlertsTrigger, "security_alerts_trigger") diff --git a/Sekoia.io/sekoiaio/operation_center/__init__.py b/Sekoia.io/sekoiaio/operation_center/__init__.py index 8d6b7da84..b8d9bfc85 100644 --- a/Sekoia.io/sekoiaio/operation_center/__init__.py +++ b/Sekoia.io/sekoiaio/operation_center/__init__.py @@ -147,13 +147,13 @@ }, ) -CreatesNewCase = type( - "CreatesNewCase", +CreateCase = type( + "CreateCase", (GenericAPIAction,), { "verb": "post", "endpoint": base_url + "cases", - "query_parameters": ["tags", "subscribers"], + "query_parameters": [], }, ) @@ -194,18 +194,18 @@ (GenericAPIAction,), { "verb": "get", - "endpoint": base_url + "cases/{case_uuid}", + "endpoint": base_url + "cases/{uuid}", "query_parameters": ["community_uuid"], }, ) -UpdatesCase = type( - "UpdatesCase", +UpdateCase = type( + "UpdateCase", (GenericAPIAction,), { "verb": "patch", - "endpoint": base_url + "cases/{case_uuid}", - "query_parameters": ["tags", "subscribers"], + "endpoint": base_url + "cases/{uuid}", + "query_parameters": [], }, ) From 6ae1a2b0ddac56e81b47aedbf7b5de8eb4c237ea Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Tue, 17 Dec 2024 16:22:00 +0100 Subject: [PATCH 2/8] add post_comment_on_case action --- .../action_post_a_comment_on_a_case.json | 58 +++++++++++++++++++ Sekoia.io/main.py | 2 + .../sekoiaio/operation_center/__init__.py | 6 +- 3 files changed, 63 insertions(+), 3 deletions(-) create mode 100644 Sekoia.io/action_post_a_comment_on_a_case.json diff --git a/Sekoia.io/action_post_a_comment_on_a_case.json b/Sekoia.io/action_post_a_comment_on_a_case.json new file mode 100644 index 000000000..388f500ea --- /dev/null +++ b/Sekoia.io/action_post_a_comment_on_a_case.json @@ -0,0 +1,58 @@ +{ + "arguments": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "uuid": { + "description": "UUID of the case", + "type": "string", + "in": "path" + }, + "content": { + "type": "string", + "description": "Content of the comment", + "in": "body" + } + }, + "required": [ + "uuid", + "content" + ], + "title": "Arguments", + "type": "object" + }, + "description": "Add a new comment to a case", + "docker_parameters": "post_comment_to_a_case", + "name": "Comment case", + "results": { + "type": "object", + "properties": { + "uuid": { + "type": "string", + "format": "uuid" + }, + "content": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "created_by": { + "type": "string" + }, + "created_by_type": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + }, + "required": [ + "content", + "created_at", + "created_by", + "created_by_type", + "uuid" + ] + }, + "uuid": "0fcabc04-43b4-4564-b9b2-08b80e0e1ecf" +} \ No newline at end of file diff --git a/Sekoia.io/main.py b/Sekoia.io/main.py index 33fce9e25..928db2987 100644 --- a/Sekoia.io/main.py +++ b/Sekoia.io/main.py @@ -43,6 +43,7 @@ CreateCase, UpdatesCase, GetCase, + PostCommentOnCase, ) from sekoiaio.operation_center.get_asset import GetAsset from sekoiaio.operation_center.get_aggregation_query import GetAggregationQuery @@ -110,6 +111,7 @@ module.register(CreateCase, "create_case") module.register(UpdateCase, "update_case") module.register(GetCase, "get_case") + module.register(PostCommentOnCase, "post_comment_to_a_case") # Operation Center Triggers module.register(SecurityAlertsTrigger, "security_alerts_trigger") diff --git a/Sekoia.io/sekoiaio/operation_center/__init__.py b/Sekoia.io/sekoiaio/operation_center/__init__.py index b8d9bfc85..985695d92 100644 --- a/Sekoia.io/sekoiaio/operation_center/__init__.py +++ b/Sekoia.io/sekoiaio/operation_center/__init__.py @@ -240,12 +240,12 @@ }, ) -CreateNewCommentOnCase = type( - "CreateNewCommentOnCase", +PostCommentOnCase = type( + "PostCommentOnCase", (GenericAPIAction,), { "verb": "post", - "endpoint": base_url + "cases/{case_uuid}/comments", + "endpoint": base_url + "cases/{uuid}/comments", "query_parameters": [], }, ) From 0239277f46c92e4fff5c2910328b56697915dfad Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 09:19:40 +0100 Subject: [PATCH 3/8] Add community_uuid parameter for get_case action --- Sekoia.io/action_get_case.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sekoia.io/action_get_case.json b/Sekoia.io/action_get_case.json index c61af5939..4a340654e 100644 --- a/Sekoia.io/action_get_case.json +++ b/Sekoia.io/action_get_case.json @@ -6,6 +6,11 @@ "description": "UUID of the case", "type": "string", "in": "path" + }, + "community_uuid": { + "description": "(Optional) Identifier of the community", + "type": "string", + "in": "query" } }, "required": [ From 98b3b818412043cccfdb04fcb5f43fa833fc7cbb Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 11:05:43 +0100 Subject: [PATCH 4/8] update changelog & version --- Sekoia.io/CHANGELOG.md | 8 ++++++++ Sekoia.io/manifest.json | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Sekoia.io/CHANGELOG.md b/Sekoia.io/CHANGELOG.md index dd89188e4..04cd0754a 100644 --- a/Sekoia.io/CHANGELOG.md +++ b/Sekoia.io/CHANGELOG.md @@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## Unreleased + +## 2024-12-18 - 2.67.0 + +- Add an action to create a case +- Add an action to modify a case +- Add an action to get the details of a case +- Add an action to add a comment to a case + ## 2024-12-09 - 2.66.2 ### Changed diff --git a/Sekoia.io/manifest.json b/Sekoia.io/manifest.json index d94e70176..8ce1bf8e2 100644 --- a/Sekoia.io/manifest.json +++ b/Sekoia.io/manifest.json @@ -12,7 +12,7 @@ "name": "Sekoia.io", "uuid": "92d8bb47-7c51-445d-81de-ae04edbb6f0a", "slug": "sekoia.io", - "version": "2.66.2", + "version": "2.67.0", "categories": [ "Generic" ] From 03a6fa56bb17876953f305371605c0dee55eb6d8 Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 11:36:10 +0100 Subject: [PATCH 5/8] fix changelog --- Sekoia.io/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sekoia.io/CHANGELOG.md b/Sekoia.io/CHANGELOG.md index 04cd0754a..ea93cce65 100644 --- a/Sekoia.io/CHANGELOG.md +++ b/Sekoia.io/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2024-12-18 - 2.67.0 +### Added + - Add an action to create a case - Add an action to modify a case - Add an action to get the details of a case From 5c52c88f3af739c9f7a0a6e538a7b066066f64f7 Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 11:39:33 +0100 Subject: [PATCH 6/8] fix typo --- Sekoia.io/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sekoia.io/main.py b/Sekoia.io/main.py index 928db2987..8207bde52 100644 --- a/Sekoia.io/main.py +++ b/Sekoia.io/main.py @@ -41,7 +41,7 @@ GetEntity, AddEventsToACase, CreateCase, - UpdatesCase, + UpdateCase, GetCase, PostCommentOnCase, ) From e6ff0251b3fea7aff8181690fcf69f3c2d18166a Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 11:51:40 +0100 Subject: [PATCH 7/8] fix required parameters for create_case action --- Sekoia.io/action_create_case.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Sekoia.io/action_create_case.json b/Sekoia.io/action_create_case.json index 7a0536cd7..41c45aad8 100644 --- a/Sekoia.io/action_create_case.json +++ b/Sekoia.io/action_create_case.json @@ -73,12 +73,7 @@ } }, "required": [ - "title", - "description", - "status_uuid", - "priority", - "tags", - "subscribers" + "title" ], "title": "Arguments", "type": "object" From 1f04a312557f55077303e4ee778d6393e4b18ddf Mon Sep 17 00:00:00 2001 From: Antoine HEUZE Date: Wed, 18 Dec 2024 12:08:18 +0100 Subject: [PATCH 8/8] add tests --- Sekoia.io/tests/test_operation_center.py | 167 ++++++++++++++++++++++- 1 file changed, 166 insertions(+), 1 deletion(-) diff --git a/Sekoia.io/tests/test_operation_center.py b/Sekoia.io/tests/test_operation_center.py index 36197a0d8..3c4eaa927 100644 --- a/Sekoia.io/tests/test_operation_center.py +++ b/Sekoia.io/tests/test_operation_center.py @@ -3,11 +3,97 @@ import pytest import requests_mock -from sekoiaio.operation_center import GetAlert, ListAlerts, AddEventsToACase +from sekoiaio.operation_center import ( + GetAlert, + ListAlerts, + AddEventsToACase, + CreateCase, + UpdateCase, + GetCase, + PostCommentOnCase, +) module_base_url = "http://fake.url/" base_url = module_base_url + "api/v1/sic/" apikey = "fake_api_key" +case_expected_response = { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "short_id": "string", + "created_at": "string", + "created_by": "string", + "created_by_type": "string", + "updated_at": "string", + "updated_by": "string", + "updated_by_type": "string", + "title": "string", + "description": "string", + "priority": "medium", + "status": "string", + "status_uuid": "5ca52387-a6f7-45c3-a713-856468ffbdd7", + "community_uuid": "e391588b-4c35-45eb-a5af-211fba0cde08", + "subscribers": [{"avatar_uuid": "bed24c33-9044-41b5-96c5-024eb9b0c439", "type": "string"}], + "tags": ["string"], + "number_of_comments": 0, + "first_seen_at": "2019-08-24T14:15:22Z", + "last_seen_at": "2019-08-24T14:15:22Z", + "manual": True, + "is_supplied": True, + "verdict_uuid": "6108af3c-010d-4cae-915e-70c748f0e58e", + "verdict": {"description": "string", "label": "string", "level": 0, "stage": "string"}, + "custom_status_uuid": "c1ccc455-a896-4e7c-8f4d-b99df293a381", + "custom_status": {"description": "string", "label": "string", "level": 0, "stage": "string"}, + "custom_priority_uuid": "f47455f5-1211-4723-9c4e-63d8752ec65f", + "custom_priority": {"description": "string", "label": "string", "level": 0, "color": "string"}, + "number_of_alerts": 0, + "alerts": [ + { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "title": "string", + "created_at": 0, + "created_by": "string", + "created_by_type": "string", + "updated_at": 0, + "updated_by": "string", + "updated_by_type": "string", + "community_uuid": "e391588b-4c35-45eb-a5af-211fba0cde08", + "short_id": "string", + "entity": {"uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", "name": "string"}, + "urgency": {"current_value": 0, "value": 0, "severity": 0, "criticity": 0, "display": "string"}, + "alert_type": {"value": "string", "category": "string"}, + "status": {"uuid": "string", "name": "string", "description": "string"}, + "rule": { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "name": "string", + "severity": 0, + "type": "string", + "pattern": "string", + }, + "detection_type": "string", + "source": "string", + "target": "string", + "similar": 0, + "details": "string", + "ttps": [{"id": "string", "type": "string", "name": "string", "description": "string"}], + "adversaries": [{"id": "string", "type": "string", "name": "string", "description": "string"}], + "stix": {}, + "kill_chain_short_id": "string", + "number_of_unseen_comments": 0, + "number_of_total_comments": 0, + "first_seen_at": "2019-08-24T14:15:22Z", + "last_seen_at": "2019-08-24T14:15:22Z", + "assets": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "time_to_ingest": 0, + "time_to_detect": 0, + "time_to_acknowledge": 0, + "time_to_respond": 0, + "time_to_resolve": 0, + "intake_uuids": ["497f6eca-6276-4993-bfeb-53cbbbba6f08"], + "cases": [ + {"short_id": "string", "name": "string", "is_supplied": True, "manual": True, "status": "string"} + ], + } + ], +} def test_list_alerts_success(): @@ -118,3 +204,82 @@ def test_add_events_to_case(): history = mock.request_history assert history[0].method == "POST" assert url_decoder(history[0].url) == f"{base_url}{ressource}" + + +def test_create_case(): + action: CreateCase = CreateCase() + action.module.configuration = {"base_url": module_base_url, "api_key": apikey} + + ressource = "cases" + + arguments = {"title": "title"} + + with requests_mock.Mocker() as mock: + mock.post(f"{base_url}{ressource}", json=case_expected_response) + + action.run(arguments) + assert mock.call_count == 1 + history = mock.request_history + assert history[0].method == "POST" + assert url_decoder(history[0].url) == f"{base_url}{ressource}" + + +def test_get_case(): + action: GetCase = GetCase() + action.module.configuration = {"base_url": module_base_url, "api_key": apikey} + + ressource = "cases/fake_uuid" + + arguments = {"uuid": "fake_uuid"} + + with requests_mock.Mocker() as mock: + mock.get(f"{base_url}{ressource}", json=case_expected_response) + + action.run(arguments) + assert mock.call_count == 1 + history = mock.request_history + assert history[0].method == "GET" + assert url_decoder(history[0].url) == f"{base_url}{ressource}" + + +def test_update_case(): + action: UpdateCase = UpdateCase() + action.module.configuration = {"base_url": module_base_url, "api_key": apikey} + + ressource = "cases/fake_uuid" + + arguments = {"uuid": "fake_uuid", "title": "title"} + + with requests_mock.Mocker() as mock: + mock.patch(f"{base_url}{ressource}", json=case_expected_response) + + action.run(arguments) + assert mock.call_count == 1 + history = mock.request_history + assert history[0].method == "PATCH" + assert url_decoder(history[0].url) == f"{base_url}{ressource}" + + +def test_post_comment_on_case(): + action: PostCommentOnCase = PostCommentOnCase() + action.module.configuration = {"base_url": module_base_url, "api_key": apikey} + + ressource = "cases/fake_uuid/comments" + expected_response = { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "content": "string", + "created_at": "string", + "created_by": "string", + "created_by_type": "string", + "updated_at": "string", + } + arguments = {"uuid": "fake_uuid", "content": "content"} + + with requests_mock.Mocker() as mock: + mock.post(f"{base_url}{ressource}", json=expected_response) + + action.run(arguments) + assert mock.call_count == 1 + history = mock.request_history + assert history[0].method == "POST" + assert url_decoder(history[0].url) == f"{base_url}{ressource}"