GCenter 103

This integration fetch events generated by the GCenter appliance.

Network Security · Gatewatcher AionIQ

Details

IDGCenter 103
ProviderGatewatcher
CategoryNetwork Security
From Version6.5.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

This integration fetch events generated by the GCenter appliance.
This integration was integrated and tested with version 2.5.3.103 of GCenter 103.

This is the default integration for this content pack when configured by the Data Onboarder in Cortex XSIAM.

Configure GCenter 103 in Cortex

Parameter Description Required
GCenter IP address The IP of the GCenter from where the events will be fetched. True
GCenter API token   False
GCenter account   False
Password   False
GCenter Version   False
Check the TLS certificate   False
Use system proxy settings   False
Fetch incidents   False
Fetch incidents from type   False
Engine alerts selection   False
First fetch This value represents how far the first fetch will grab the events stored in the GCenter e.g. 2 days False
Fetch limit This value represents the maximum events fetched by instruction, this integration can handle up to 10000. The default value is 200 and is the optimum for Cortex XSOAR. False
Incident type    

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.

gcenter103-alerts-list


List all alerts.

Base Command

gcenter103-alerts-list

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
ids A comma-separated list of alert IDs. Optional
excluded_ids A comma-separated list of alert IDs to exclude. Optional
acknowledged Whether to filter on the acknowledgement status. Possible values are: true, false. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
src_ip Comma-separated list of source IP addresses of the alerts. Optional
dest_ip Comma-separated list of destination IP addresses of the alerts. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
name Filter on alert signature. Comma-separated list of signatures. Optional
description Filter alerts on their description. Optional
tag Filter on alerts containing tags. Comma-separated list of tag names. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional
excluded_tags Filter out alerts containing tags. Comma-separated list of tags. Logical OR between the tags. Optional
sort_by The filter by which to sort the results. Possible values are: date, -date, risk, -risk, name, -name. Optional
type The type by which to filter alerts on engines. Possible values are: active_cti, beacon_detect, dga_detect, malcore, malcore_retroanalyzer, malicious_powershell_detect, ransomware_detect, retrohunt, shellcode_detect, sigflow_alert. Optional
mitre_tactic_name Filter alert by MITRE tactic name. Possible values are: Collection, Collection (ICS), Collection (Mobile), Command and Control, Command and Control (ICS), Command and Control (Mobile), Credential Access, Credential Access (Mobile), Defense Evasion, Defense Evasion (Mobile), Discovery, Discovery (ICS), Discovery (Mobile), Evasion, Execution, Execution (ICS), Execution (Mobile), Exfiltration, Exfiltration (Mobile), Impact, Impact (ICS), Impact (Mobile), Impair Process Control, Inhibit Response Function, Initial Access, Initial Access (ICS), Initial Access (Mobile), Lateral Movement, Lateral Movement (ICS), Lateral Movement (Mobile), Persistence, Persistence (ICS), Persistence (Mobile), Privilege Escalation, Privilege Escalation (ICS), Privilege Escalation (Mobile), Reconnaissance, Resource Development. Optional
hostname Comma-separated list of hostnames. Optional
src_hostname Comma-separated list of source hostnames. Optional
dest_hostname Comma-separated list of destination hostnames. Optional
username Comma-separated list of usernames. Optional
note User note content. Optional
state Filter alerts on their state. Possible values are: closed, mute, open. Optional
search A search term. Optional
page A page to select in the results set. Optional
page_size Number of results per page. Optional

Context Output

Path Type Description
Gatewatcher.Alerts.List.uuid string Alert UUIDs.

gcenter103-alerts-get


Get an alert with its UUID (corresponds to event.id field) or the GCenter ID of the alert.

Base Command

gcenter103-alerts-get

Input

Argument Name Description Required
uuid UUID or GCenter ID of the alert. Required

Context Output

Path Type Description
Gatewatcher.Alerts.Get.uuid string The UUID of the alert fetched.

gcenter103-alerts-note-add


Add or update a note to an alert.

Base Command

gcenter103-alerts-note-add

Input

Argument Name Description Required
note The note to set on the alert. Required
uuid The UUID of the alert to set the note on (corresponds to event.id field). Required
overwrite Whether to overwrite the note. Possible values are: true, false. Required

Context Output

Path Type Description
Gatewatcher.Alerts.Note.Add.note string The note added to the alert.

gcenter103-alerts-note-remove


Delete the note of an alert.

Base Command

gcenter103-alerts-note-remove

Input

Argument Name Description Required
uuid The UUID of the alert to delete the note on (corresponds to event.id field). Required

Context Output

Path Type Description
Gatewatcher.Alerts.Note.Remove.uuid string The UUID of the alert whose note was removed.

gcenter103-alerts-tags-get


Get the tags of an alert.

Base Command

gcenter103-alerts-tags-get

Input

Argument Name Description Required
uuid The UUID of the alert to get tags (corresponds to event.id field). Required

Context Output

Path Type Description
Gatewatcher.Alerts.Tags.Get.tags string The tags of the alert.
Gatewatcher.Alerts.Tags.Get.uuid string The UUID of the alert having these tags.

gcenter103-alerts-tags-add


Add or update tags of an alert.

Base Command

gcenter103-alerts-tags-add

Input

Argument Name Description Required
uuid The UUID of the alert to add tags (corresponds to event.id field). Required
tags A comma-separated list of tag names to add to the alert. Required

Context Output

Path Type Description
Gatewatcher.Alerts.Tags.Add.tags string The tags added to the alert.
Gatewatcher.Alerts.Tags.Add.uuid string The UUID of the alert where the tags were added.

gcenter103-alerts-tags-remove


Remove tags from an alert.

Base Command

gcenter103-alerts-tags-remove

Input

Argument Name Description Required
uuid The UUID of the alert from which to remove tags (corresponds to event.id field). Required
tags A comma-separated list of tag names to remove to the alert. Required

Context Output

Path Type Description
Gatewatcher.Alerts.Tags.Remove string The tags present in the alert.

gcenter103-alerts-status-update


Update status of an alert.

Base Command

gcenter103-alerts-status-update

Input

Argument Name Description Required
note_u A note to add/update. Optional
tag_u Tags to add/update. Optional
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
uuid UUID of the alert to perform action (corresponds to event.id field). Required
acknowledged Whether to filter on the acknowledgement status. Possible values are: true, false. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
src_ip Comma-separated list of source IP addresses of the alerts. Optional
dest_ip Comma-separated list of destination IP addresses of the alerts. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
name Filter on alert signature. Comma-separated list of signatures. Optional
description Filter alerts on their description. Optional
tag Filter on alerts containing tags. Comma-separated list of tag names. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional
excluded_tags Filter out alerts containing tags. Comma-separated list of tags. Logical OR between the tags. Optional
sort_by The filter by which to sort the results. Possible values are: date, -date, risk, -risk, name, -name. Optional
type The type by which to filter alerts on engines. Possible values are: active_cti, beacon_detect, dga_detect, malcore, malcore_retroanalyzer, malicious_powershell_detect, ransomware_detect, retrohunt, shellcode_detect, sigflow_alert. Optional
mitre_tactic_name Filter alert by MITRE tactic name. Possible values are: Collection, Collection (ICS), Collection (Mobile), Command and Control, Command and Control (ICS), Command and Control (Mobile), Credential Access, Credential Access (Mobile), Defense Evasion, Defense Evasion (Mobile), Discovery, Discovery (ICS), Discovery (Mobile), Evasion, Execution, Execution (ICS), Execution (Mobile), Exfiltration, Exfiltration (Mobile), Impact, Impact (ICS), Impact (Mobile), Impair Process Control, Inhibit Response Function, Initial Access, Initial Access (ICS), Initial Access (Mobile), Lateral Movement, Lateral Movement (ICS), Lateral Movement (Mobile), Persistence, Persistence (ICS), Persistence (Mobile), Privilege Escalation, Privilege Escalation (ICS), Privilege Escalation (Mobile), Reconnaissance, Resource Development. Optional
hostname Comma-separated list of hostnames. Optional
src_hostname Comma-separated list of source hostnames. Optional
dest_hostname Comma-separated list of destination hostnames. Optional
username Comma-separated list of usernames. Optional
note User note content. Optional
state Filter alerts on their state. Possible values are: closed, mute, open. Optional
search A search term. Optional
action The action to perform on the alerts. Possible values are: acknowledge, open, tag, untag, note, open_related, close_related, mute_signature, unmute_signature. Required

