diff --git a/Packs/CofenseTriage/.pack-ignore b/Packs/CofenseTriage/.pack-ignore
index 9ba23337edf3..0a75216b525f 100644
--- a/Packs/CofenseTriage/.pack-ignore
+++ b/Packs/CofenseTriage/.pack-ignore
@@ -12,4 +12,53 @@ ignore=IM111
[known_words]
cofense
-
+cofens
+lt
+lteq
+gt
+gteq
+d
+updation
+s
+md
+assignee
+x
+ss
+vp
+ztrv
+fc
+v
+vq
+m
+nt
+vdv
+sm
+yx
+jv
+tp
+h
+qfz
+crlf
+xlsm
+br
+xl
+categorizations
+n
+mw
+dg
+dc
+j
+tc
+r
+vlet
+kn
+nstrings
+ctt
+b
+submi
+srctag
+phenotypes
+commentable
+jpg
+png
+rgba
\ No newline at end of file
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.py b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.py
index 6e381ff50fb9..47a3767f7ac3 100644
--- a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.py
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.py
@@ -35,7 +35,9 @@
"COMMENTS": "api/public/v2/comments/",
"REPORT_ID": "api/public/v2/reports/{}",
"CLUSTER": "api/public/v2/clusters",
- "REPORT_ATTACHMENT_PAYLOAD": "/api/public/v2/reports/{}/attachment_payloads"
+ "REPORT_ATTACHMENT_PAYLOAD": "/api/public/v2/reports/{}/attachment_payloads",
+ "REPORT_ATTACHMENT": "/api/public/v2/reports/{}/attachments",
+ "REPORT_ATTACHMENT_DOWNLOAD": "api/public/v2/attachments/{}/download",
}
OUTPUT_PREFIX = {
@@ -46,6 +48,7 @@
"RULE": "Cofense.Rule",
"REPORTER": "Cofense.Reporter",
"ATTACHMENT_PAYLOAD": "Cofense.AttachmentPayload",
+ "ATTACHMENT": "Cofense.Attachment",
"INTEGRATION_SUBMISSION": "Cofense.IntegrationSubmission",
"COMMENT": "Cofense.Comment",
"CLUSTER": "Cofense.Cluster"
@@ -985,6 +988,35 @@ def prepare_hr_for_attachment_payloads(results: List[Dict[str, Any]]) -> str:
UPDATED_AT], removeNull=True)
+def prepare_hr_for_report_attachments(results: List[Dict[str, Any]]) -> str:
+ """
+ Parse and convert the report attachment in the response into human-readable markdown string.
+
+ :type results: ``List[Dict[str, Any]]``
+ :param results: Details of urls.
+
+ :return: Human Readable string containing information of report attachment.
+ :rtype: ``str``
+ """
+ attachments_hr = []
+ for res in results:
+ attributes = res.get("attributes")
+ hr = {"Attachment ID": res.get("id", "")}
+
+ if attributes:
+ hr["File Name"] = attributes.get("filename", "")
+ hr["File Size in Bytes"] = attributes.get("size", "")
+ hr["Is Child"] = attributes.get("is_child", "")
+ hr[CREATED_AT] = attributes.get("created_at", "")
+ hr[UPDATED_AT] = attributes.get("updated_at", "")
+ attachments_hr.append(hr)
+
+ return tableToMarkdown("Attachment(s)", attachments_hr,
+ headers=["Attachment ID", "File Name",
+ "File Size in Bytes", "Is Child", CREATED_AT, UPDATED_AT],
+ removeNull=True)
+
+
def validate_comment_list_args(args: Dict[str, str]) -> Dict[str, Any]:
"""
Validate arguments for cofense-comment-list command, raise ValueError on invalid arguments.
@@ -1399,6 +1431,87 @@ def cofense_report_attachment_payload_list_command(client: Client, args: Dict[st
)
+def cofense_report_attachment_list_command(client: Client, args: Dict[str, str]) -> CommandResults:
+ """
+ Retrieves report attachment list based on the filter values provided in the command arguments.
+ For reported emails that contain attachments, Cofense Triage captures the attachment's filename and size.
+
+ :type client: ``Client``
+ :param client: Client object to be used.
+
+ :type args: ``Dict[str, str]``
+ :param args: The command arguments provided by the user.
+
+ :return: Standard command result.
+ :rtype: ``CommandResults``
+ """
+ params, _ = validate_list_command_args(args, "attachments")
+ report_id = args.get("id")
+ # Validation for empty report_id
+ if not report_id:
+ raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id"))
+ # Appending the report id to the url_suffix
+ url_suffix = URL_SUFFIX["REPORT_ATTACHMENT"].format(report_id)
+
+ # Sending http request
+ response = client.http_request(url_suffix, params=params)
+
+ result = response.get("data")
+
+ # Returning if data is empty or not present
+ if not result:
+ return CommandResults(readable_output=MESSAGES["NO_RECORDS_FOUND"].format("attachments"))
+
+ if isinstance(result, dict):
+ result = [result]
+
+ # Creating the Human Readable
+ hr_response = prepare_hr_for_report_attachments(result)
+
+ # Creating the Context data
+ context_data = remove_empty_elements(result)
+
+ return CommandResults(outputs_prefix=OUTPUT_PREFIX["ATTACHMENT"],
+ outputs_key_field="id",
+ outputs=context_data,
+ readable_output=hr_response,
+ raw_response=response
+ )
+
+
+def cofense_report_attachment_download_command(client: Client, args: Dict[str, str]) -> dict:
+ """
+ Downloads the attachment for a the specified attachment ID.
+
+ :type client: ``Client``
+ :param client: Client object to be used.
+
+ :type args: ``Dict[str, str]``
+ :param args: The command arguments provided by the user.
+
+ :return: File Result.
+ :rtype: ``dict``
+ """
+ attachment_id = args.get("id")
+ if not attachment_id:
+ raise ValueError(MESSAGES["REQUIRED_ARGUMENT"].format("id"))
+ # Appending the id to the url_suffix
+ url_suffix = URL_SUFFIX["REPORT_ATTACHMENT_DOWNLOAD"].format(attachment_id)
+ headers = {
+ 'Accept': "*/*"
+ }
+ # Sending http request
+ response = client.http_request(url_suffix, resp_type="response", headers=headers)
+ content_disposition = response.headers.get('Content-Disposition') or ''
+ content_disposition_split = content_disposition.split(';')
+ if len(content_disposition_split) > 1:
+ file_name = content_disposition_split[1].replace('filename=', '').replace('"', '')
+ file_name = urllib.parse.unquote(file_name).strip()
+ else:
+ file_name = f"Attachment ID - {attachment_id}"
+ return fileResult(file_name, data=response.content)
+
+
def fetch_incidents(client: Client, last_run: dict, params: Dict) -> Tuple[dict, list]:
"""Fetches incidents from Cofense API.
@@ -2033,7 +2146,9 @@ def main() -> None:
'cofense-cluster-list': cofense_cluster_list_command,
'cofense-threat-indicator-update': cofense_threat_indicator_update_command,
'cofense-report-image-download': cofense_report_image_download_command,
- 'cofense-report-attachment-payload-list': cofense_report_attachment_payload_list_command
+ 'cofense-report-attachment-payload-list': cofense_report_attachment_payload_list_command,
+ 'cofense-report-attachment-list': cofense_report_attachment_list_command,
+ 'cofense-report-attachment-download': cofense_report_attachment_download_command,
}
command = demisto.command()
demisto.debug(f'[CofenseTriagev3] Command being called is {command}')
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.yml b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.yml
index 22b2f5626a4d..417260d2b5d3 100644
--- a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.yml
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3.yml
@@ -118,15 +118,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the threat indicators.
name: page_number
- - description: 'Specify the attributes to sort the threat indicators. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: threat_level, -created_at'
+ - description: 'Specify the attributes to sort the threat indicators. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: threat_level, -created_at.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of threat indicators by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"threat_level_eq\":\"Malicious,Benign\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}
+ For example: {\"threat_level_eq\":\"Malicious,Benign\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: threat_level, threat_type, threat_value'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: threat_level, threat_type, threat_value.'
isArray: true
name: fields_to_retrieve
- description: 'Specify the level of the threat to retrieve the threat indicators. Some possible values are: Malicious, Suspicious, Benign.'
@@ -208,15 +208,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the reports.
name: page_number
- - description: 'Specify the attributes to sort the reports. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -received_at, match_priority'
+ - description: 'Specify the attributes to sort the reports. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -received_at, match_priority.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of reports by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"updated_at_gt\":\"2020-10-26T10:48:16.834Z\",\"categorization_tags_any\":\"test, snow\"}
+ For example: {\"updated_at_gt\":\"2020-10-26T10:48:16.834Z\",\"categorization_tags_any\":\"test, snow\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: location, from_address'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: location, from_address.'
name: fields_to_retrieve
- description: 'Specify the priority to retrieve the reports based on the priority of the rules that match the reports. Possible values are: 0, 1, 2, 3, 4, 5.'
isArray: true
@@ -486,15 +486,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the categories.
name: page_number
- - description: 'Specify the attributes to sort the categories. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: score, -name'
+ - description: 'Specify the attributes to sort the categories. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: score, -name.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of categories by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"score_gteq\":\"2,10\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}
+ For example: {\"score_gteq\":\"2,10\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: name, score'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: name, score.'
isArray: true
name: fields_to_retrieve
- description: Specify the name of the category to retrieve the category accordingly.
@@ -571,15 +571,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the rules.
name: page_number
- - description: 'Specify the attributes to sort the rules. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -name, priority'
+ - description: 'Specify the attributes to sort the rules. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -name, priority.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of rules by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"priority_eq\":\"2,3\", \"name_cont\":\"Test\"}
+ For example: {\"priority_eq\":\"2,3\", \"name_cont\":\"Test\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: name, description'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: name, description.'
isArray: true
name: fields_to_retrieve
- description: Specify the name of the rule to retrieve the rule.
@@ -728,15 +728,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the URLs.
name: page_number
- - description: 'Specify the attributes to sort the URLs. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -created_at, -updated_at'
+ - description: 'Specify the attributes to sort the URLs. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -created_at, -updated_at.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of urls by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"risk_score_eq\":\"1,2\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}
+ For example: {\"risk_score_eq\":\"1,2\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: url, risk_score'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: url, risk_score.'
name: fields_to_retrieve
- description: Specify the risk scores to retrieve the urls.
isArray: true
@@ -900,15 +900,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the reporters.
name: page_number
- - description: 'Specify the attributes to sort the reporters. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: reports_count, -email'
+ - description: 'Specify the attributes to sort the reporters. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: reports_count, -email.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of reporters by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"reputation_score_eq\":\"1,2\", \"reports_count_gt\":\"3\"}
+ For example: {\"reputation_score_eq\":\"1,2\", \"reports_count_gt\":\"3\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: email, reports_count'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: email, reports_count.'
isArray: true
name: fields_to_retrieve
- description: Specify reputation score to retrieve the reporters.
@@ -990,15 +990,15 @@ script:
name: page_size
- description: Specify a page number to retrieve the integration submissions.
name: page_number
- - description: 'Specify the attributes to sort the integration submissions. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: status, -id'
+ - description: 'Specify the attributes to sort the integration submissions. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: status, -id.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of integration submissions by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"status_eq\":\"complete\", \"risk_score_eq\":\"0,1\"}
+ For example: {\"status_eq\":\"complete\", \"risk_score_eq\":\"0,1\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: status, kind'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: status, kind.'
isArray: true
name: fields_to_retrieve
- description: 'Specify the status to retrieve the integration submission. Some possible values are: ending, complete, target_not_found, error, running, or hash_not_found.'
@@ -1083,15 +1083,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the attachment payloads.
name: page_number
- - description: 'Specify the attributes to sort the attachment payloads. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: risk_score, -id'
+ - description: 'Specify the attributes to sort the attachment payloads. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: risk_score, -id.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of attachment payloads by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"risk_score\":\"0,1\", \"created_at_gteq\":\"2020-04-13T10:48:16.834Z\"}
+ For example: {\"risk_score\":\"0,1\", \"created_at_gteq\":\"2020-04-13T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: md5, risk_score'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: md5, risk_score.'
isArray: true
name: fields_to_retrieve
- description: Specify the risk scores to retrieve the attachment payloads.
@@ -1166,14 +1166,14 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the comments.
name: page_number
- - description: 'Specify the attributes to sort the comments. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -created_at, body'
+ - description: 'Specify the attributes to sort the comments. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: -created_at, body.'
name: sort_by
- description: |-
Specify the filters to filter the list of comments by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"body_format_eq\":\"json\", \"created_at_gteq\":\"2021-04-13T10:48:16.834Z\"}
+ For example: {\"body_format_eq\":\"json\", \"created_at_gteq\":\"2021-04-13T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: body, body_format'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: body, body_format.'
isArray: true
name: fields_to_retrieve
- auto: PREDEFINED
@@ -1386,15 +1386,15 @@ script:
- defaultValue: '1'
description: Specify a page number to retrieve the clusters.
name: page_number
- - description: 'Specify the attributes to sort the clusters. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: created_at, -updated_at'
+ - description: 'Specify the attributes to sort the clusters. Note: The default sort order for an attribute is ascending. Prefix the attributes with a hyphen to sort in descending order. For example: created_at, -updated_at.'
isArray: true
name: sort_by
- description: |-
Specify the filters to filter the list of clusters by attribute values. Note: Enter values in key-value JSON format. To separate multiple values of a single attribute, use commas. Add backslash(\) before quotes.
Format accepted: {\"attribute1_operator \": \"value1, value2\", \"attribute2_operator\" : \"value3, value4\"}
- For example: {\"risk_score_eq\":\"1,2\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}
+ For example: {\"risk_score_eq\":\"1,2\", \"updated_at_gt\":\"2020-10-26T10:48:16.834Z\"}.
name: filter_by
- - description: 'Specify the fields to retrieve the mentioned attributes only. For example: unprocessed_reports_count, processed_reports_count'
+ - description: 'Specify the fields to retrieve the mentioned attributes only. For example: unprocessed_reports_count, processed_reports_count.'
isArray: true
name: fields_to_retrieve
- description: Specify the tags to retrieve the cluster.
@@ -1704,7 +1704,128 @@ script:
- contextPath: Cofense.AttachmentPayload.relationships.reports.links.related
description: Link to retrieve the detailed information of the report with attachments containing the payload.
type: String
- dockerimage: demisto/python3:3.10.13.72123
+ - arguments:
+ - description: 'Specify ID of the report to retrieve the attachments.'
+ name: id
+ required: true
+ - defaultValue: '20'
+ description: 'Specify the number of attachments to retrieve per page. Note: Possible values are between 1 and 200.'
+ name: page_size
+ - defaultValue: '1'
+ description: 'Specify a page number to retrieve the attachments.'
+ name: page_number
+ - description: 'Specify the date and time of creation, from when to retrieve the attachments. Formats accepted: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ, etc.'
+ name: created_at
+ - description: 'Specify the date and time of updation, from when to retrieve the attachments. Formats accepted: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ, etc.'
+ name: updated_at
+ description: |-
+ Retrieves attachments based on provided report id in the command arguments.
+ For reported emails that contain attachments, Cofense Triage captures the attachment's filename and size.
+ name: cofense-report-attachment-list
+ outputs:
+ - contextPath: Cofense.Attachment.id
+ description: Unique identifier of the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.type
+ description: Type of the resource of Cofense Triage.
+ type: String
+ - contextPath: Cofense.Attachment.links.self
+ description: Link of the resource.
+ type: String
+ - contextPath: Cofense.Attachment.attributes.filename
+ description: Name of the attachment file.
+ type: String
+ - contextPath: Cofense.Attachment.attributes.size
+ description: Attachment size in bytes.
+ type: Number
+ - contextPath: Cofense.Attachment.attributes.is_child
+ description: Boolean value indicating that attachment is child or not.
+ type: Boolean
+ - contextPath: Cofense.Attachment.attributes.created_at
+ description: Date and time, in ISO 8601 format, when the resource was created.
+ type: Date
+ - contextPath: Cofense.Attachment.attributes.updated_at
+ description: Date and time, in ISO 8601 format, when the resource was last updated.
+ type: Date
+ - contextPath: Cofense.Attachment.relationships.attachment_payload.links.self
+ description: Link to retrieve the attachment payload associated with the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.attachment_payload.links.related
+ description: Link to retrieve the detailed information of the attachment payload associated with the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.attachment_payload.data.type
+ description: Type indicating attachment payload.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.attachment_payload.data.id
+ description: Unique identifier of the attachment payload associated with the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.parent.links.self
+ description: Link to retrieve the parent of the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.parent.links.related
+ description: Link to retrieve the detailed information of the parent of the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.parent.data.type
+ description: Type indicating the parent of the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.parent.data.id
+ description: Unique identifier of the parent of the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.reports.links.self
+ description: Link to retrieve the report associated with the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.reports.links.related
+ description: Link to retrieve the detailed information of the report associated with the attachment.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.reports.data.type
+ description: Type indicating report.
+ type: String
+ - contextPath: Cofense.Attachment.relationships.reports.data.id
+ description: Unique identifier of the report associated with the attachment.
+ type: String
+ - arguments:
+ - description: |-
+ Specify the ID of the attachment to download the attachment file.
+ Note: To retrieve id, execute cofense-report-attachment-list command.
+ name: id
+ required: true
+ description: Downloads the attachment for the specified attachment ID.
+ name: cofense-report-attachment-download
+ outputs:
+ - contextPath: File.Size
+ description: File size in bytes.
+ type: String
+ - contextPath: File.SHA1
+ description: SHA1 hash of file.
+ type: String
+ - contextPath: File.SHA256
+ description: SHA256 hash of file.
+ type: String
+ - contextPath: File.SHA512
+ description: SHA512 hash of file.
+ type: String
+ - contextPath: File.Name
+ description: File name.
+ type: String
+ - contextPath: File.SSDeep
+ description: SSDeep hash of the file.
+ type: String
+ - contextPath: File.EntryID
+ description: The entry ID of the file.
+ type: Unknown
+ - contextPath: File.Info
+ description: File information.
+ type: String
+ - contextPath: File.Type
+ description: The file type.
+ type: String
+ - contextPath: File.MD5
+ description: MD5 hash of the file.
+ type: String
+ - contextPath: File.Extension
+ description: The file extension.
+ type: String
+ dockerimage: demisto/python3:3.10.13.83255
isfetch: true
isremotesyncin: true
runonce: false
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3_test.py b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3_test.py
index 521682dc096f..b85e87745490 100644
--- a/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3_test.py
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/CofenseTriagev3_test.py
@@ -1,5 +1,4 @@
import json
-import io
import time
import os
import pytest
@@ -28,7 +27,7 @@
def util_load_json(path: str) -> dict:
"""Load a json to python dict."""
- with io.open(path, mode='r', encoding='utf-8') as f:
+ with open(path, mode='r', encoding='utf-8') as f:
return json.loads(f.read())
@@ -1103,3 +1102,106 @@ def test_validate_report_attachment_payload_list_args_when_invalid_args_are_prov
with pytest.raises(ValueError) as err:
cofense_report_attachment_payload_list_command(mocked_client, args)
assert str(err.value) == MESSAGES['REQUIRED_ARGUMENT'].format('id')
+
+
+def test_cofense_report_attachment_list_command_when_invalid_args_are_provided(mocked_client):
+ """Test case scenario when the arguments provided are not valid."""
+
+ from CofenseTriagev3 import MESSAGES, cofense_report_attachment_list_command
+
+ args = {
+ "id": None,
+ }
+
+ with pytest.raises(ValueError) as err:
+ cofense_report_attachment_list_command(mocked_client, args)
+ assert str(err.value) == MESSAGES['REQUIRED_ARGUMENT'].format('id')
+
+
+def test_cofense_report_attachment_list_command_when_empty_response_is_returned(mocked_client):
+ """Test case scenario for successful execution of cofense-report-attachment-list command with an empty
+ response. """
+
+ from CofenseTriagev3 import cofense_report_attachment_list_command
+ mocked_client.http_request.return_value = {"data": {}}
+ readable_output = "No attachments were found for the given argument(s)."
+
+ # Execute
+ command_response = cofense_report_attachment_list_command(mocked_client, {'id': 'test'})
+ # Assert
+ assert command_response.readable_output == readable_output
+
+
+def test_cofense_report_attachment_list_command_when_valid_response_is_returned(mocked_client):
+ """Test case scenario for successful execution of cofense-report-attachment-list command."""
+
+ from CofenseTriagev3 import cofense_report_attachment_list_command
+
+ response = util_load_json(
+ os.path.join("test_data", os.path.join("report_attachment", "report_attachment_list_response.json")))
+
+ mocked_client.http_request.return_value = response
+
+ context_output = util_load_json(
+ os.path.join("test_data", os.path.join("report_attachment", "report_attachment_list_context.json")))
+
+ with open(os.path.join("test_data", os.path.join("report_attachment", "report_attachment_list.md")), 'r') as f:
+ readable_output = f.read()
+
+ # Execute
+ args = {"id": "30339", "updated_at": "2020-10-21T20:30:24.185Z"}
+
+ command_response = cofense_report_attachment_list_command(mocked_client, args)
+ # Assert
+ assert command_response.outputs_prefix == 'Cofense.Attachment'
+ assert command_response.outputs_key_field == "id"
+ assert command_response.outputs == context_output
+ assert command_response.readable_output == readable_output
+ assert command_response.raw_response == response
+
+
+def test_cofense_report_attachment_download_command_when_invalid_args_are_provided(mocked_client):
+ """Test case scenario when the arguments provided are not valid."""
+
+ from CofenseTriagev3 import MESSAGES, cofense_report_attachment_download_command
+
+ args = {
+ "id": None,
+ }
+
+ with pytest.raises(ValueError) as err:
+ cofense_report_attachment_download_command(mocked_client, args)
+ assert str(err.value) == MESSAGES['REQUIRED_ARGUMENT'].format('id')
+
+
+def test_cofense_report_attachment_download_command_when_valid_args_are_provided(mocked_client):
+ """Test case scenario when the arguments provided are valid."""
+
+ from CofenseTriagev3 import cofense_report_attachment_download_command
+
+ with open(os.path.join("test_data", os.path.join("report_attachment", "report_attachment_download_response.xml")), 'r') as f:
+ response = f.read()
+
+ # Mock response with the valid headers.
+ class MockResponse:
+ content = response
+ headers = {"Content-Disposition": """attachment; filename="xl%2FordStrings.xml"; filename*=UTF-8''xl%2FordStrings.xml"""}
+
+ mocked_client.http_request.return_value = MockResponse
+
+ args = {"id": "30339"}
+ command_response = cofense_report_attachment_download_command(mocked_client, args)
+
+ # Assert for file name based on the header.
+ assert command_response["File"] == 'xl/ordStrings.xml'
+
+ # Mock response with empty headers
+ MockResponse.headers = {}
+
+ mocked_client.http_request.return_value = MockResponse
+
+ args = {"id": "30339"}
+ command_response = cofense_report_attachment_download_command(mocked_client, args)
+
+ # Assert for file name based on the attachment ID.
+ assert command_response["File"] == 'Attachment ID - 30339'
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/README.md b/Packs/CofenseTriage/Integrations/CofenseTriagev3/README.md
index ba62796491e7..7a06eadfb6ac 100644
--- a/Packs/CofenseTriage/Integrations/CofenseTriagev3/README.md
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/README.md
@@ -862,6 +862,230 @@ Attachment payloads identify the MIME type and MD5 and SHA256 hash signatures of
>| 78 | image/png; charset=binary | 61da9c47fff9b04e59b951aa700c7980 | 7757f5392a8971b280464ae0d760b04980b82a9a2a3105c2bd6c9293ff7f9b9a | | 2020-10-21T20:57:56.940Z | 2020-10-21T20:57:56.940Z |
+### cofense-report-attachment-list
+
+***
+Retrieves attachments based on provided report id in the command arguments.
+For reported emails that contain attachments, Cofense Triage captures the attachment's filename and size.
+
+#### Base Command
+
+`cofense-report-attachment-list`
+
+#### Input
+
+| **Argument Name** | **Description** | **Required** |
+| --- | --- | --- |
+| id | Specify ID of the report to retrieve the attachments. | Required |
+| page_size | Specify the number of attachments to retrieve per page. Note: Possible values are between 1 and 200. Default is 20. | Optional |
+| page_number | Specify a page number to retrieve the attachments. Default is 1. | Optional |
+| created_at | Specify the date and time of creation, from when to retrieve the attachments. Formats accepted: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ, etc. | Optional |
+| updated_at | Specify the date and time of updation, from when to retrieve the attachments. Formats accepted: 2 minutes, 2 hours, 2 days, 2 weeks, 2 months, 2 years, yyyy-mm-dd, yyyy-mm-ddTHH:MM:SSZ, etc. | Optional |
+
+#### Context Output
+
+| **Path** | **Type** | **Description** |
+| --- | --- | --- |
+| Cofense.Attachment.id | String | Unique identifier of the attachment. |
+| Cofense.Attachment.type | String | Type of the resource of Cofense Triage. |
+| Cofense.Attachment.links.self | String | Link of the resource. |
+| Cofense.Attachment.attributes.filename | String | Name of the attachment file. |
+| Cofense.Attachment.attributes.size | Number | Attachment size in bytes. |
+| Cofense.Attachment.attributes.is_child | Boolean | Boolean value indicating that attachment is child or not. |
+| Cofense.Attachment.attributes.created_at | Date | Date and time, in ISO 8601 format, when the resource was created. |
+| Cofense.Attachment.attributes.updated_at | Date | Date and time, in ISO 8601 format, when the resource was last updated. |
+| Cofense.Attachment.relationships.attachment_payload.links.self | String | Link to retrieve the attachment payload associated with the attachment. |
+| Cofense.Attachment.relationships.attachment_payload.links.related | String | Link to retrieve the detailed information of the attachment payload associated with the attachment. |
+| Cofense.Attachment.relationships.attachment_payload.data.type | String | Type indicating attachment payload. |
+| Cofense.Attachment.relationships.attachment_payload.data.id | String | Unique identifier of the attachment payload associated with the attachment. |
+| Cofense.Attachment.relationships.parent.links.self | String | Link to retrieve the parent of the attachment. |
+| Cofense.Attachment.relationships.parent.links.related | String | Link to retrieve the detailed information of the parent of the attachment. |
+| Cofense.Attachment.relationships.parent.data.type | String | Type indicating the parent of the attachment. |
+| Cofense.Attachment.relationships.parent.data.id | String | Unique identifier of the parent of the attachment. |
+| Cofense.Attachment.relationships.reports.links.self | String | Link to retrieve the report associated with the attachment. |
+| Cofense.Attachment.relationships.reports.links.related | String | Link to retrieve the detailed information of the report associated with the attachment. |
+| Cofense.Attachment.relationships.reports.data.type | String | Type indicating report. |
+| Cofense.Attachment.relationships.reports.data.id | String | Unique identifier of the report associated with the attachment. |
+
+
+#### Command Example
+```!cofense-report-attachment-list id=30339 page_size=2```
+
+#### Context Example
+```json
+{
+ "Cofense": {
+ "Attachment": [
+ {
+ "id": "30339",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339"
+ },
+ "attributes": {
+ "filename": "Invoice.xlsm",
+ "size": 100000,
+ "is_child": false,
+ "created_at": "2023-04-09T13:25:28.540Z",
+ "updated_at": "2023-04-09T13:25:28.540Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "1452"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/parent"
+ }
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ },
+ {
+ "id": "30340",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340"
+ },
+ "attributes": {
+ "filename": "docProps/app.xml",
+ "size": 700,
+ "is_child": true,
+ "created_at": "2023-04-09T13:25:29.249Z",
+ "updated_at": "2023-04-09T13:25:29.249Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "74"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/parent"
+ },
+ "data": {
+ "type": "attachments",
+ "id": "30339"
+ }
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ }
+ ]
+ }
+}
+```
+
+#### Human Readable Output
+
+>### Attachment(s)
+>|Attachment ID|File Name|File Size in Bytes|Is Child|Created At|Updated At|
+>|---|---|---|---|---|---|
+>| 30339 | Invoice.xlsm | 100000 | false | 2023-04-09T13:25:28.540Z | 2023-04-09T13:25:28.540Z |
+>| 30340 | docProps/app.xml | 700 | true | 2023-04-09T13:25:29.249Z | 2023-04-09T13:25:29.249Z |
+
+
+### cofense-report-attachment-download
+
+***
+Downloads the attachment for the specified attachment ID.
+
+#### Base Command
+
+`cofense-report-attachment-download`
+
+#### Input
+
+| **Argument Name** | **Description** | **Required** |
+| --- | --- | --- |
+| id | Specify the ID of the attachment to download the attachment file.
Note: To retrieve id, execute cofense-report-attachment-list command. | Required |
+
+#### Context Output
+
+| **Path** | **Type** | **Description** |
+| --- | --- | --- |
+| File.Size | String | File size in bytes. |
+| File.SHA1 | String | SHA1 hash of file. |
+| File.SHA256 | String | SHA256 hash of file. |
+| File.SHA512 | String | SHA512 hash of file. |
+| File.Name | String | File name. |
+| File.SSDeep | String | SSDeep hash of the file. |
+| File.EntryID | Unknown | The entry ID of the file. |
+| File.Info | String | File information. |
+| File.Type | String | The file type. |
+| File.MD5 | String | MD5 hash of the file. |
+| File.Extension | String | The file extension. |
+
+#### Command example
+```!cofense-report-attachment-download id=30```
+#### Context Example
+```json
+{
+ "File": {
+ "EntryID": "3000@80068006-8006-8006-8006-800680068006",
+ "Extension": "xml",
+ "Type": "text/xml; charset=utf-8",
+ "MD5": "11111111111111111111111111111111",
+ "Name": "xl/sharedStrings.xml",
+ "SHA1": "1111111111111111111111111111111111111111",
+ "SHA256": "1111111111111111111111111111111111111111111111111111111111111111",
+ "SHA512": "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",
+ "SSDeep": "3:111111111111111111111111111111111111111111111111111111111111:111111111111111111111111",
+ "Size": 206,
+ "Info": "XML 1.0 document, ASCII text, with CRLF line terminators"
+ }
+}
+```
+
+#### Human Readable Output
+
+>Uploaded file: xl/sharedStrings.xml Download
+
+>|Property|Value|
+>|---|---|
+>| Type | text/xml; charset=utf-8 |
+>| Size | 206 bytes |
+>| Info | XML 1.0 document, ASCII text, with CRLF line terminators |
+>| MD5 | 11111111111111111111111111111111 |
+>| SHA1 | 1111111111111111111111111111111111111111 |
+>| SHA256 | 1111111111111111111111111111111111111111111111111111111111111111 |
+>| SHA512 | 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 |
+>| SSDeep | 3:111111111111111111111111111111111111111111111111111111111111:111111111111111111111111 |
+
+
### cofense-category-list
***
Retrieves categories based on the provided parameters.
@@ -2559,3 +2783,5 @@ The ability to mirror incident data has been added.
* *cofense-threat-indicator-update*
* *cofense-url-list*
* *cofense-report-attachment-payload-list*
+* *cofense-report-attachment-list*
+* *cofense-report-attachment-download*
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_download_response.xml b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_download_response.xml
new file mode 100644
index 000000000000..67a0a989fcc5
--- /dev/null
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_download_response.xml
@@ -0,0 +1,6 @@
+
+
+
+ Click here to view the invoice
+
+
\ No newline at end of file
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list.md b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list.md
new file mode 100644
index 000000000000..345934445a3d
--- /dev/null
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list.md
@@ -0,0 +1,5 @@
+### Attachment(s)
+|Attachment ID|File Name|File Size in Bytes|Is Child|Created At|Updated At|
+|---|---|---|---|---|---|
+| 30339 | Invoice.xlsm | 100000 | false | 2023-04-09T13:25:28.540Z | 2023-04-09T13:25:28.540Z |
+| 30340 | docProps/app.xml | 700 | true | 2023-04-09T13:25:29.249Z | 2023-04-09T13:25:29.249Z |
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_context.json b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_context.json
new file mode 100644
index 000000000000..d2bee9b80ba3
--- /dev/null
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_context.json
@@ -0,0 +1,90 @@
+[
+ {
+ "id": "30339",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339"
+ },
+ "attributes": {
+ "filename": "Invoice.xlsm",
+ "size": 100000,
+ "is_child": false,
+ "created_at": "2023-04-09T13:25:28.540Z",
+ "updated_at": "2023-04-09T13:25:28.540Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "1452"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/parent"
+ }
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ },
+ {
+ "id": "30340",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340"
+ },
+ "attributes": {
+ "filename": "docProps/app.xml",
+ "size": 700,
+ "is_child": true,
+ "created_at": "2023-04-09T13:25:29.249Z",
+ "updated_at": "2023-04-09T13:25:29.249Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "74"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/parent"
+ },
+ "data": {
+ "type": "attachments",
+ "id": "30339"
+ }
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ }
+]
\ No newline at end of file
diff --git a/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_response.json b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_response.json
new file mode 100644
index 000000000000..4f90fa32ceb4
--- /dev/null
+++ b/Packs/CofenseTriage/Integrations/CofenseTriagev3/test_data/report_attachment/report_attachment_list_response.json
@@ -0,0 +1,102 @@
+{
+ "data": [
+ {
+ "id": "30339",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339"
+ },
+ "attributes": {
+ "filename": "Invoice.xlsm",
+ "size": 100000,
+ "is_child": false,
+ "created_at": "2023-04-09T13:25:28.540Z",
+ "updated_at": "2023-04-09T13:25:28.540Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "1452"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/parent"
+ },
+ "data": null
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30339/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30339/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ },
+ {
+ "id": "30340",
+ "type": "attachments",
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340"
+ },
+ "attributes": {
+ "filename": "docProps/app.xml",
+ "size": 700,
+ "is_child": true,
+ "created_at": "2023-04-09T13:25:29.249Z",
+ "updated_at": "2023-04-09T13:25:29.249Z"
+ },
+ "relationships": {
+ "attachment_payload": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/attachment_payload",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/attachment_payload"
+ },
+ "data": {
+ "type": "attachment_payloads",
+ "id": "74"
+ }
+ },
+ "parent": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/parent",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/parent"
+ },
+ "data": {
+ "type": "attachments",
+ "id": "30339"
+ }
+ },
+ "report": {
+ "links": {
+ "self": "https://triage.example.com/api/public/v2/attachments/30340/relationships/report",
+ "related": "https://triage.example.com/api/public/v2/attachments/30340/report"
+ },
+ "data": {
+ "type": "reports",
+ "id": "47024"
+ }
+ }
+ }
+ }
+ ],
+ "meta": {
+ "record_count": 16,
+ "page_count": 8
+ },
+ "links": {
+ "first": "https://triage.example.com/api/public/v2/reports/47024/attachments?page%5Bnumber%5D=1&page%5Bsize%5D=2",
+ "next": "https://triage.example.com/api/public/v2/reports/47024/attachments?page%5Bnumber%5D=2&page%5Bsize%5D=2",
+ "last": "https://triage.example.com/api/public/v2/reports/47024/attachments?page%5Bnumber%5D=8&page%5Bsize%5D=2"
+ }
+}
\ No newline at end of file
diff --git a/Packs/CofenseTriage/ReleaseNotes/2_1_20.md b/Packs/CofenseTriage/ReleaseNotes/2_1_20.md
new file mode 100644
index 000000000000..93daecbc3bb6
--- /dev/null
+++ b/Packs/CofenseTriage/ReleaseNotes/2_1_20.md
@@ -0,0 +1,8 @@
+
+#### Integrations
+
+##### Cofense Triage v3
+
+- Added the new `cofense-report-attachment-list` command.
+- Added the new `cofense-report-attachment-download` command.
+- Updated the Docker image to: *demisto/python3:3.10.13.83255*.
diff --git a/Packs/CofenseTriage/pack_metadata.json b/Packs/CofenseTriage/pack_metadata.json
index 570283070abf..3bd23e89fed0 100644
--- a/Packs/CofenseTriage/pack_metadata.json
+++ b/Packs/CofenseTriage/pack_metadata.json
@@ -2,7 +2,7 @@
"name": "Cofense Triage",
"description": "Cofense Triage allows users to fetch reports by using the fetch incidents capability. It also provides commands to get entities like reporters, rules, categories, and more.",
"support": "partner",
- "currentVersion": "2.1.19",
+ "currentVersion": "2.1.20",
"author": "Cofense",
"url": "https://cofense.com/contact-support/",
"email": "support@cofense.com",