Gem
Use Gem alerts as a trigger for Cortex XSOAR’s custom playbooks, to automate response to specific TTPs.
Cloud Services · Gem
Details
| ID | Gem |
|---|---|
| Provider | Wiz |
| Category | Cloud Services |
| From Version | 6.12.0 |
| Docker Image | demisto/auth-utils:1.0.0.10133006 |
| Supported Modules | Agentix XSIAM |
README
Use Gem alerts as a trigger for Cortex XSOAR’s custom playbooks, to automate response to specific TTPs.
Configure Gem in Cortex
| Parameter | Description | Required |
|---|---|---|
| Incident type | False | |
| API Endpoint | The API endpoint to use for connection (US or EU) | True |
| Service Account ID | The Service Account ID to use for connection | True |
| Service Account Secret | The Service Account Secret to use for connection | True |
| First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days) | False | |
| Use system proxy settings | False | |
| Trust any certificate (not secure) | False | |
| Fetch incidents | False | |
| Maximum number of alerts per fetch | False |
Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
gem-list-threats
List all threats detected in Gem.
Base Command
gem-list-threats
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The number of alert to fetch. Default is 50. | Optional |
| time_start | The start time of the threats to return in ISO format. Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| time_end | The end time of the threats to return in ISO format. Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| ordering | The ordering of the items. Possible values are: -timeframe_start, timeframe_state, -mitre_technique, mitre_technique, -severity, severity, -assignee, assignee, -is_resolved, is_resolved. Default is -timeframe_start. | Optional |
| status | The status of the threats to return. Possible values are: open, resolved, in_progress. | Optional |
| ttp_id | The TTP ID of the threats to return. | Optional |
| title | The title of the threats to return. | Optional |
| severity | The severity of the threats to return. Possible values are: low, medium, high. | Optional |
| cloud_provider | The provider of the threats to return. Possible values are: aws, azure, gcp, okta, huawei. | Optional |
| entity_type | The entity type of the threats to return. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.ThreatsList.accounts.account_status | String | Indicates the current status of the account (e.g., active, suspended). |
| Gem.ThreatsList.accounts.cloud_provider | String | Specifies the cloud service provider for the account (e.g., AWS, Azure). |
| Gem.ThreatsList.accounts.display_name | String | The display name associated with the account. |
| Gem.ThreatsList.accounts.hierarchy_path.id | String | Unique identifier within the account hierarchy path. |
| Gem.ThreatsList.accounts.hierarchy_path.name | String | Name designation within the account hierarchy path. |
| Gem.ThreatsList.accounts.id | Number | The unique numerical identifier for the account. |
| Gem.ThreatsList.accounts.identifier | String | An alternative identifier for the account. |
| Gem.ThreatsList.accounts.organization_name | String | The name of the organization to which the account belongs. |
| Gem.ThreatsList.alert_source | String | The source of the alert. |
| Gem.ThreatsList.alerts.accounts.account_status | String | Indicates the account status related to a specific alert. |
| Gem.ThreatsList.alerts.accounts.cloud_provider | String | Cloud provider associated with the alert’s account. |
| Gem.ThreatsList.alerts.accounts.display_name | String | Display name of the account related to the alert. |
| Gem.ThreatsList.alerts.accounts.id | Number | Numerical identifier for the account associated with the alert. |
| Gem.ThreatsList.alerts.accounts.identifier | String | Identifier for the account related to the alert. |
| Gem.ThreatsList.alerts.accounts.organization_name | String | Organization name associated with the alert’s account. |
| Gem.ThreatsList.alerts.alert_source | String | The source of individual alerts. |
| Gem.ThreatsList.alerts.datetime | Date | The date and time when the alert was generated. |
| Gem.ThreatsList.alerts.description | String | Description of the alert. |
| Gem.ThreatsList.alerts.entities.activity_by_provider | Unknown | Details about activity by the cloud provider in relation to the alert. |
| Gem.ThreatsList.alerts.entities.cloud_provider | String | Cloud provider related to the alert entities. |
| Gem.ThreatsList.alerts.entities.id | String | Unique identifier for the entities related to the alert. |
| Gem.ThreatsList.alerts.entities.is_main_entity | Boolean | Indicates if the entity is the primary subject of the alert. |
| Gem.ThreatsList.alerts.entities.is_secondary_entity | Boolean | Indicates if the entity is a secondary subject of the alert. |
| Gem.ThreatsList.alerts.entities.resource_id | Unknown | Identifier for the resources involved in the alert. |
| Gem.ThreatsList.alerts.entities.type | String | Type of entities involved in the alert. |
| Gem.ThreatsList.alerts.id | String | Unique identifier for the alert. |
| Gem.ThreatsList.alerts.main_alert_id | String | Identifier for the primary alert, if applicable. |
| Gem.ThreatsList.alerts.mitre_techniques.id | String | Identifier for the MITRE ATT&CK technique associated with the alert. |
| Gem.ThreatsList.alerts.mitre_techniques.technique_name | String | Name of the MITRE ATT&CK technique related to the alert. |
| Gem.ThreatsList.alerts.organization_id | String | Identifier for the organization associated with the alert. |
| Gem.ThreatsList.alerts.severity | Number | Numerical representation of the alert’s severity. |
| Gem.ThreatsList.alerts.severity_text | String | Textual description of the alert’s severity. |
| Gem.ThreatsList.alerts.status | String | Current status of the alert (e.g., open, resolved. in_progress). |
| Gem.ThreatsList.alerts.title | String | Title or summary of the alert. |
| Gem.ThreatsList.alerts.ttp_id | String | Identifier for the tactics, techniques, and procedures (TTP) related to the alert. |
| Gem.ThreatsList.assignees | Unknown | Information about who is assigned to address the threats. |
| Gem.ThreatsList.category | String | Classification or category of the threat. |
| Gem.ThreatsList.datetime | Date | The date and time when the threat was identified or logged. |
| Gem.ThreatsList.description | String | Detailed description of the threat. |
| Gem.ThreatsList.entities.activity_by_provider | Unknown | Details about the activity conducted by the cloud provider in relation to the threat. |
| Gem.ThreatsList.entities.cloud_provider | String | Cloud service provider associated with the entities in the threat. |
| Gem.ThreatsList.entities.id | String | Unique identifier for the entities involved in the threat. |
| Gem.ThreatsList.entities.is_main_entity | Boolean | Indicates if the entity is the primary focus of the threat. |
| Gem.ThreatsList.entities.is_secondary_entity | Boolean | Indicates if the entity plays a secondary role in the context of the threat. |
| Gem.ThreatsList.entities.resource_id | Unknown | Identifier for the resources targeted or involved in the threat. |
| Gem.ThreatsList.entities.type | String | Type or nature of the entities involved in the threat. |
| Gem.ThreatsList.id | String | Unique identifier for the threat list item. |
| Gem.ThreatsList.main_alert_id | String | Main alert identifier related to the threat. |
| Gem.ThreatsList.mitre_techniques.id | String | Identifier for MITRE ATT&CK techniques associated with the threat. |
| Gem.ThreatsList.mitre_techniques.technique_name | String | Name of the MITRE ATT&CK technique associated with the threat. |
| Gem.ThreatsList.organization_id | String | Identifier of the organization associated with the threat. |
| Gem.ThreatsList.severity_text | String | Textual description of the overall severity of the threat. |
| Gem.ThreatsList.status | String | Current status of the threat (e.g., active, resolved). |
| Gem.ThreatsList.title | String | Title or main description of the threat. |
| Gem.ThreatsList.ttp_id | String | Identifier for the tactics, techniques, and procedures (TTP) associated with the threat. |
gem-get-threat-details
Get details about a specific threat.
Base Command
gem-get-threat-details
Input
| Argument Name | Description | Required |
|---|---|---|
| threat_id | The ID of the threat to get details for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Threat.accounts.account_status | String | Indicates the current status of the account (e.g., active, suspended). |
| Gem.Threat.accounts.cloud_provider | String | Specifies the cloud service provider for the account (e.g., AWS, Azure). |
| Gem.Threat.accounts.display_name | String | The display name associated with the account. |
| Gem.Threat.accounts.hierarchy_path.id | String | Unique identifier within the account hierarchy path. |
| Gem.Threat.accounts.hierarchy_path.name | String | Name designation within the account hierarchy path. |
| Gem.Threat.accounts.id | Number | The unique numerical identifier for the account. |
| Gem.Threat.accounts.identifier | String | An alternative identifier for the account. |
| Gem.Threat.accounts.organization_name | String | The name of the organization to which the account belongs. |
| Gem.Threat.alert_source | String | The source of the alert. |
| Gem.Threat.alerts.accounts.account_status | String | Indicates the account status related to a specific alert. |
| Gem.Threat.alerts.accounts.cloud_provider | String | Cloud provider associated with the alert’s account. |
| Gem.Threat.alerts.accounts.display_name | String | Display name of the account related to the alert. |
| Gem.Threat.alerts.accounts.id | Number | Numerical identifier for the account associated with the alert. |
| Gem.Threat.alerts.accounts.identifier | String | Identifier for the account related to the alert. |
| Gem.Threat.alerts.accounts.organization_name | String | Organization name associated with the alert’s account. |
| Gem.Threat.alerts.alert_source | String | The source of individual alerts. |
| Gem.Threat.alerts.datetime | Date | The date and time when the alert was generated. |
| Gem.Threat.alerts.description | String | Description of the alert. |
| Gem.Threat.alerts.entities.activity_by_provider | Unknown | Details about activity by the cloud provider in relation to the alert. |
| Gem.Threat.alerts.entities.cloud_provider | String | Cloud provider related to the alert entities. |
| Gem.Threat.alerts.entities.id | String | Unique identifier for the entities related to the alert. |
| Gem.Threat.alerts.entities.is_main_entity | Boolean | Indicates if the entity is the primary subject of the alert. |
| Gem.Threat.alerts.entities.is_secondary_entity | Boolean | Indicates if the entity is a secondary subject of the alert. |
| Gem.Threat.alerts.entities.resource_id | Unknown | Identifier for the resources involved in the alert. |
| Gem.Threat.alerts.entities.type | String | Type of entities involved in the alert. |
| Gem.Threat.alerts.id | String | Unique identifier for the alert. |
| Gem.Threat.alerts.main_alert_id | String | Identifier for the primary alert, if applicable. |
| Gem.Threat.alerts.mitre_techniques.id | String | Identifier for the MITRE ATT&CK technique associated with the alert. |
| Gem.Threat.alerts.mitre_techniques.technique_name | String | Name of the MITRE ATT&CK technique related to the alert. |
| Gem.Threat.alerts.organization_id | String | Identifier for the organization associated with the alert. |
| Gem.Threat.alerts.severity | Number | Numerical representation of the alert’s severity. |
| Gem.Threat.alerts.severity_text | String | Textual description of the alert’s severity. |
| Gem.Threat.alerts.status | String | Current status of the alert (e.g., open, resolved. in_progress). |
| Gem.Threat.alerts.title | String | Title or summary of the alert. |
| Gem.Threat.alerts.ttp_id | String | Identifier for the tactics, techniques, and procedures (TTP) related to the alert. |
| Gem.Threat.assignees | Unknown | Information about who is assigned to address the threats. |
| Gem.Threat.category | String | Classification or category of the threat. |
| Gem.Threat.datetime | Date | The date and time when the threat was identified or logged. |
| Gem.Threat.description | String | Detailed description of the threat. |
| Gem.Threat.entities.activity_by_provider | Unknown | Details about the activity conducted by the cloud provider in relation to the threat. |
| Gem.Threat.entities.cloud_provider | String | Cloud service provider associated with the entities in the threat. |
| Gem.Threat.entities.id | String | Unique identifier for the entities involved in the threat. |
| Gem.Threat.entities.is_main_entity | Boolean | Indicates if the entity is the primary focus of the threat. |
| Gem.Threat.entities.is_secondary_entity | Boolean | Indicates if the entity plays a secondary role in the context of the threat. |
| Gem.Threat.entities.resource_id | Unknown | Identifier for the resources targeted or involved in the threat. |
| Gem.Threat.entities.type | String | Type or nature of the entities involved in the threat. |
| Gem.Threat.id | String | Unique identifier for the threat list item. |
| Gem.Threat.main_alert_id | String | Main alert identifier related to the threat. |
| Gem.Threat.mitre_techniques.id | String | Identifier for MITRE ATT&CK techniques associated with the threat. |
| Gem.Threat.mitre_techniques.technique_name | String | Name of the MITRE ATT&CK technique associated with the threat. |
| Gem.Threat.organization_id | String | Identifier of the organization associated with the threat. |
| Gem.Threat.severity_text | String | Textual description of the overall severity of the threat. |
| Gem.Threat.status | String | Current status of the threat (e.g., active, resolved). |
| Gem.Threat.title | String | Title or main description of the threat. |
| Gem.Threat.ttp_id | String | Identifier for the tactics, techniques, and procedures (TTP) associated with the threat. |
gem-get-alert-details
Get details about a specific alert.
Base Command
gem-get-alert-details
Input
| Argument Name | Description | Required |
|---|---|---|
| alert_id | The ID of the alert to get details for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Alert.alert_context.account_db_id | String | Database identifier for the account associated with the alert. |
| Gem.Alert.alert_context.alert_id | String | Unique identifier for the alert. |
| Gem.Alert.alert_context.alert_source | String | The source from which the alert originated. |
| Gem.Alert.alert_context.alert_source_id | String | Identifier for the specific source of the alert. |
| Gem.Alert.alert_context.alert_source_url | String | URL associated with the alert source. |
| Gem.Alert.alert_context.cloud_provider | String | The cloud service provider associated with the alert. |
| Gem.Alert.alert_context.created_at | Date | The timestamp when the alert was created. |
| Gem.Alert.alert_context.description | String | Detailed description of the alert. |
| Gem.Alert.alert_context.description_template | String | Template used for generating the alert description. |
| Gem.Alert.alert_context.general_cloud_provider | String | General classification of the cloud provider related to the alert. |
| Gem.Alert.alert_context.mitre_techniques.id | String | Identifier for the MITRE ATT&CK technique associated with the alert. |
| Gem.Alert.alert_context.mitre_techniques.technique_name | String | Name of the MITRE ATT&CK technique related to the alert. |
| Gem.Alert.alert_context.resolved | Boolean | Indicates whether the alert has been resolved. |
| Gem.Alert.alert_context.severity | Number | Numerical representation of the alert’s severity. |
| Gem.Alert.alert_context.status | String | Current status of the alert (e.g., open, resolved, in_progress). |
| Gem.Alert.alert_context.timeframe_end | Date | End date and time of the timeframe relevant to the alert. |
| Gem.Alert.alert_context.timeframe_start | Date | Start date and time of the timeframe relevant to the alert. |
| Gem.Alert.alert_context.title | String | Title or main description of the alert. |
| Gem.Alert.alert_context.ttp_id | String | Identifier for the tactics, techniques, and procedures (TTP) related to the alert. |
| Gem.Alert.triage_configuration.analysis | String | Analysis or summary of the triage configuration for the alert. |
| Gem.Alert.triage_configuration.entities.activity_by_provider | String | Activity details by the cloud provider related to the triage entities. |
| Gem.Alert.triage_configuration.entities.cloud_provider | String | Cloud provider associated with the triage entities. |
| Gem.Alert.triage_configuration.entities.id | String | Unique identifier for the entities involved in the triage. |
| Gem.Alert.triage_configuration.entities.is_main_entity | Boolean | Indicates if the entity is the primary focus in the triage. |
| Gem.Alert.triage_configuration.entities.is_secondary_entity | Boolean | Indicates if the entity plays a secondary role in the triage. |
| Gem.Alert.triage_configuration.entities.resource_id | String | Resource identifier associated with the triage entities. |
| Gem.Alert.triage_configuration.entities.type | String | Type or nature of the entities involved in the triage. |
| Gem.Alert.triage_configuration.event_groups.description | String | Description of the event groups involved in the triage. |
| Gem.Alert.triage_configuration.event_groups.end_time | Date | End time for the event groups in the triage. |
| Gem.Alert.triage_configuration.event_groups.error_code | String | Error code associated with the event groups in the triage. |
| Gem.Alert.triage_configuration.event_groups.event_name | String | Name of the specific event within the event group related to the triage. |
| Gem.Alert.triage_configuration.event_groups.event_type | String | Type or category of the event within the event group. |
| Gem.Alert.triage_configuration.event_groups.events | String | Details of the events that are part of the event group in the triage. |
| Gem.Alert.triage_configuration.event_groups.start_time | Date | Start time for the event groups involved in the triage. |
| Gem.Alert.triage_configuration.event_groups.time_indicator_text | String | Textual indicator of the time relevant to the event groups in the triage. |
| Gem.Alert.triage_configuration.event_groups.timeline_item_type | String | Type of timeline item represented by the event groups in the triage. |
| Gem.Alert.triage_configuration.event_groups.title | String | Title or main description of the event groups in the triage. |
| Gem.Alert.triage_configuration.event_groups.type | String | Overall type or classification of the event groups in the triage. |
| Gem.Alert.triage_configuration.resolve_params.include_data_events | Boolean | Indicates whether data events should be included in the resolution process. |
| Gem.Alert.triage_configuration.resolve_params.timeframe_lookup_window_hours | Number | Number of hours in the lookup window for timeframe analysis in the resolution process. |
| Gem.Alert.triage_configuration.state | String | Current state or status of the triage configuration for the alert. |
gem-list-inventory-resources
List inventory resources in Gem.
Base Command
gem-list-inventory-resources
Input
| Argument Name | Description | Required |
|---|---|---|
| limit | The number of items to return. Default is 50. | Optional |
| include_deleted | Include deleted resources in the response. | Optional |
| region | The region of the resources to return. | Optional |
| resource_type | The type of the resources to return. | Optional |
| search | The search query to use. | Optional |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.InventoryItems.account.account_status | String | Current status of the account associated with the inventory item (e.g., active, suspended). |
| Gem.InventoryItems.account.cloud_provider | String | Name of the cloud service provider for the account associated with the inventory item. |
| Gem.InventoryItems.account.display_name | String | Display name of the account associated with the inventory item. |
| Gem.InventoryItems.account.hierarchy_path | String | Hierarchical path in the account structure associated with the inventory item. |
| Gem.InventoryItems.account.id | Number | Unique numerical identifier for the account associated with the inventory item. |
| Gem.InventoryItems.account.identifier | String | Alternative identifier for the account associated with the inventory item. |
| Gem.InventoryItems.account.organization_name | String | Name of the organization to which the account associated with the inventory item belongs. |
| Gem.InventoryItems.account.tenant | String | Tenant information for the account associated with the inventory item in a multi-tenant environment. |
| Gem.InventoryItems.categories | String | Categories or types assigned to the inventory item. |
| Gem.InventoryItems.created_at | Date | Timestamp indicating when the inventory item was created. |
| Gem.InventoryItems.deleted | Boolean | Indicates whether the inventory item has been marked as deleted. |
| Gem.InventoryItems.external_url | String | URL linking to external information or resources related to the inventory item. |
| Gem.InventoryItems.identifiers.name | String | Name associated with the identifier of the inventory item. |
| Gem.InventoryItems.identifiers.value | String | Value of the identifier assigned to the inventory item. |
| Gem.InventoryItems.region | String | Geographic region associated with the inventory item. |
| Gem.InventoryItems.resource_id | String | Unique identifier for the resource that the inventory item represents. |
| Gem.InventoryItems.resource_type | String | Type of resource that the inventory item represents (e.g., VM, database). |
| Gem.InventoryItems.tags | String | Tags or labels assigned to the inventory item for categorization or identification. |
gem-get-resource-details
Get details about a specific resource.
Base Command
gem-get-resource-details
Input
| Argument Name | Description | Required |
|---|---|---|
| resource_id | The ID of the resource to get details for. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.InventoryItem.account.account_status | String | Current status of the account associated with the inventory item (e.g., active, suspended). |
| Gem.InventoryItem.account.cloud_provider | String | Name of the cloud service provider for the account associated with the inventory item. |
| Gem.InventoryItem.account.display_name | String | Display name of the account associated with the inventory item. |
| Gem.InventoryItem.account.hierarchy_path | String | Hierarchical path in the account structure associated with the inventory item. |
| Gem.InventoryItem.account.id | Number | Unique numerical identifier for the account associated with the inventory item. |
| Gem.InventoryItem.account.identifier | String | Alternative identifier for the account associated with the inventory item. |
| Gem.InventoryItem.account.organization_name | String | Name of the organization to which the account associated with the inventory item belongs. |
| Gem.InventoryItem.account.tenant | String | Tenant information for the account associated with the inventory item in a multi-tenant environment. |
| Gem.InventoryItem.categories | String | Categories or types assigned to the inventory item. |
| Gem.InventoryItem.created_at | Date | Timestamp indicating when the inventory item was created. |
| Gem.InventoryItem.deleted | Boolean | Indicates whether the inventory item has been marked as deleted. |
| Gem.InventoryItem.external_url | String | URL linking to external information or resources related to the inventory item. |
| Gem.InventoryItem.identifiers.name | String | Name associated with the identifier of the inventory item. |
| Gem.InventoryItem.identifiers.value | String | Value of the identifier assigned to the inventory item. |
| Gem.InventoryItem.region | String | Geographic region associated with the inventory item. |
| Gem.InventoryItem.resource_id | String | Unique identifier for the resource that the inventory item represents. |
| Gem.InventoryItem.resource_type | String | Type of resource that the inventory item represents (e.g., VM, database). |
gem-list-ips-by-entity
List all source IP addresses used by an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-ips-by-entity
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.IP.AS_NAME | String | Name of the Autonomous System (AS) associated with the IP address. |
| Gem.IP.AS_NUMBER | String | Number of the Autonomous System (AS) associated with the IP address. |
| Gem.IP.CITY | String | City where the IP address is located. |
| Gem.IP.COUNTRY_CODE | String | Country code corresponding to the location of the IP address. |
| Gem.IP.COUNTRY_NAME | String | Name of the country where the IP address is located. |
| Gem.IP.COUNT_SOURCEIP | String | Count of occurrences or references to the source IP address. |
| Gem.IP.IP_TYPE | String | Type of the IP address (e.g., IPv4, IPv6). |
| Gem.IP.IS_PRIVATE | String | Indicates whether the IP address is private (e.g., within a local network). |
| Gem.IP.LATITUDE | String | Latitude coordinate of the IP address’s location. |
| Gem.IP.LONGITUDE | String | Longitude coordinate of the IP address’s location. |
| Gem.IP.PROVIDER | String | Internet service provider associated with the IP address. |
| Gem.IP.SOURCEIPADDRESS | String | The actual IP address being referenced or analyzed. |
gem-list-services-by-entity
List all services accessed by an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-services-by-entity
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.By.Services.COUNT_SERVICE | String | Number of times the specified service appears or is utilized within the context. |
| Gem.Entity.By.Services.SERVICE | String | Name or type of the service being referenced or analyzed. |
gem-list-events-by-entity
List all events performed by an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-events-by-entity
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.By.Events.EVENTNAME | String | Name of the event being referenced or analyzed. |
| Gem.Entity.By.Events.EVENTNAME_COUNT | String | Count of occurrences or references to the specified event name. |
gem-list-accessing-entities
List all entities that accessed an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-accessing-entities
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.Accessing.USER_COUNT | String | Number of users accessing or interacting with the entity. |
| Gem.Entity.Accessing.USER_ID | String | Identifier(s) of the user(s) accessing or interacting with the entity. |
gem-list-using-entities
List all entities that used an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-using-entities
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.Using.ENTITY_COUNT | String | Count of the number of times the entity is used or referenced. |
| Gem.Entity.Using.ENTITY_ID | String | Unique identifier for the entity being used or referenced. |
gem-list-events-on-entity
List all events performed on an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-events-on-entity
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.On.Events.EVENTNAME | String | Name of the event associated with the entity. |
| Gem.Entity.On.Events.EVENTNAME_COUNT | String | Count of occurrences or instances of the specified event name related to the entity. |
gem-list-accessing-ips
List all source IP addresses that accessed an entity in a specific timeframe. The results are sorted by activity volume.
Base Command
gem-list-accessing-ips
Input
| Argument Name | Description | Required |
|---|---|---|
| entity_id | Gem ID of the entity. This will usually be the ARN or CSP ID. This property is also available for every resource in the Inventory screen. Example: arn:aws:ec2:us-east-1:112233445566:instance/i-1234567890abcdefg. | Required |
| entity_type | Type of the entity. See documentation for the full options list. | Required |
| read_only | Show read-only events. | Optional |
| start_time | Timeframe start (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
| end_time | Timeframe end (ISO format). Examples: 2023-01-01, 2023-01-01T01:01:01Z, 2023-01-01T01:01:01+00:00. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| Gem.Entity.Accessing.IPs.AS_NAME | String | Name of the Autonomous System (AS) associated with the IP address accessing the entity. |
| Gem.Entity.Accessing.IPs.AS_NUMBER | String | Number of the Autonomous System (AS) associated with the IP address accessing the entity. |
| Gem.Entity.Accessing.IPs.CITY | String | City where the IP address accessing the entity is located. |
| Gem.Entity.Accessing.IPs.COUNTRY_CODE | String | Country code corresponding to the location of the IP address accessing the entity. |
| Gem.Entity.Accessing.IPs.COUNTRY_NAME | String | Name of the country where the IP address accessing the entity is located. |
| Gem.Entity.Accessing.IPs.COUNT_SOURCEIP | String | Count of occurrences or references to the source IP address accessing the entity. |
| Gem.Entity.Accessing.IPs.IP_TYPE | String | Type of the IP address (e.g., IPv4, IPv6) accessing the entity. |
| Gem.Entity.Accessing.IPs.IS_PRIVATE | String | Indicates whether the IP address accessing the entity is private (e.g., within a local network). |
| Gem.Entity.Accessing.IPs.LATITUDE | String | Latitude coordinate of the IP address’s location accessing the entity. |
| Gem.Entity.Accessing.IPs.LONGITUDE | String | Longitude coordinate of the IP address’s location accessing the entity. |
| Gem.Entity.Accessing.IPs.PROVIDER | String | Internet service provider associated with the IP address accessing the entity. |
| Gem.Entity.Accessing.IPs.SOURCEIPADDRESS | String | The actual IP address being referenced or analyzed that is accessing the entity. |
gem-update-threat-status
Set a threat’s status to open, in progress or resolved.
Base Command
gem-update-threat-status
Input
| Argument Name | Description | Required |
|---|---|---|
| threat_id | The ID of the threat to update. | Required |
| status | The new status of the threat (open, in_progress, resolved). Possible values are: open, in_progress, resolved. | Required |
| verdict | The verdict of the threat. Possible values are: malicious, security_test, planned_action, not_malicious, inconclusive. | Optional |
| reason | The reason for resolving the threat. | Optional |
Context Output
There is no context output for this command.
gem-run-action
Run an action on an entity.
Base Command
gem-run-action
Input
| Argument Name | Description | Required |
|---|---|---|
| action | The action to run. | Required |
| entity_id | The ID of the entity to run the action on. | Required |
| entity_type | The type of the entity to run the action on. | Required |
| alert_id | The ID of the alert to run the action on. | Required |
| resource_id | The ID of the resource to run the action on. | Required |
Context Output
There is no context output for this command.
gem-add-timeline-event
Add a timeline event to a threat.
Base Command
gem-add-timeline-event
Input
| Argument Name | Description | Required |
|---|---|---|
| threat_id | The ID of the threat to add the timeline event to. | Required |
| comment | The comment to add to the timeline event. | Required |
Context Output
There is no context output for this command.
Configuration parameters
incidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalapi_endpoint— API Endpoint (required)credentials— Service Account ID (required)first_fetch— First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days)proxy— Use system proxy settingsinsecure— Trust any certificate (not secure)isFetch— Fetch incidentsmax_fetch— Maximum number of alerts per fetch
Commands (15)
-
gem-add-timeline-eventAdd a timeline event to a threat.
-
gem-get-alert-detailsGet details about a specific alert.
-
gem-get-resource-detailsGet details about a specific resource.
-
gem-get-threat-detailsGet details about a specific threat.
-
gem-list-accessing-entitiesList all entities that accessed an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-accessing-ipsList all source IP addresses that accessed an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-events-by-entityList all events performed by an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-events-on-entityList all events performed on an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-inventory-resourcesList inventory resources in Gem.
-
gem-list-ips-by-entityList all source IP addresses used by an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-services-by-entityList all services accessed by an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-list-threatsList all threats detected in Gem.
-
gem-list-using-entitiesList all entities that used an entity in a specific timeframe. The results are sorted by activity volume.
-
gem-run-actionRun an action on an entity.
-
gem-update-threat-statusSet a threat's status to open, in progress or resolved.
import re from typing import Any import demistomock as demisto # noqa: F401 import jwt import urllib3 from CommonServerPython import * # noqa: F401 from CommonServerUserPython import * # noqa # Disable insecure warnings urllib3.disable_warnings() """ CONSTANTS """ DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR PAGE_SIZE = 10 OK_CODES = (200, 201, 202) MAX_ALERTS_TO_FETCH = 50 # ENDPOINTS TOKEN_URL = "https://login.gem.security/oauth/token" # Get information Endpoints THREATS_ENDPOINT = "/v1/threats" THREAT_ENDPOINT = "/v1/threats/{id}" INVENTORY_ENDPOINT = "/v1/inventory" INVENTORY_ITEM_ENDPOINT = "/v1/inventory/{id}" ALERTS_ENDPOINT = "/triage/investigation/timeline/configuration" BREAKDOWN_ENDPOINT = "/triage/investigation/timeline/breakdown" FETCH_ENDPOINT = "/integrations/notification" # Actions Endpoints UPDATE_THREAT_ENDPOINT = "/v1/threats/{id}/status" RUN_ACTION_ENDPOINT = "/triage/containment/entity/run-action" ADD_TIMELINE_EVENT_ENDPOINT = "/detection/threats/{id}/add_timeline_event" """ CLIENT CLASS """ class GemClient(BaseClient): """This class defines a client to interact with the Gem API""" def __init__(self, base_url: str, verify: bool, proxy: bool, client_id: str, client_secret: str): super().__init__(base_url=base_url, verify=verify, proxy=proxy, ok_codes=OK_CODES) self._client_id = client_id self._client_secret = client_secret try: self._auth_token = self._get_token() except Exception as e: raise DemistoException(f"Failed to get token. Error: {e!s}") def _get_token(self): """ Retrieves the authentication token for the Gem integration. If the token is not found in the integration context or if it is expired, a new token is generated and returned. Returns: str: The authentication token. """ ctx = get_integration_context() if not ctx or not ctx.get("auth_token"): # No token in integration context, probably first run auth_token = self._generate_token() else: # Token exists, check if it's expired and generate a new one if needed auth_token = ctx.get("auth_token") decoded_jwt = jwt.decode(auth_token, options={"verify_signature": False}) # type: ignore token_expiration = datetime.fromtimestamp(decoded_jwt["exp"]) if token_expiration < datetime.now(): auth_token = self._generate_token() return auth_token def http_request(self, method: str, url_suffix="", full_url=None, headers=None, json_data=None, params=None, auth=True): """ Sends an HTTP request to the specified URL, adding the required headers and authentication token. Args: method (str): The HTTP method to use (e.g., GET, POST, PUT, DELETE). url_suffix (str, optional): The URL suffix to append to the base URL. Defaults to ''. full_url (str, optional): The full URL to send the request to. If provided, `url_suffix` will be ignored. Defaults to None. headers (dict, optional): Additional headers to include in the request. Defaults to None. json_data (dict, optional): JSON data to include in the request body. Defaults to None. params (dict, optional): Query parameters to include in the request URL. Defaults to None. auth (bool, optional): Whether to include authentication headers. Defaults to True. Returns: dict: The response from the HTTP request. Raises: Exception: If the request fails. """ if auth: headers = headers or {} headers["Authorization"] = f"Bearer {self._auth_token}" try: response = super()._http_request( method=method, url_suffix=url_suffix, full_url=full_url, headers=headers, json_data=json_data, params=params, raise_on_status=True, ) demisto.debug(f"Got response: {response}") return response except DemistoException as e: demisto.error(f"Failed to execute {method} request to {url_suffix}. Error: {e!s}") raise Exception(f"Failed to execute {method} request to {url_suffix}. Error: {e!s}") def _generate_token(self) -> str: """Generate an access token using the client id and secret :return: valid token """ data = { "client_id": self._client_id, "client_secret": self._client_secret, "grant_type": "client_credentials", "audience": "https://backend.gem.security", } headers = {"Content-Type": "application/json"} token_res = self.http_request(method="POST", full_url=TOKEN_URL, headers=headers, json_data=data, auth=False) set_integration_context((get_integration_context() or {}).update({"auth_token": token_res.get("access_token")})) return token_res.get("access_token") def _filter_non_empty_params(self, params): return {k: v for k, v in params.items() if v is not None} def fetch_threats(self, maxincidents=None, start_time=None) -> list[dict]: """ Fetches a list of threats from the Gem API. Args: maxincidents (int, optional): The maximum number of incidents to fetch. Defaults to None. start_time (str, optional): The start time to fetch incidents from. Defaults to None. Returns: list[dict]: A list of threat incidents. """ params = {"limit": maxincidents, "created__gt": start_time, "ordering": "created"} return self.http_request(method="GET", url_suffix=FETCH_ENDPOINT, params=self._filter_non_empty_params(params)) def get_resource_details(self, resource_id: str) -> dict: """ Get inventory item details. :param resource_id: ID of the item to get. :return: Inventory item. """ return self.http_request(method="GET", url_suffix=INVENTORY_ITEM_ENDPOINT.format(id=resource_id)) def get_threat_details(self, threat_id: str): """ Get threat details :param threat_id: id of the threat to get :return: threat details """ response = self.http_request(method="GET", url_suffix=THREAT_ENDPOINT.format(id=threat_id)) return response def get_alert_details(self, alert_id: str): """ Get alert details :param alert_id: id of the alert to get :return: alert details """ params = {"alert_id": alert_id} response = self.http_request(method="GET", url_suffix=ALERTS_ENDPOINT, params=self._filter_non_empty_params(params)) return response def list_threats( self, limit, time_start=None, time_end=None, ordering=None, status=None, ttp_id=None, title=None, severity=None, entity_type=None, cloud_provider=None, ) -> list[dict]: """ List threats :param time_start: time of first threat :param time_end: time of last threat :param limit: amount of threats :param ordering: how to order threats :param status: filter of threat status :param ttp_id: filter of threat ttp :param title: filter of threat title :param severity: filter of threat severity :param entity_type: filter of threat entity type :param cloud_provider: filter of threat cloud provider :return: threat list """ results = [] results_fetched = 0 for p in range(1, int(limit / PAGE_SIZE) + 2): if limit == results_fetched: break if limit - results_fetched < PAGE_SIZE: demisto.debug(f"Fetching page #{p} page_size {limit - results_fetched}") params = { "start_time": time_start, "end_time": time_end, "page": p, "page_size": limit - results_fetched, "ordering": ordering, "status": status, "ttp_id": ttp_id, "title": title, "severity": severity, "entity_type": entity_type, "provider": cloud_provider, } response = self.http_request( method="GET", url_suffix=THREATS_ENDPOINT, params=self._filter_non_empty_params(params) ) results_fetched = limit else: demisto.debug(f"Fetching page #{p} page_size {PAGE_SIZE}") params = { "start_time": time_start, "end_time": time_end, "page": p, "page_size": PAGE_SIZE, "ordering": ordering, "status": status, "ttp_id": ttp_id, "title": title, "severity": severity, "entity_type": entity_type, "provider": cloud_provider, } response = self.http_request( method="GET", url_suffix=THREATS_ENDPOINT, params=self._filter_non_empty_params(params) ) if len(response["results"]) < PAGE_SIZE: demisto.debug(f"Fetched {len(response['results'])}") results_fetched += len(response["results"]) results.extend(response["results"]) break results_fetched += PAGE_SIZE results.extend(response["results"]) demisto.debug(f"Fetched {len(results)} threats") return results def list_inventory_resources(self, limit, include_deleted=None, region=None, resource_type=None, search=None) -> list[dict]: """List inventory resources Args: limit (int): How many resources to fetch include_deleted (boolean, optional): Should include deleted resources. Defaults to None. region (str, optional): Resources region. Defaults to None. resource_type (str, optional): Filter resource types. Defaults to None. search (str, optional): Filter search params. Defaults to None. Returns: list[dict]: List of inventory resources """ results = [] results_fetched = 0 params = { "page_size": min(PAGE_SIZE, limit), "include_deleted": include_deleted, "region": region, "resource_type": resource_type, "search": search, } response = self.http_request(method="GET", url_suffix=INVENTORY_ENDPOINT, params=self._filter_non_empty_params(params)) results_fetched += len(response["results"]) results.extend(response["results"]) while response["next"] != "" and results_fetched < limit: page_size = min(PAGE_SIZE, limit - results_fetched) demisto.debug(f"Fetching page #{response['next']} page_size {page_size}") params = { "cursor": response["next"], "page_size": page_size, "include_deleted": include_deleted, "region": region, "resource_type": resource_type, "search": search, } response = self.http_request( method="GET", url_suffix=INVENTORY_ENDPOINT, params=self._filter_non_empty_params(params) ) results_fetched += len(response["results"]) results.extend(response["results"]) demisto.debug(f"Fetched {len(results)} inventory resources") return results def _breakdown(self, breakdown_by, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: params = { "breakdown_by": breakdown_by, "entity_id": entity_id, "entity_type": entity_type, "read_only": read_only, "start_time": start_time, "end_time": end_time, } response = self.http_request(method="GET", url_suffix=BREAKDOWN_ENDPOINT, params=self._filter_non_empty_params(params)) return response["table"] def list_ips_by_entity(self, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: """ Retrieves a dictionary of IP addresses associated with the specified entity. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. read_only (bool): Whether to retrieve read-only IP addresses. start_time (str): The start time for filtering IP addresses. end_time (str): The end time for filtering IP addresses. Returns: dict: A dictionary of IP addresses associated with the entity. """ return self._breakdown( breakdown_by="source_ip", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_services_by_entity(self, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: """ Retrieves a list of services associated with a specific entity. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. read_only (bool): Whether to retrieve read-only services only. start_time (str): The start time for filtering services. end_time (str): The end time for filtering services. Returns: dict: A dictionary containing the list of services associated with the entity. """ return self._breakdown( breakdown_by="service", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_events_by_entity(self, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: """ Retrieves a list of events associated with a specific entity. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. read_only (bool): Whether to retrieve read-only events only. start_time (str): The start time of the events. end_time (str): The end time of the events. Returns: dict: A dictionary containing the list of events. """ return self._breakdown( breakdown_by="entity_event_out", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_accessing_entities(self, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: """ Retrieves a list of accessing entities based on the provided parameters. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. read_only (bool): Specifies if the entity is read-only. start_time (datetime): The start time for filtering the accessing entities. end_time (datetime): The end time for filtering the accessing entities. Returns: dict: A dictionary containing the list of accessing entities. """ return self._breakdown( breakdown_by="user_in", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_using_entities(self, entity_id=None, entity_type=None, read_only=None, start_time=None, end_time=None) -> dict: """ Retrieves a list of entities using the specified parameters. Args: entity_id (str, optional): The ID of the entity. Defaults to None. entity_type (str, optional): The type of the entity. Defaults to None. read_only (bool, optional): Specifies if the entity is read-only. Defaults to None. start_time (str, optional): The start time for filtering entities. Defaults to None. end_time (str, optional): The end time for filtering entities. Defaults to None. Returns: dict: A dictionary containing the list of entities. """ return self._breakdown( breakdown_by="using_entities", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_events_on_entity(self, entity_id=None, entity_type=None, start_time=None, end_time=None, read_only=None) -> dict: """ Retrieves a list of events associated with a specific entity. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. start_time (str): The start time of the events. end_time (str): The end time of the events. read_only (bool): Whether to retrieve read-only events only. Returns: dict: A dictionary containing the list of events. """ return self._breakdown( breakdown_by="entity_event_in", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def list_accessing_ips(self, entity_id=None, entity_type=None, start_time=None, end_time=None, read_only=None) -> dict: """ Retrieves a breakdown of accessing IPs for a given entity. Args: entity_id (str): The ID of the entity. entity_type (str): The type of the entity. start_time (str): The start time of the breakdown. end_time (str): The end time of the breakdown. read_only (bool): Whether to include read-only access in the breakdown. Returns: dict: A breakdown of accessing IPs. """ return self._breakdown( breakdown_by="ip_access", entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time, ) def update_threat_status(self, threat_id: str, status: Optional[str], verdict: Optional[str], reason: Optional[str] = None): """ Update the threat status for a given threat ID. Args: threat_id (str): The ID of the threat to update. status (str): The new status of the threat. verdict (str): The new verdict of the threat. reason (str, optional): Additional information or reason for the update. Returns: dict: The response from the API call. """ json_data = {"verdict": verdict, "additional_info": reason, "status": status} response = self.http_request(method="PATCH", url_suffix=UPDATE_THREAT_ENDPOINT.format(id=threat_id), json_data=json_data) return response def run_action_on_entity(self, action: str, entity_id: str, entity_type: str, alert_id: str, resource_id: str) -> dict: """ Runs an action on a specific entity. Args: action (str): The action to be performed on the entity. entity_id (str): The ID of the entity. entity_type (str): The type of the entity. alert_id (str): The ID of the alert associated with the entity. resource_id (str): The ID of the resource associated with the entity. Returns: dict: The response from the API. """ params = { "action": action, "entity_id": entity_id, "entity_type": entity_type, "alert_id": alert_id, "resource_id": resource_id, } response = self.http_request(method="POST", url_suffix=RUN_ACTION_ENDPOINT, params=self._filter_non_empty_params(params)) return response def add_timeline_event(self, threat_id: str, comment: str, timestamp: str) -> dict: """ Adds a timeline event to a threat. Args: threat_id (str): The ID of the threat. comment (str): The comment for the timeline event. timestamp (str): The timestamp of the timeline event. Returns: dict: The response from the API. """ params = {"title": "XSOAR comment", "description": comment, "timeline_event_type": "xsoar", "timestamp": timestamp} response = self.http_request( method="POST", url_suffix=ADD_TIMELINE_EVENT_ENDPOINT.format(id=threat_id), json_data=self._filter_non_empty_params(params), ) return response """ HELPER FUNCTIONS """ # as per recommendation from @freylis, compile once only CLEANR = re.compile("<.*?>") def _cleanhtml(raw_html): """ Cleans HTML tags from the given raw HTML string. Args: raw_html (str): The raw HTML string to be cleaned. Returns: str: The cleaned text without HTML tags. """ cleantext = re.sub(CLEANR, "", raw_html) return cleantext.replace("\n", "") def _clean_description(alert: dict) -> dict: """ Cleans the description of the alert by removing HTML tags. Args: alert (dict): The alert dictionary. Returns: dict: The modified alert dictionary with cleaned description. """ if alert["triage_configuration"]["event_groups"]: i = 0 for e in alert["triage_configuration"]["event_groups"]: clean_description = _cleanhtml(e["description"]) alert["triage_configuration"]["event_groups"][i]["description"] = clean_description i += 1 return alert def init_client(params: dict) -> GemClient: """ Initializes a new GemClient object """ return GemClient( base_url=params["api_endpoint"], verify=not params.get("insecure", False), proxy=params.get("proxy", False), client_id=demisto.getParam("credentials")["identifier"] if demisto.getParam("credentials") else "", client_secret=demisto.getParam("credentials")["password"] if demisto.getParam("credentials") else "", ) """ COMMAND FUNCTIONS """ def fetch_threats(client: GemClient, max_results: int, last_run: dict, first_fetch_time: str) -> tuple[dict, list[dict]]: """ Fetches threats from the Gem platform within a specified time range. Args: client (GemClient): The Gem client object. max_results (int): Maximum number of results to fetch. last_run (dict): A dictionary containing information about the last run of the fetch. first_fetch_time (str): The earliest time from which to fetch threats, if there is no last run. Returns: tuple[dict, list[dict]]: A tuple containing the new last run and a list of incidents (threats). """ last_fetch = last_run.get("last_fetch", None) if last_fetch is None: # if missing, use what provided via first_fetch_time last_fetch = first_fetch_time else: # otherwise use the stored last fetch last_fetch = last_fetch demisto.debug(f"Last fetch time: {last_fetch}") incidents: list[dict[str, Any]] = [] for _ in range(int(max_results / PAGE_SIZE) + 1): results = client.fetch_threats(maxincidents=PAGE_SIZE, start_time=last_fetch) for r in results: incident = { "name": r["title"], # name is required field, must be set "occurred": r["created"], # must be string of a format ISO8601 "dbotMirrorId": str(r["id"]), # must be a string "rawJSON": json.dumps(r), # the original event, this will allow mapping of the event in the mapping stage. } incidents.append(incident) demisto.debug(f"Fetched {len(incidents)} incidents") if incidents: last_fetch = incidents[-1].get("occurred") demisto.debug(f"Last fetch time: {last_fetch}") assert last_fetch last_run["last_fetch"] = last_fetch return last_run, incidents def test_module(params: dict[str, Any]) -> str: """ Tests API connectivity and authentication. Return "ok" if test passed, anything else will fail the test. Args: params (Dict): Integration parameters Returns: str: 'ok' if test passed, anything else will raise an exception and will fail the test. """ try: init_client(params) except Exception: raise DemistoException("Authentication failed") return "ok" def get_resource_details(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Retrieves details of a specific resource from the Gem API. Args: client (GemClient): The Gem client object. args (dict): Command arguments, must contain 'resource_id'. Returns: CommandResults: Object containing the resource details for display in Cortex XSOAR. """ resource_id = args.get("resource_id", "") result = client.get_resource_details(resource_id) return CommandResults( readable_output=tableToMarkdown("Inventory Item", result), outputs_prefix="Gem.InventoryItem", outputs_key_field="resource_id", outputs=result, ) def get_threat_details(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Retrieves details of a specific threat from the Gem API. Args: client (GemClient): The Gem client object. args (dict): Command arguments, must contain 'threat_id'. Returns: CommandResults: Object containing the threat details for display in Cortex XSOAR. """ threat_id = args.get("threat_id", "") result = client.get_threat_details(threat_id=threat_id) return CommandResults( readable_output=tableToMarkdown("Threat", result), outputs_prefix="Gem.Threat", outputs_key_field="id", outputs=result ) def get_alert_details(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Retrieves details of a specific alert from the Gem API. Args: client (GemClient): The Gem client object. args (dict): Command arguments, must contain 'alert_id'. Returns: CommandResults: Object containing the alert details for display in Cortex XSOAR. """ alert_id = args.get("alert_id", "") result = client.get_alert_details(alert_id=alert_id) result = _clean_description(result) return CommandResults( readable_output=tableToMarkdown("Alert", result), outputs_prefix="Gem.Alert", outputs_key_field="id", outputs=result ) def list_inventory_resources(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists inventory resources from the Gem API based on provided arguments. Args: client (GemClient): The Gem client object. args (dict): Command arguments, may include 'limit', 'include_deleted', 'region', 'resource_type', and 'search'. Returns: CommandResults: Object containing the list of inventory resources for display in Cortex XSOAR. """ limit = arg_to_number(args.get("limit")) or PAGE_SIZE include_deleted = args.get("include_deleted") region = args.get("region") resource_type = args.get("resource_type") search = args.get("search") result = client.list_inventory_resources( limit, include_deleted=include_deleted, region=region, resource_type=resource_type, search=search ) return CommandResults( readable_output=tableToMarkdown("Inventory Items", result), outputs_prefix="Gem.InventoryItems", outputs_key_field="id", outputs=result, ) def list_threats(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists threats from the Gem API based on provided time range and other optional filters. Args: client (GemClient): The Gem client object. args (dict): Command arguments, must include 'time_start' and 'time_end', and may include 'limit', 'ordering', 'status', 'ttp_id', 'title', 'severity', 'entity_type', and 'cloud_provider'. Returns: CommandResults: Object containing the list of threats for display in Cortex XSOAR. """ time_start = args.get("time_start") time_end = args.get("time_end") limit = arg_to_number(args.get("limit")) or PAGE_SIZE ordering = args.get("ordering") status = args.get("status") ttp_id = args.get("ttp_id") title = args.get("title") severity = args.get("severity") entity_type = args.get("entity_type") cloud_provider = args.get("cloud_provider") result = client.list_threats( time_start=time_start, time_end=time_end, limit=limit, ordering=ordering, status=status, ttp_id=ttp_id, title=title, severity=severity, entity_type=entity_type, cloud_provider=cloud_provider, ) demisto.debug(f"Got {len(result)} Threats") return CommandResults( readable_output=tableToMarkdown("Threats", result), outputs_prefix="Gem.ThreatsList", outputs_key_field="id", outputs=result, ) def _breakdown_validate_params(client: GemClient, args: dict[str, Any]) -> tuple[Any, Any, Any | None, Any, Any]: """ Validates and extracts parameters required for breakdown-related API requests. Args: client (GemClient): The Gem client object (unused in this function but included for consistency). args (dict): Command arguments, must include 'entity_id', 'entity_type', 'start_time', and 'end_time'. Returns: tuple: A tuple containing extracted parameters. """ entity_id = args.get("entity_id") entity_type = args.get("entity_type") read_only = args.get("read_only") start_time = args.get("start_time") end_time = args.get("end_time") return entity_id, entity_type, read_only, start_time, end_time def _parse_breakdown_result(result: dict) -> tuple[list[str], list[list[str]], list[dict]]: """ Parses the result from a breakdown API response. Args: result (dict): The API response containing the breakdown results. Returns: tuple: A tuple containing parsed headers, rows for table display, and raw output data. """ new_t = [] for r in result["rows"]: new_t.append(r["row"]) return result["headers"], new_t, new_t def list_ips_by_entity(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists IP addresses associated with a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of IP addresses for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_ips_by_entity( entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("IPs", rows, headers=headers), outputs_prefix="Gem.IP", outputs_key_field="SOURCEIPADDRESS", outputs=outputs, ) def list_services_by_entity(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists services associated with a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of services for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_services_by_entity( entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("Services", rows, headers=headers), outputs_prefix="Gem.Entity.By.Services", outputs_key_field="SERVICE", outputs=outputs, ) def list_events_by_entity(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists events associated with a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of events for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_events_by_entity( entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("Events by Entity", rows, headers=headers), outputs_prefix="Gem.Entity.By.Events", outputs_key_field="EVENTNAME", outputs=outputs, ) def list_accessing_entities(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists entities that have accessed a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of accessing entities for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_accessing_entities( entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("Accessing Entities", rows, headers=headers), outputs_prefix="Gem.Entity.Accessing", outputs_key_field="", outputs=outputs, ) def list_using_entities(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists entities using a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of using entities for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_using_entities( entity_id=entity_id, entity_type=entity_type, read_only=read_only, start_time=start_time, end_time=end_time ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("Using Entities", rows, headers=headers), outputs_prefix="Gem.Entity.Using", outputs_key_field="ENTITY_ID", outputs=outputs, ) def list_events_on_entity(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists events occurring on a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of events on the entity for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_events_on_entity( entity_id=entity_id, entity_type=entity_type, start_time=start_time, end_time=end_time, read_only=read_only ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("Events on Entity", rows, headers=headers), outputs_prefix="Gem.Entity.On.Events", outputs_key_field="EVENTNAME", outputs=outputs, ) def list_accessing_ips(client: GemClient, args: dict[str, Any]) -> CommandResults: """ Lists IP addresses that have accessed a specific entity. Args: client (GemClient): The Gem client object. args (dict): Command arguments, including 'entity_id', 'entity_type', 'read_only', 'start_time', and 'end_time'. Returns: CommandResults: Object containing a list of accessing IP addresses for display in Cortex XSOAR. """ entity_id, entity_type, read_only, start_time, end_time = _breakdown_validate_params(client, args) result = client.list_accessing_ips( entity_id=entity_id, entity_type=entity_type, start_time=start_time, end_time=end_time, read_only=read_only ) headers, rows, outputs = _parse_breakdown_result(result) return CommandResults( readable_output=tableToMarkdown("IPs Accessing Entity", rows, headers=headers), outputs_prefix="Gem.Entity.Accessing.IPs", outputs_key_field="AS_NAME", outputs=outputs, ) def update_threat_status(client: GemClient, args: dict[str, Any]): """ Updates the status of a specified threat in the Gem system. Args: client (GemClient): The Gem client object. args (dict): Command arguments, must include 'threat_id', 'status', 'verdict', and optionally 'reason'. """ threat_id = args.get("threat_id", "") status = args.get("status") verdict = args.get("verdict") reason = args.get("reason") client.update_threat_status(threat_id=threat_id, status=status, verdict=verdict, reason=reason) def run_action_on_entity(client: GemClient, args: dict[str, Any]) -> CommandResults: action = args.get("action", "") entity_id = args.get("entity_id", "") entity_type = args.get("entity_type", "") alert_id = args.get("alert_id", "") resource_id = args.get("resource_id", "") result = client.run_action_on_entity( action=action, entity_id=entity_id, entity_type=entity_type, alert_id=alert_id, resource_id=resource_id, ) return CommandResults( readable_output=tableToMarkdown("Run Result", result), outputs_prefix="Gem.Run", outputs_key_field="id", outputs=result ) def add_timeline_event(client: GemClient, args: dict[str, Any]) -> CommandResults: threat_id = args.get("threat_id", "") comment = args.get("comment", "") result = client.add_timeline_event(threat_id=threat_id, comment=comment, timestamp=datetime.now().strftime(DATE_FORMAT)) return CommandResults( readable_output=tableToMarkdown("AddTimelineEvent Result", result), outputs_prefix="Gem.AddTimelineEvent", outputs_key_field="", outputs=result, ) """ MAIN FUNCTION """ def main() -> None: """main function, parses params and runs command functions :return: :rtype: """ params = demisto.params() args = demisto.args() command = demisto.command() demisto.debug(f"args {args}") demisto.debug(f"Command being called is {command}") try: if command == "test-module": # This is the call made when pressing the integration Test button return_results(test_module(params)) client = init_client(params) if command == "gem-list-threats": return_results(list_threats(client, args)) elif command == "gem-get-threat-details": return_results(get_threat_details(client, args)) elif command == "gem-get-alert-details": return_results(get_alert_details(client, args)) elif command == "gem-list-inventory-resources": return_results(list_inventory_resources(client, args)) elif command == "gem-get-resource-details": return_results(get_resource_details(client, args)) elif command == "gem-list-ips-by-entity": return_results(list_ips_by_entity(client, args)) elif command == "gem-list-services-by-entity": return_results(list_services_by_entity(client, args)) elif command == "gem-list-events-by-entity": return_results(list_events_by_entity(client, args)) elif command == "gem-list-accessing-entities": return_results(list_accessing_entities(client, args)) elif command == "gem-list-using-entities": return_results(list_using_entities(client, args)) elif command == "gem-list-events-on-entity": return_results(list_events_on_entity(client, args)) elif command == "gem-list-accessing-ips": return_results(list_accessing_ips(client, args)) elif command == "gem-update-threat-status": return_results(update_threat_status(client, args)) elif command == "gem-run-action": return_results(run_action_on_entity(client, args)) elif command == "gem-add-timeline-event": return_results(add_timeline_event(client, args)) elif command == "fetch-incidents": # How much time before the first fetch to retrieve alerts first_fetch_time = arg_to_datetime( arg=params.get("first_fetch", "30 days"), arg_name="First fetch time", required=True ) assert first_fetch_time max_results = arg_to_number(arg=params.get("max_fetch"), arg_name="max_fetch", required=False) if not max_results or max_results > MAX_ALERTS_TO_FETCH: max_results = MAX_ALERTS_TO_FETCH next_run, incidents = fetch_threats( client=client, max_results=max_results, last_run=demisto.getLastRun(), # getLastRun() gets the last run dict first_fetch_time=datetime.strftime(first_fetch_time, DATE_FORMAT), ) demisto.debug(f"Fetched {len(incidents)} incidents") demisto.debug(f"Next run: {next_run}") # saves next_run for the time fetch-incidents is invoked demisto.setLastRun(next_run) # fetch-incidents calls ``demisto.incidents()`` to provide the list # of incidents to create demisto.incidents(incidents) else: raise NotImplementedError(f"Command {command} is not implemented") # Log exceptions and return errors except Exception as e: return_error(f"Failed to execute {command} command.\nError:\n{e!s}") """ ENTRY POINT """ if __name__ in ("__main__", "__builtin__", "builtins"): main()