Context Output

Path Type Description
Gatewatcher.Alerts.Status.Update string The updated status of the alerts.

gcenter103-raw-alerts-get


Get a raw alert with its UUID.

Base Command

gcenter103-raw-alerts-get

Input

Argument Name Description Required
uuid UUID of the alert to fetch (corresponds to event.id field). Required

Context Output

Path Type Description
Gatewatcher.Raw.Alerts.Get string The alert content.

gcenter103-raw-alerts-file-get


Get a file attached to an alert with its UUID.

Base Command

gcenter103-raw-alerts-file-get

Input

Argument Name Description Required
uuid UUID of the alert to fetch (corresponds to event.id field). Required

Context Output

Path Type Description
Gatewatcher.Raw.Alerts.File.Get string The zip file.

gcenter103-file-scan


Scan a file on a selected engine. You must upload the file to scan before execution.

Base Command

gcenter103-file-scan

Input

Argument Name Description Required
engine Engine that will scan the file. Possible values are: malcore, powershell, shellcode. Required
entryID Entry ID of the file to scan. Required

Context Output

Path Type Description
Gatewatcher.File.Scan string Results of the scan.

gcenter103-file-scan-result-get


Retrieve previous scan by its ID.

Base Command

gcenter103-file-scan-result-get

Input

Argument Name Description Required
id ID of a previous file scan. Required

Context Output

Path Type Description
Gatewatcher.File.Scan.Result.Get string Result of the file scan.

gcenter103-assets-list


List all assets.

Base Command

gcenter103-assets-list

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
name Comma-separated list of hostnames of the asset. Optional
tag Filter on assets containing tags. Comma-separated list of tag names. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional
sort_by The filter by which to sort the results. Possible values are: risk, -risk, name, -name. Optional
type Asset type. Possible values are: Smartphone, IoT, Laptop, Videogame, TV, Other, Firewall, Hypervisor, IPBX, Printer, Proxy, Router, Server, Storage, Virtual Machine, WAF, WiFi, unknown. Optional
note Asset note content. Optional
search A search term. Optional
page A page to select in the results set. Optional
page_size Number of results per page. Optional
fast The fast mode uses cached data to present faster results. Disabled by default. Possible values are: true, false. Optional
os_firmware OS/Firwmare of the asset. Optional
mac_address Asset MAC addresses. Optional

Context Output

Path Type Description
Gatewatcher.Assets.List string List of assets.

gcenter103-assets-alerts-get


Retrieve alerts of a given asset.

Base Command

gcenter103-assets-alerts-get

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
ids A comma-separated list of alert IDs. Optional
excluded_ids A comma-separated list of alert IDs to exclude. Optional
acknowledged Whether to filter on the acknowledgement status. Possible values are: true, false. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
src_ip Comma-separated list of source IP addresses of the alerts. Optional
dest_ip Comma-separated list of destination IP addresses of the alerts. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
name Filter on alert signature. Comma-separated list of signatures. Optional
description Filter alerts on their description. Optional
tag Filter on alerts containing tags. Comma-separated list of tag names. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional
excluded_tags Filter out alerts containing tags. Comma-separated list of tags. Logical OR between the tags. Optional
sort_by The filter by which to sort the results. Possible values are: date, -date, risk, -risk, name, -name. Optional
type The type by which to filter alerts on engines. Possible values are: active_cti, beacon_detect, dga_detect, malcore, malcore_retroanalyzer, malicious_powershell_detect, ransomware_detect, retrohunt, shellcode_detect, sigflow_alert. Optional
mitre_tactic_name Filter alert by MITRE tactic name. Possible values are: Collection, Collection (ICS), Collection (Mobile), Command and Control, Command and Control (ICS), Command and Control (Mobile), Credential Access, Credential Access (Mobile), Defense Evasion, Defense Evasion (Mobile), Discovery, Discovery (ICS), Discovery (Mobile), Evasion, Execution, Execution (ICS), Execution (Mobile), Exfiltration, Exfiltration (Mobile), Impact, Impact (ICS), Impact (Mobile), Impair Process Control, Inhibit Response Function, Initial Access, Initial Access (ICS), Initial Access (Mobile), Lateral Movement, Lateral Movement (ICS), Lateral Movement (Mobile), Persistence, Persistence (ICS), Persistence (Mobile), Privilege Escalation, Privilege Escalation (ICS), Privilege Escalation (Mobile), Reconnaissance, Resource Development. Optional
hostname Comma-separated list of hostnames. Optional
src_hostname Comma-separated list of source hostnames. Optional
dest_hostname Comma-separated list of destination hostnames. Optional
username Comma-separated list of usernames. Optional
note User note content. Optional
state Filter alerts on their state. Possible values are: closed, mute, open. Optional
page A page number within the results pages. Optional
page_size Number of results per page. Optional
asset_name Name of the asset. Required

Context Output

Path Type Description
Gatewatcher.Assets.Alerts.Get string Get alerts for an asset.

gcenter103-assets-get


Retrieve specific asset data.

Base Command

gcenter103-assets-get

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
fast The fast mode uses cached data to present faster results. Disabled by default. Possible values are: true, false. Optional
asset_name Asset name. Required

Context Output

Path Type Description
Gatewatcher.Assets.Get string Asset data.

gcenter103-assets-note-add


Add or update a note to an asset.

Base Command

gcenter103-assets-note-add

Input

Argument Name Description Required
asset_name Asset name. Required
note Note to update. Required
overwrite Whether to overwrite the note. Possible values are: true, false. Required

Context Output

Path Type Description
Gatewatcher.Assets.Note.Add string The note added or updated.

gcenter103-assets-note-remove


Remove a note from an asset.

Base Command

gcenter103-assets-note-remove

Input

Argument Name Description Required
asset_name Asset name. Required

Context Output

Path Type Description
Gatewatcher.Assets.Note.Remove string The request response code.

gcenter103-assets-tags-get


Get the tags of an asset.

Base Command

gcenter103-assets-tags-get

Input

Argument Name Description Required
asset_name Asset name. Required

Context Output

Path Type Description
Gatewatcher.Assets.Tags.Get string The tags of the asset.

gcenter103-assets-tags-add


Add or update the tags of an asset.

Base Command

gcenter103-assets-tags-add

Input

Argument Name Description Required
asset_name Asset name. Required
tags A comma-separated list of tag names to add to the asset. Required

Context Output

Path Type Description
Gatewatcher.Assets.Tags.Add string Added or updated tags of the asset.

gcenter103-assets-tags-remove


Remove tags of an asset.

Base Command

gcenter103-assets-tags-remove

Input

Argument Name Description Required
asset_name Asset name. Required
tags A comma-separated list of tag names to remove to the asset. Required

Context Output

Path Type Description
Gatewatcher.Assets.Tags.Remove string Removed tags of the asset.

gcenter103-users-list


Retrieves a list of Kerberos users.

Base Command

gcenter103-users-list

Input

Argument Name Description Required
search A search term. Optional
page A page to select in the results set. Optional
page_size Number of results per page. Optional
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
fast The fast mode uses cached data to present faster results. Disabled by default. Possible values are: true, false. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
sort_by The filter by which to sort the results. Possible values are: risk, -risk, name, -name. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
username Comma-separated list of usernames. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
hostname Comma-separated list of hostnames. Optional
tag Filter on users containing tags. Comma-separated list of tag names. Optional
note User note content. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional

Context Output

Path Type Description
Gatewatcher.Users.List string The list of Kerberos users.

gcenter103-users-alerts-get


Retrieves a list of the alerts of a Kerberos user.

Base Command

gcenter103-users-alerts-get

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
ids A comma-separated list of alert IDs. Optional
excluded_ids A comma-separated list of alert IDs to exclude. Optional
acknowledged Whether to filter on the acknowledgement status. Possible values are: true, false. Optional
gcap_id Comma-separated list of GCap IDs. First GCap has ID 1. Optional
ip Comma-separated list of IP addresses of the alerts. Optional
src_ip Comma-separated list of source IP addresses of the alerts. Optional
dest_ip Comma-separated list of destination IP addresses of the alerts. Optional
risk_min Minimal risk value. Optional
risk_max Maximal risk value. Optional
name Filter on alert signature. Comma-separated list of signatures. Optional
description Filter alerts on their description. Optional
tag Filter on users containing tags. Comma-separated list of tag names. Optional
no_tag Whether to include users with no tags. Possible values are: true, false. Optional
excluded_tags Filter out alerts containing tags. Comma-separated list of tags. Logical OR between the tags. Optional
sort_by The filter by which to sort the results. Possible values are: date, -date, risk, -risk, name, -name. Optional
type The type by which to filter alerts on engines. Possible values are: active_cti, beacon_detect, dga_detect, malcore, malcore_retroanalyzer, malicious_powershell_detect, ransomware_detect, retrohunt, shellcode_detect, sigflow_alert. Optional
mitre_tactic_name Filter alert by MITRE tactic name. Possible values are: Collection, Collection (ICS), Collection (Mobile), Command and Control, Command and Control (ICS), Command and Control (Mobile), Credential Access, Credential Access (Mobile), Defense Evasion, Defense Evasion (Mobile), Discovery, Discovery (ICS), Discovery (Mobile), Evasion, Execution, Execution (ICS), Execution (Mobile), Exfiltration, Exfiltration (Mobile), Impact, Impact (ICS), Impact (Mobile), Impair Process Control, Inhibit Response Function, Initial Access, Initial Access (ICS), Initial Access (Mobile), Lateral Movement, Lateral Movement (ICS), Lateral Movement (Mobile), Persistence, Persistence (ICS), Persistence (Mobile), Privilege Escalation, Privilege Escalation (ICS), Privilege Escalation (Mobile), Reconnaissance, Resource Development. Optional
hostname Comma-separated list of hostnames. Optional
src_hostname Comma-separated list of source hostnames. Optional
dest_hostname Comma-separated list of destination hostnames. Optional
username Comma-separated list of usernames. Optional
note User note content. Optional
state Filter alerts on their state. Possible values are: closed, mute, open. Optional
page A page number within the results pages. Optional
page_size Number of results per page. Optional
kuser_name Alerts of this Kerberos user name. Required

Context Output

Path Type Description
Gatewatcher.Users.Alerts.Get string The list of alerts of a Kerberos user.

gcenter103-users-get


Retrieves Kerberos user data.

Base Command

gcenter103-users-get

Input

Argument Name Description Required
date_from Starting date filter. ISO-8601 date format. Optional
date_to Ending data filter. ISO-8601 date format. Optional
since Not compatible with date_from and date_to parameters. Possible values are: 15d, yesterday. Optional
fast The fast mode uses cached data to present faster results. Disabled by default. Possible values are: true, false. Optional
kuser_name Alerts of this Kerberos user name. Required

Context Output

Path Type Description
Gatewatcher.Users.Get string Get information of a Kerberos user.

gcenter103-users-note-add


Add or update the note of a Kerberos user.

Base Command

gcenter103-users-note-add

Input

Argument Name Description Required
note Note content to add/update. Required
kuser_name Kerberos user name. Required
overwrite Whether to overwrite the note. Possible values are: true, false. Required

Context Output

Path Type Description
Gatewatcher.Users.Note.Add string Added/updated note.

gcenter103-users-note-remove


Remove the note of a Kerberos user.

Base Command

gcenter103-users-note-remove

Input

Argument Name Description Required
kuser_name Kerberos user name. Required

Context Output

Path Type Description
Gatewatcher.Users.Note.Remove string Request response code.

gcenter103-users-tags-get


Get the tags of a Kerberos user.

Base Command

gcenter103-users-tags-get

Input

Argument Name Description Required
kuser_name Kerberos user name to get tags of. Required

Context Output

Path Type Description
Gatewatcher.Users.Tags.Get string The tags associated to the Kerberos user.

gcenter103-users-tags-add


Add or update the tags of a Kerberos user.

Base Command

gcenter103-users-tags-add

Input

Argument Name Description Required
tags A comma-separated list of tags to add to the Kerberos user. Required
kuser_name Kerberos user name to add tags of. Required

Context Output

Path Type Description
Gatewatcher.Users.Tags.Add string Added/updated tags associated to the Kerberos user.

gcenter103-users-tags-remove


Remove tags of a Kerberos user.

Base Command

gcenter103-users-tags-remove

Input

Argument Name Description Required
tags A comma-separated list of tag names to remove to the Kerberos user. Required
kuser_name Kerberos user name to remove tags from. Required

Context Output

Path Type Description
Gatewatcher.Users.Tags.Remove string Tags of the Kerberos user.

gcenter103-yara-rules-get


Get YARA settings.

Base Command

gcenter103-yara-rules-get

Input

Argument Name Description Required
export Export state. Possible values are: true, false. Optional

Context Output

Path Type Description
Gatewatcher.Yara.Rules.Get string The YARA settings.

gcenter103-yara-rules-add


Add YARA rules to Malcore. You must upload the YARA file before execution.

Base Command

gcenter103-yara-rules-add

Input

Argument Name Description Required
enabled Set if YARA is enabled or not. Possible values are: true, false. Required
name Name of the YARA ruleset. Required
entryID EntryID of the YARA file. Required

Context Output

Path Type Description
Gatewatcher.Yara.Rules.Add string The updated YARA settings.

gcenter103-malcore-fingerprints-get


Get fingerprints of the white or black list of Malcore.

Base Command

gcenter103-malcore-fingerprints-get

Input

Argument Name Description Required
ordering The order by which the results should be sorted. Possible values are: created, sha256, user, -created, -sha256, -user. Optional
page A page to select in the results set. Optional
list_type The type of list given. Possible values are: white, black. Required

Context Output

Path Type Description
Gatewatcher.Malcore.Fingerprints.Get string Hash list informations.

gcenter103-malcore-fingerprints-add


Add fingerprints to white or black list to Malcore.

Base Command

gcenter103-malcore-fingerprints-add

Input

Argument Name Description Required
sha256 The SHA256 to add. Required
comment An attached comment (200 chars max). Required
threat Name of the threat for reference (100 chars max). Required
list_type The type of list given. Possible values are: white, black. Required

Context Output

Path Type Description
Gatewatcher.Malcore.Fingerprints.Add string Hash list informations.

gcenter103-malcore-fingerprints-remove


Remove fingerprints to white or black list to Malcore.

Base Command

gcenter103-malcore-fingerprints-remove

Input

Argument Name Description Required
sha256 The SHA256 to remove. Required
list_type The type of list to remove from. Possible values are: white, black. Required

Context Output

Path Type Description
Gatewatcher.Malcore.Fingerprints.Remove string Hash list informations.

Configuration parameters

  • ip — GCenter IP address or FQDN (required)
  • token
  • credentials — GCenter account
  • version — GCenter Version
  • check_cert — Check the TLS certificate
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents
  • fetch_type — Fetch incidents from type
  • engine_selection — Engine alerts selection
  • first_fetch — First fetch
  • max_fetch — Fetch limit
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval

Commands (33)

  • gcenter103-alerts-get

    Get an alert with its UUID (corresponds to event.id field) or the GCenter ID of the alert.

  • gcenter103-alerts-list

    List all alerts.

  • gcenter103-alerts-note-add

    Add or update a note to an alert.

  • gcenter103-alerts-note-remove

    Delete the note of an alert.

  • gcenter103-alerts-status-update

    Update status of an alert.

  • gcenter103-alerts-tags-add

    Add or update tags of an alert.

  • gcenter103-alerts-tags-get

    Get the tags of an alert.

  • gcenter103-alerts-tags-remove

    Remove tags from an alert.

  • gcenter103-assets-alerts-get

    Retrieve alerts of a given asset.

  • gcenter103-assets-get

    Retrieve specific asset data.

  • gcenter103-assets-list

    List all assets.

  • gcenter103-assets-note-add

    Add or update a note to an asset.

  • gcenter103-assets-note-remove

    Remove a note from an asset.

  • gcenter103-assets-tags-add

    Add or update the tags of an asset.

  • gcenter103-assets-tags-get

    Get the tags of an asset.

  • gcenter103-assets-tags-remove

    Remove tags of an asset.

  • gcenter103-file-scan

    Scan a file on a selected engine. You must upload the file to scan before execution.

  • gcenter103-file-scan-result-get

    Retrieve previous scan by its ID.

  • gcenter103-malcore-fingerprints-add

    Add fingerprints to white or black list to Malcore.

  • gcenter103-malcore-fingerprints-get

    Get fingerprints of the white or black list of Malcore.

  • gcenter103-malcore-fingerprints-remove

    Remove fingerprints to white or black list to Malcore.

  • gcenter103-raw-alerts-file-get

    Get a file attached to an alert with its UUID.

  • gcenter103-raw-alerts-get

    Get a raw alert with its UUID.

  • gcenter103-users-alerts-get

    Retrieves a list of the alerts of a Kerberos user.

  • gcenter103-users-get

    Retrieves Kerberos user data.

  • gcenter103-users-list

    Retrieves a list of Kerberos users.

  • gcenter103-users-note-add

    Add or update the note of a Kerberos user.

  • gcenter103-users-note-remove

    Remove the note of a Kerberos user.

  • gcenter103-users-tags-add

    Add or update the tags of a Kerberos user.

  • gcenter103-users-tags-get

    Get the tags of a Kerberos user.

  • gcenter103-users-tags-remove

    Remove tags of a Kerberos user.

  • gcenter103-yara-rules-add

    Add YARA rules to Malcore. You must upload the YARA file before execution.

  • gcenter103-yara-rules-get

    Get YARA settings.

from datetime import datetime
from unittest.mock import MagicMock, Mock, patch

import demistomock as demisto  # noqa: F401
import GCenter103
import pytest
import yaml
from CommonServerPython import *
from pytest_mock import MockerFixture


def test_convert_event_severity():
    """
    Given:
     - A severity integer (0, 1, 2, 3).
    When:
     - Calling the convert_event_severity function.
    Then:
     - Ensure the correct mapped severity is returned. If the severity is not recognized, return 0.
    """
    from GCenter103 import convert_event_severity

    assert convert_event_severity(0) == 0.5
    assert convert_event_severity(1) == 4
    assert convert_event_severity(2) == 2
    assert convert_event_severity(3) == 1
    # Test an unmapped severity
    assert convert_event_severity(999) == 0


def test_gw_client_auth_success():
    """
    Given:
     - A GwClient instance with username/password.
     - The server returns a 200 status code and a token in JSON.
    When:
     - The auth method is called.
    Then:
     - The client.headers dict should contain the 'API-KEY'.
    """
    from GCenter103 import GwClient

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"token": "testtoken"}

    with patch.object(GwClient, "_post", return_value=mock_response):
        client = GwClient(ip="fake_ip")
        client.auth(user="test_user", password="test_pass")
        assert client.headers.get("API-KEY") == "testtoken"


def test_gw_client_auth_failure():
    """
    Given:
     - A GwClient instance with wrong credentials.
     - The server returns a non-200 status code.
    When:
     - The auth method is called.
    Then:
     - GwAPIException is raised due to failed authentication.
    """
    from GCenter103 import GwAPIException, GwClient

    mock_response = MagicMock()
    mock_response.status_code = 401
    mock_response.reason = "Unauthorized"
    mock_response.text = "Invalid credentials"

    with patch.object(GwClient, "_post", return_value=mock_response):
        client = GwClient(ip="fake_ip")
        with pytest.raises(GwAPIException):
            client.auth(user="wrong_user", password="wrong_pass")


def test_gw_client_is_authenticated_true():
    """
    Given:
     - A GwClient instance that has valid session info.
     - The server's _get call returns status code 200.
    When:
     - is_authenticated is called.
    Then:
     - The function should return True.
    """
    from GCenter103 import GwClient

    mock_response = MagicMock()
    mock_response.status_code = 200

    with patch.object(GwClient, "_get", return_value=mock_response):
        client = GwClient(ip="fake_ip")
        assert client.is_authenticated() is True


def test_last_run_range_no_last_run(mocker):
    """
    Given:
     - No previous last run data (demisto.getLastRun() returns an empty dict).
     - A 'first_fetch' param specifying an offset time, e.g., '1 day'.
    When:
     - last_run_range is called.
    Then:
     - It returns a list of two strings [start_time, end_time].
       The start_time is the computed 'first_fetch_dt', and the end_time is the current time.
    """
    from GCenter103 import last_run_range

    # 1) Patch demisto.getLastRun to return an empty dict (first fetch).
    mocker.patch.object(demisto, "getLastRun", return_value={})

    # 2) Patch the datetime module in GCenter103 so that 'today()' returns a fixed date.
    fixed_now = datetime(2025, 1, 1, 10, 0, 0)
    mock_datetime = mocker.patch("GCenter103.datetime")
    mock_datetime.today.return_value = fixed_now
    mock_datetime.side_effect = lambda *args, **kw: datetime(*args, **kw)

    # 3) Call the function under test.
    params = {"first_fetch": "1 day"}
    from_to = last_run_range(params=params)

    # 4) Basic assertions: we have a start time and an end time.
    assert len(from_to) == 2
    # The second element should contain our fixed timestamp "2025-01-01T10:00:00"
    assert "2025-01-01T10:00:00" in from_to[1]


def test_last_run_range_has_last_run(mocker):
    """
    Given:
     - A last run exists in demisto's context with a specific start_time.
    When:
     - last_run_range is called.
    Then:
     - It returns [last_start_time, now].
    """
    from GCenter103 import last_run_range

    # 1) Patch demisto.getLastRun to simulate an existing last run time.
    mocker.patch.object(demisto, "getLastRun", return_value={"start_time": "2025-01-01T00:00:00Z"})

    # 2) Patch the datetime module to control the current time.
    fixed_now = datetime(2025, 1, 2, 12, 0, 0)
    mock_datetime = mocker.patch("GCenter103.datetime")
    mock_datetime.today.return_value = fixed_now
    mock_datetime.side_effect = lambda *args, **kw: datetime(*args, **kw)

    # 3) Call the function under test.
    params = {"first_fetch": "1 day"}
    from_to = last_run_range(params=params)

    # 4) Validate that we get [stored_start_time, now].
    assert len(from_to) == 2
    assert from_to[0] == "2025-01-01T00:00:00Z"
    assert "2025-01-02T12:00:00" in from_to[1]


def test_fix_broken_list_valid_str():
    """
    Given:
     - A valid 'engine_selection' string that contains known engine names.
    When:
     - fix_broken_list is called.
    Then:
     - Verify we only return known engines from the string.
    """
    from GCenter103 import fix_broken_list

    params = {"engine_selection": "malcore,shellcode_detect,unknown_engine"}
    result = fix_broken_list(params)
    # 'unknown_engine' should not appear
    assert "unknown_engine" not in result


def test_fix_broken_list_valid_list():
    """
    Given:
     - A valid 'engine_selection' list that contains known and unknown engine names.
    When:
     - fix_broken_list is called.
    Then:
     - Verify we only return known engines from the list.
    """
    from GCenter103 import fix_broken_list

    params = {"engine_selection": ["dga_detect", "ransomware_detect", "nonexistent"]}
    result = fix_broken_list(params)
    assert set(result) == {"dga_detect", "ransomware_detect"}, f"Expected ['dga_detect','ransomware_detect'] but got {result}"


def test_fix_broken_list_invalid():
    """
    Given:
     - An invalid 'engine_selection' key or type in params (e.g., missing or not str/list).
    When:
     - fix_broken_list is called.
    Then:
     - A ValueError is raised.
    """
    from GCenter103 import fix_broken_list

    params = {
        "engine_selection": 12345  # Not a valid type
    }
    with pytest.raises(ValueError):
        fix_broken_list(params)


def test_gw_client_auth_token_only():
    """
    Given:
     - Params has a token but no user/password.
    When:
     - gw_client_auth is called.
    Then:
     - The client is created and its headers contain the API-KEY equal to the token.
    """
    from GCenter103 import GwClient, gw_client_auth

    with patch.object(GwClient, "auth", return_value=None) as mock_auth:
        params = {"ip": "1.2.3.4", "token": {"password": "testtoken"}, "credentials": {"identifier": "", "password": ""}}
        client = gw_client_auth(params=params)
        mock_auth.assert_called_once()
        assert client.headers.get("API-KEY") == "testtoken"


def test_gw_client_auth_missing_all():
    """
    Given:
     - Params has no token, no user, no password.
    When:
     - gw_client_auth is called.
    Then:
     - We expect an AttributeError because user/password/token are all missing.
    """
    from GCenter103 import gw_client_auth

    params = {"ip": "1.2.3.4", "credentials": {"identifier": "", "password": ""}, "token": None}
    with pytest.raises(AttributeError):
        gw_client_auth(params=params)


def test_index_alerts_incidents():
    """
    Given:
     - A list of alert hits from ES (to_index).
    When:
     - index_alerts_incidents is called.
    Then:
     - We return a properly structured list of incidents with correct fields.
    """
    from GCenter103 import index_alerts_incidents

    sample_hits = [
        {
            "_source": {
                "event": {"id": "alert123", "module": "malcore", "severity": 1},
                "source": {"ip": "1.1.1.1"},
                "destination": {"ip": "2.2.2.2"},
                "@timestamp": "2025-01-01T12:00:00Z",
            },
            "sort": [9999],
        }
    ]
    params = {"ip": "1.2.3.4"}
    # Run the function
    results = index_alerts_incidents(sample_hits, params)
    # Check that we have 1 incident with the correct fields
    assert len(results) == 1
    incident = results[0]
    assert incident["name"] == "Gatewatcher Alert: malcore"
    assert incident["occurred"] == "2025-01-01T12:00:00Z"
    assert incident["dbotMirrorId"] == "alert123"
    assert incident["severity"] == 4  # from convert_event_severity(1)
    assert incident["CustomFields"]["GatewatcherRawEvent"] is not None


def test_index_metadata_incidents():
    """
    Given:
     - A list of metadata hits from ES (to_index).
    When:
     - index_metadata_incidents is called.
    Then:
     - We return a properly structured list of incidents with correct fields.
    """
    from GCenter103 import index_metadata_incidents

    sample_hits = [
        {
            "_source": {
                "event": {"id": "meta123", "module": "beacon_detect", "severity": 0},
                "source": {"ip": "3.3.3.3"},
                "destination": {"ip": "4.4.4.4"},
                "@timestamp": "2025-01-02T12:00:00Z",
            },
            "sort": [1111],
        }
    ]
    results = index_metadata_incidents(sample_hits)
    assert len(results) == 1
    incident = results[0]
    assert incident["name"] == "Gatewatcher Metadata: beacon_detect"
    assert incident["occurred"] == "2025-01-02T12:00:00Z"
    assert incident["dbotMirrorId"] == "meta123"
    assert incident["severity"] == 0.5  # from convert_event_severity(0)


def test_query_selected_engines_builder():
    """
    Given:
     - max_fetch, engine_selection, from_to range.
    When:
     - query_selected_engines_builder is called.
    Then:
     - The generated query includes 'match' for the first engine and a timestamp range.
    """
    from GCenter103 import query_selected_engines_builder

    engine_selection = ["malcore", "shellcode_detect"]
    from_to = ["2025-01-01T00:00:00Z", "2025-01-02T00:00:00Z"]
    query = query_selected_engines_builder(max_fetch=5000, engine_selection=engine_selection, from_to=from_to)
    assert query["size"] == 5000
    assert query["query"]["bool"]["must"][0]["match"]["event.module"] == "malcore"
    assert query["query"]["bool"]["must"][1]["range"]["@timestamp"]["gt"] == "2025-01-01T00:00:00Z"


def test_query_empty_selected_engines_builder():
    """
    Given:
     - A from_to range and max_fetch.
    When:
     - query_empty_selected_engines_builder is called.
    Then:
     - The generated query doesn't contain a 'match' on 'event.module', only a time range.
    """
    from GCenter103 import query_empty_selected_engines_builder

    from_to = ["2025-01-01T00:00:00Z", "2025-01-02T00:00:00Z"]
    query = query_empty_selected_engines_builder(from_to=from_to, max_fetch=9999)
    assert query["size"] == 9999
    assert "range" in query["query"]
    assert "@timestamp" in query["query"]["range"]
    assert "match" not in query["query"]


@pytest.mark.parametrize(
    "engine_list,fetch_type,max_fetch",
    [
        (["malcore"], "Alerts", 5),
        (["malcore", "shellcode_detect"], "Both", 12000),
        ([], "Alerts", 5),  # Should go to fetch_empty_selected_engines
    ],
)
def test_fetch_incidents(mocker, engine_list, fetch_type, max_fetch):
    """
    Given:
     - Different engine_list setups (empty or not), different fetch_type, and different max_fetch.
    When:
     - fetch_incidents is called.
    Then:
     - The correct sub-function (fetch_selected_engines or fetch_empty_selected_engines) is invoked.
     - The final demisto.incidents(...) is called with a list of built incidents.
    """
    from GCenter103 import GwClient, demisto, fetch_incidents

    # Patch demisto methods using mocker.patch.object
    mocker.patch.object(
        demisto,
        "params",
        return_value={
            "ip": "1.2.3.4",
            "fetch_type": fetch_type,
            "max_fetch": max_fetch,
            "engine_selection": engine_list,
            "credentials": {"identifier": "", "password": ""},
            "token": "dummy_token",
        },
    )
    mocker.patch.object(demisto, "getLastRun", return_value={})
    mock_set_last_run = mocker.patch.object(demisto, "setLastRun")
    mock_incidents = mocker.patch.object(demisto, "incidents")

    # Patch subfunctions within GCenter103
    mock_sel = mocker.patch(
        "GCenter103.fetch_selected_engines", return_value=[{"name": "TestIncidentSelected", "occurred": "2025-01-01T12:00:00Z"}]
    )
    mock_emp = mocker.patch(
        "GCenter103.fetch_empty_selected_engines",
        return_value=[{"name": "TestIncidentEmpty", "occurred": "2025-01-01T12:00:00Z"}],
    )
    mocker.patch("GCenter103.gw_client_auth", return_value=MagicMock(spec=GwClient))

    # Execute
    fetch_incidents(client=client)

    # Verify
    if engine_list:
        # We used fetch_selected_engines
        mock_sel.assert_called_once()
        mock_emp.assert_not_called()
        mock_incidents.assert_called_once_with(incidents=[{"name": "TestIncidentSelected", "occurred": "2025-01-01T12:00:00Z"}])
    else:
        # We used fetch_empty_selected_engines
        mock_emp.assert_called_once()
        mock_sel.assert_not_called()
        mock_incidents.assert_called_once_with(incidents=[{"name": "TestIncidentEmpty", "occurred": "2025-01-01T12:00:00Z"}])

    # In both scenarios, last run should be set
    mock_set_last_run.assert_called_once()


@pytest.fixture
def mock_gw_client(mocker):
    """
    Fixture creating a mock GwClient instance with basic _post, _get stubs.
    """
    from GCenter103 import GwClient

    client = GwClient(ip="fake_ip")
    return client


def test_fix_broken_list_str(mocker):
    """
    Given:
     - A params dictionary with 'engine_selection' set to a string containing known engine keywords.
    When:
     - fix_broken_list is called.
    Then:
     - We get only the matching engines in a list.
    """
    from GCenter103 import fix_broken_list

    params = {"engine_selection": "malcore,random,sigflow_alert"}
    result = fix_broken_list(params)
    # Known engines are: "malcore", "sigflow_alert"
    assert len(result) == 2
    assert "malcore" in result
    assert "sigflow_alert" in result


def test_fix_broken_list_list(mocker):
    """
    Given:
     - A params dictionary with 'engine_selection' as a list containing known engine keywords.
    When:
     - fix_broken_list is called.
    Then:
     - We get only the valid engines from that list.
    """
    from GCenter103 import fix_broken_list

    params = {"engine_selection": ["malcore", "abc", "shellcode_detect"]}
    result = fix_broken_list(params)
    assert len(result) == 2
    assert "malcore" in result
    assert "shellcode_detect" in result


def test_fix_broken_list_invalid_param(mocker):
    """
    Given:
     - A params dictionary missing engine_selection or with invalid type.
    When:
     - fix_broken_list is called.
    Then:
     - A ValueError is raised.
    """
    from GCenter103 import fix_broken_list

    with pytest.raises(ValueError):
        fix_broken_list({"no_engine_selection": True})
    with pytest.raises(ValueError):
        fix_broken_list({"engine_selection": 123})  # not str or list


def test_query_es_alerts(mocker, mock_gw_client):
    """
    Given:
     - A GwClient and a query dict.
    When:
     - query_es_alerts is called and the response has hits.hits data.
    Then:
     - The function returns hits.hits from the JSON response.
    """
    from GCenter103 import query_es_alerts

    mock_response = MagicMock(spec=requests.Response)
    mock_response.json.return_value = {"hits": {"hits": [{"_id": "1"}]}}
    mock_gw_client._post = MagicMock(return_value=mock_response)

    q = {"query": {"match_all": {}}}
    hits = query_es_alerts(mock_gw_client, q)
    assert hits == [{"_id": "1"}]


def test_query_es_alerts_empty(mocker, mock_gw_client):
    """
    Given:
     - A GwClient and a query dict.
    When:
     - query_es_alerts is called and hits.hits is empty.
    Then:
     - An empty dict is returned.
    """
    from GCenter103 import query_es_alerts

    mock_response = MagicMock(spec=requests.Response)
    mock_response.json.return_value = {"hits": {"hits": []}}
    mock_gw_client._post = MagicMock(return_value=mock_response)

    q = {"query": {"match_all": {}}}
    hits = query_es_alerts(mock_gw_client, q)
    assert hits is None


def test_query_es_metadata(mocker, mock_gw_client):
    """
    Given:
     - A GwClient and a query dict.
    When:
     - query_es_metadata is called and the response has hits.hits data.
    Then:
     - The function returns hits.hits from the JSON response.
    """
    from GCenter103 import query_es_metadata

    mock_response = MagicMock(spec=requests.Response)
    mock_response.json.return_value = {"hits": {"hits": [{"_id": "m1"}]}}
    mock_gw_client._post = MagicMock(return_value=mock_response)

    q = {"query": {"match_all": {}}}
    hits = query_es_metadata(mock_gw_client, q)
    assert hits == [{"_id": "m1"}]


def test_gw_client_auth(mocker):
    """
    Given:
     - A params dict with user/password or token.
    When:
     - gw_client_auth is called.
    Then:
     - Returns a GwClient with the authentication set.
    """
    from GCenter103 import gw_client_auth

    mocker.patch("GCenter103.GwClient.auth", return_value=None)
    params = {
        "ip": "1.1.1.1",
        "token": {"password": ""},
        "credentials": {"identifier": "admin", "password": "admin"},
        "check_cert": False,
    }
    client = gw_client_auth(params)
    assert client.ip == "1.1.1.1"


def test_handle_little_fetch_empty_selected_engines_alerts(mocker, mock_gw_client):
    """
    Given:
     - fetch_type in ("Alerts", "Both").
     - query_es_alerts returning some hits.
    When:
     - handle_little_fetch_empty_selected_engines is called.
    Then:
     - The returned data is not empty (the alerts).
    """
    from GCenter103 import handle_little_fetch_empty_selected_engines

    mock_response = [{"_id": "abc"}]
    mocker.patch("GCenter103.query_es_alerts", return_value=mock_response)

    query = {"query": {"bool": {"must": []}}}
    res = handle_little_fetch_empty_selected_engines(mock_gw_client, "Alerts", query)
    assert res == mock_response


def test_handle_little_fetch_empty_selected_engines_not_alerts(mocker, mock_gw_client):
    """
    Given:
     - fetch_type = "Metadata" (no alerts).
     When:
     - handle_little_fetch_empty_selected_engines is called.
    Then:
     - The function returns an empty dict (no alerts fetched).
    """
    from GCenter103 import handle_little_fetch_empty_selected_engines

    query = {"query": {"bool": {"must": []}}}
    res = handle_little_fetch_empty_selected_engines(mock_gw_client, "Metadata", query)
    assert res == [{}]  # no alerts if fetch_type == "Metadata"


def test_main_test_module(mocker):
    """
    Given:
     - demisto.command returns 'test-module'.
     - The client authenticates successfully.
    When:
     - main is called.
    Then:
     - test_module is executed, and 'ok' is returned as a result.
    """
    from GCenter103 import main

    # 1) Patch demisto commands/params
    mocker.patch.object(demisto, "command", return_value="test-module")
    mocker.patch.object(
        demisto,
        "params",
        return_value={"ip": "1.1.1.1", "token": {"password": ""}, "credentials": {"identifier": "admin", "password": "admin"}},
    )
    mocker.patch.object(demisto, "args", return_value={})

    # 2) Patch `return_results` from the correct module path.
    mocked_return_results = mocker.patch("GCenter103.return_results")

    # 3) Mock GwClient so it doesn't do real auth
    client_mock = mocker.patch("GCenter103.GwClient", autospec=True).return_value
    client_mock.is_authenticated.return_value = True

    # 4) Run main
    main()

    # 5) Verify test_module returned "ok"
    mocked_return_results.assert_called_with("ok")


def test_main_fetch_incidents(mocker):
    """
    Given:
     - demisto.command returns 'fetch-incidents'.
    When:
     - main is called.
    Then:
     - fetch_incidents is invoked and passes a real list of incidents to return_results.
    """
    from GCenter103 import main

    # 1) Patch demisto commands/params
    mocker.patch.object(demisto, "command", return_value="fetch-incidents")
    mocker.patch.object(
        demisto,
        "params",
        return_value={"ip": "1.1.1.1", "fetch_type": "Alerts", "credentials": {"identifier": "admin", "password": "admin"}},
    )
    mocker.patch.object(demisto, "args", return_value={})

    # 2) Patch `return_results` from the correct module path.
    mocked_return_results = mocker.patch("GCenter103.return_results")

    # 3) Mock out GwClient so we don't do real auth
    mocker.patch("GCenter103.GwClient")

    # 4) Make `fetch_incidents` return a **real list** (not MagicMock)
    #    so JSON serialization won't fail.
    mock_incidents = [{"name": "test_incident", "occurred": "2025-01-01T00:00:00Z", "type": "Gatewatcher Incident"}]
    mocker.patch("GCenter103.fetch_incidents", return_value=mock_incidents)

    # 5) Execute main
    main()

    # 6) Confirm return_results was called with that real list
    #    (The actual call structure is [mock_incidents], but
    #     mocker captures the first positional arg from call_args[0]).
    called_arg = mocked_return_results.call_args[0][0]
    assert called_arg == mock_incidents


def test_handle_big_fetch_selected_engines_alerts(mocker):
    """
    Given:
     - fetch_type = "Alerts".
     - engine_selection has multiple engines (e.g., ["engineA", "engineB"]).
     - query_es_alerts returns chunks of alerts, each with a 'sort' key.
     - max_fetch is large enough to trigger multiple while-loop iterations.
    When:
     - handle_big_fetch_selected_engines is called.
    Then:
     - All fetched alerts from multiple engines are combined and returned.
     - search_after is updated repeatedly in the query.
    """
    from GCenter103 import handle_big_fetch_selected_engines

    mock_client = MagicMock()

    def mock_query_es_alerts_side_effect(*args, **kwargs):
        query = kwargs.get("query", {})
        # Distinguish the first chunk from the second chunk by checking
        # if 'search_after' is in the query
        if "search_after" not in query:
            # first chunk
            return [{"sort": [100], "_source": {"event": {"id": "id1"}}}, {"sort": [101], "_source": {"event": {"id": "id2"}}}]
        else:
            # second chunk
            return [{"sort": [200], "_source": {"event": {"id": "id3"}}}, {"sort": [201], "_source": {"event": {"id": "id4"}}}]

    mocker.patch("GCenter103.query_es_alerts", side_effect=mock_query_es_alerts_side_effect)

    initial_query = {
        "size": 0,
        "query": {"bool": {"must": [{"match": {"event.module": "engineA"}}, {"range": {"@timestamp": {"gt": "2025-01-01"}}}]}},
    }
    engine_selection = ["engineA", "engineB"]
    max_fetch = 1  # Ensure nb_req=0 => nb_req=1 => 1 iteration => 2 calls total/engine
    fetch_type = "Alerts"

    results = handle_big_fetch_selected_engines(
        client=mock_client, query=initial_query, engine_selection=engine_selection, max_fetch=max_fetch, fetch_type=fetch_type
    )

    # Each engine => 4 total items (2 per call * 2 calls).
    # We have 2 engines => 8 total.
    assert len(results) == 4
    # Confirm query had 'size' set to 10000
    assert initial_query["size"] == 10000
    # Confirm each chunk's 'search_after' was updated in the while loop
    # The final value should have been reset to [] after engineB is processed.
    assert "search_after" not in initial_query


def test_handle_big_fetch_selected_engines_no_alerts(mocker):
    """
    Given:
     - fetch_type = "Metadata" (the code *still* fetches alerts in the for-loop).
    When:
     - handle_big_fetch_selected_engines is called.
    Then:
     - We confirm that calls to query_es_alerts return our dummy item,
       and the final list matches it, e.g. 4 items if we have 2 engines.
    """
    from GCenter103 import handle_big_fetch_selected_engines

    mock_client = MagicMock()

    def mock_query_es_alerts_side_effect(*args, **kwargs):
        return [{"_source": {"event": {"id": "dummy"}}, "sort": [999]}]

    mocker.patch("GCenter103.query_es_alerts", side_effect=mock_query_es_alerts_side_effect)

    # Correctly define query_mock as a dict with the structure your code expects
    query_mock = {
        "size": 0,
        "query": {"bool": {"must": [{"match": {"event.module": "engineA"}}, {"range": {"@timestamp": {"gt": "2025-01-01"}}}]}},
    }
    engine_selection = ["engineA", "engineB"]
    max_fetch = 20000
    fetch_type = "Metadata"

    results = handle_big_fetch_selected_engines(
        client=mock_client, query=query_mock, engine_selection=engine_selection, max_fetch=max_fetch, fetch_type=fetch_type
    )
    assert results == []


@pytest.mark.parametrize(
    "max_fetch_val, fetch_type_val, returned_alerts, returned_metadata",
    [
        # 1) Big fetch scenario (max_fetch > 10000), "Both" => calls big-fetch logic for both alerts+metadata
        (15000, "Both", [{"_source": {"event": {"id": "alert1"}}}], [{"_source": {"event": {"id": "meta1"}}}]),
        # 2) Small fetch scenario (max_fetch <= 10000), "Alerts" => calls little-fetch for alerts
        (5000, "Alerts", [{"_source": {"event": {"id": "alert2"}}}], []),
        # 3) Another small fetch scenario with "Both"
        (5000, "Both", [{"_source": {"event": {"id": "alert3"}}}], [{"_source": {"event": {"id": "meta3"}}}]),
    ],
)
def test_fetch_selected_engines(mocker, max_fetch_val, fetch_type_val, returned_alerts, returned_metadata):
    """
    Given:
     - A non-empty engine_selection.
     - max_fetch can be above or below 10000.
     - Different fetch_type ("Alerts", "Both", etc.).
    When:
     - fetch_selected_engines is called.
    Then:
     - The correct big or little fetch helper is used, and the results are combined with indexing.
    """
    from GCenter103 import fetch_selected_engines

    # 1) Patch last_run_range to avoid real datetime calls
    mocker.patch("GCenter103.last_run_range", return_value=["2025-01-01T00:00:00Z", "2025-01-02T00:00:00Z"])

    # 2) Patch the big fetch or little fetch calls
    mock_handle_big_fetch_selected_engines = mocker.patch(
        "GCenter103.handle_big_fetch_selected_engines", return_value=returned_alerts
    )
    mock_handle_big_fetch_metadata = mocker.patch("GCenter103.handle_big_fetch_metadata", return_value=returned_metadata)

    mock_handle_little_fetch_alerts = mocker.patch("GCenter103.handle_little_fetch_alerts", return_value=returned_alerts)
    mock_handle_little_fetch_metadata = mocker.patch("GCenter103.handle_little_fetch_metadata", return_value=returned_metadata)

    # 3) Patch index functions to simply return the incidents back
    def mock_index_alerts_incidents(to_index, params):
        # Just append them with a placeholder structure
        return [{"name": "Alert", "occurred": "2025-01-01T00:00:00Z"}]

    def mock_index_metadata_incidents(to_index):
        return [{"name": "Meta", "occurred": "2025-01-02T00:00:00Z"}]

    mocker.patch("GCenter103.index_alerts_incidents", side_effect=mock_index_alerts_incidents, return_value=returned_alerts)
    mocker.patch("GCenter103.index_metadata_incidents", side_effect=mock_index_metadata_incidents, return_value=returned_metadata)

    mock_client = MagicMock()  # pretend we have a real client
    engine_selection = ["suricata"]
    params = {"ip": "1.1.1.1"}  # minimal for test

    # 4) Call function under test
    results = fetch_selected_engines(
        client=mock_client, engine_selection=engine_selection, params=params, max_fetch=max_fetch_val, fetch_type=fetch_type_val
    )

    # 5) Then: check logic paths
    if max_fetch_val > 10000:
        # big fetch
        mock_handle_big_fetch_selected_engines.assert_called_once()
        if fetch_type_val in ("Both", "Alerts"):
            # We should see calls to big fetch for alerts
            mock_handle_big_fetch_metadata.assert_called_once()
        else:
            mock_handle_big_fetch_metadata.assert_not_called()
        mock_handle_little_fetch_alerts.assert_not_called()
        mock_handle_little_fetch_metadata.assert_not_called()
    else:
        # little fetch
        mock_handle_little_fetch_alerts.assert_called_once()
        if fetch_type_val in ("Both", "Alerts"):
            mock_handle_little_fetch_alerts.assert_called_once()
        if fetch_type_val in ("Both", "Metadata"):
            mock_handle_little_fetch_metadata.assert_called_once()
        mock_handle_big_fetch_selected_engines.assert_not_called()
        mock_handle_big_fetch_metadata.assert_not_called()

    # Also verify the final incidents list structure
    if returned_alerts:
        assert results[0]["name"] == "Alert"
    if returned_metadata:
        assert results[1]["name"] == "Meta"
    # If we get no alerts or metadata, results is empty


with open("test_data/test_commands_data.dat") as yaml_file:
    _data_as_dict = cast(dict[str, list[dict]], yaml.Loader(yaml_file).get_data())

TEST_COMMANDS_DATA = []
for func_name, func_data in _data_as_dict.items():
    for scenario in func_data:
        TEST_COMMANDS_DATA.append((func_name, scenario))

IP = "10.10.10.10"
USERNAME = "username"
PASSWORD = "password"


def mock_login(requests_mock, code: int = 200) -> None:
    """Setup the mock for a login."""
    requests_mock.post(
        f"https://{IP}/api/v1/auth/login",
        json={
            "token": "hdkxo7ybuzpfenkmlioo2parm196yyvg",
            "expiration_date": "2022-04-23T15:11:30.297457",
        },
        status_code=code,
    )


@pytest.fixture
def client(requests_mock) -> GCenter103.GwClient:
    """Gcenter client used in this test module."""
    mock_login(requests_mock)
    client = GCenter103.GwClient(ip=IP)
    client.auth(user=USERNAME, password=PASSWORD)
    return client


@pytest.mark.parametrize("func_name, func_test", TEST_COMMANDS_DATA)
def test_gcenter103_command(mocker: MockerFixture, func_name: str, func_test: dict, client: GCenter103.GwClient) -> None:
    """This generic function can be used to test any gcenter function, by defining a test in the json file associated.

    The fields defining a test are the following:
    - comment: Comment about this particular test.
    - command_args: Arguments to be used for the command test.
    - command_kwargs: Keyword arguments to be used for the command test.
    - exec_data: Returned data of the gcap low-level query.
    - output_data: Value of the gcap command result.
    """

    mocker.patch("requests.api.request", Mock())

    command_args: list = func_test.get("command_args")
    command_kwargs: dict = func_test.get("command_kwargs")
    requests.api.request.side_effect = func_test.get("exec_data")
    output_data = func_test.get("output_data")
    command_result = getattr(GCenter103, func_name)(*command_args, **command_kwargs)

    assert command_result.__dict__
    assert command_result.__dict__.get("outputs_prefix") == output_data.__dict__.get("outputs_prefix")


def test_test_module() -> None:
    from GCenter103 import GwClient

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"token": "testtoken"}

    with patch.object(GwClient, "_post", return_value=mock_response):
        client = GwClient(ip="fake_ip")
        client.auth(user="test_user", password="test_pass")
        assert client.headers.get("API-KEY") == "testtoken"
        mock_auth_response = MagicMock()
        mock_auth_response.status_code = 200
        mock_auth_response.json.return_value = {}
        with patch.object(GwClient, "_get", return_value=mock_auth_response):
            assert client.is_authenticated()


def test_get_tags_ids() -> None:
    from GCenter103 import GwClient, get_tags_ids

    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"token": "testtoken"}

    with patch.object(GwClient, "_post", return_value=mock_response):
        client = GwClient(ip="fake_ip")
        client.auth(user="test_user", password="test_pass")
        assert client.headers.get("API-KEY") == "testtoken"

        mock_response = MagicMock()
        mock_response.status_code = 200
        mock_response.json.return_value = {"results": [{"id": "1", "label": "tag"}]}
        with patch.object(GwClient, "_get", return_value=mock_response):
            assert get_tags_ids(client=client, tags_args=["tag"]) == {"tag": "1"}