RTIR
Request Tracker for Incident Response is a ticketing system which provides pre-configured queues and workflows designed for incident response teams.
Case Management · RTIR
Details
| ID | RTIR |
|---|---|
| Provider | Open Source |
| Category | Case Management |
| From Version | 5.0.0 |
| Docker Image | demisto/python3:3.12.13.10116658 |
| Supported Modules | Agentix XSIAM |
README
Use the Request Tracker for Incident Response (RTIR) integration to manage tickets and incidents.
This integration was integrated and tested with RTIR v4.4.2, using the SDK python-rtir v1.0.11.
Use Cases
- Create new tickets.
- Resolve existing tickets.
- Search for tickets using filters.
- Edit tickets.
- Get ticket data.
Known Limitations
- This integration does not support the lifecycle
countermeasures. - Custom fields cannot be created through this integration, but custom fields created on RTIR can be filled when creating a new ticket.
Configure RTIR on Cortex XSOAR
- Navigate to Settings > Integrations > Servers & Services.
- Search for RTIR.
- Click Add instance to create and configure a new integration instance.
- Name: A textual name for the integration instance.
- Server URL (for example: https://192.168.0.1)
- Username
- Password
- Token
- Certificate
- Private Key
- Trust any certificate (not secure)
- Use system proxy settings
- Use system proxy settings
- Fetch incidents
- Fetch incidents with priority greater or equal to
- Fetch incidents of the following status
- Incident type
- Referer request header
- Click Test to validate the URLs and token.
Fetched Incidents Data
The integration fetches newly created tickets. The tickets are fetched by ID in ascending order, starting from 0 at the first fetch. The fetch is filtered by priority and status, which can be set in the integration settings. The initial fetch interval is one minute.
The following data is fetched for each ticket:
- General ticket information: ID, priority, created date, subject, queue, custom fields, and so on.
- Ticket history.
- Ticket attachments.
Commands
You can execute these commands from the Cortex XSOAR 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.
- Create a new ticket: rtir-create-ticket
- Search for tickets: rtir-search-ticket
- Close a resolved ticket: rtir-resolve-ticket
- Edit a ticket: rtir-edit-ticket
- Get the history of a ticket: rtir-ticket-history
- Get ticket details: rtir-get-ticket
- Get ticket attachments: rtir-ticket-attachments
- Add a comment to a ticket: rtir-add-comment
1. Create a new ticket
Creates a new ticket in RFIR.
Base Command
rtir-create-ticket
Input
| Argument Name | Description |
| queue | Where to create the ticket. |
| subject | Subject of the ticket. |
| requestor | Email address of the requester. |
| cc | Sends a carbon-copy (cc) of this update to a comma separated list of email addresses. These people will also receive future updates. |
| admin-cc | Sends a carbon-copy (cc) of this update to a comma separated list of administrative email addresses. These people will also receive future updates. |
| owner | Ticket owner |
| status | Ticket status |
| priority | Ticket priority |
| text | The ticket content |
| initial-priority | Initial priority of ticket |
| final-priority | Final priority of ticket |
| member-of | Ticket MembersOF links |
| members | Ticket Members links |
| attachment |
Comma separated list of entry IDs of attachment to add to the ticket (for example: entryID1,entryID2). |
| customfields |
Ticket custom fields, in the following format: field1=value1,field2=value2. For example: IP=8.8.8.8,HowReported=Email. Note: This command does not create custom fields, these should be created on RTIR. |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.InitialPriority | Ticket initial priority 0-100). |
| RTIR.Ticket.Priority | Ticket priority (0-100). |
| RTIR.Ticket.FinalPriority | Ticket final priority (0-100). |
| RTIR.Ticket.Owner | Ticket owner. |
| RTIR.Ticket.Subject | Ticket subject. |
| RTIR.Ticket.Creator | Ticket creator. |
Command Example
!rtir-create-ticket subject=NewTicket queue="Incident Reports" priority=70 requestor=root@localhost customfields="IP=8.8.8.8,How Reported=Email"
Raw Output
Ticket 121 was created successfully.
Context Example
{
"RTIR": {
"Ticket": {
"CF_How Reported": "Email",
"CF_IP": "8.8.8.8",
"Priority": 70,
"Requestor": "root@localhost",
"Subject": "NewTicket"
}
}
}
2. Search for tickets
Searches for tickets in RTIR using specified filters.
Base Command
rtir-search-ticket
Input
| Argument Name | Description |
| ticket-id | Ticket ID |
| subject | Ticket subject |
| queue |
CSV list of ticket queues. For example: General,Incident reports,Incidents |
| status | Ticket status |
| creator | Ticket creator |
| priority-equal-to | Ticket priority (range 0-100) |
| priority-greater-than | Ticket priority (range 0-100) |
| created-after |
Date after which the ticket was created, in the following format: YYYY-MM-DD. For example: 2011-02-24 |
| created-on |
Date the ticket was created, in the following format: YYYY-MM-DD. For example: 2011-02-24 |
| created-before |
Date before which the ticket was created, in the following format: YYYY-MM-DD. For example: 2011-02-24 |
| owner | Ticket owner |
| due |
Ticket due date, in the following format: YYYY-MM-DD. For example: 2011-02-24 |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.State | Ticket state. |
| RTIR.Ticket.Creator | Ticket creator. |
| RTIR.Ticket.Subject | Ticket subject. |
| RTIR.Ticket.Created | Ticket creation date. |
| RTIR.Ticket.Priority | Ticket priority (0-100). |
| RTIR.Ticket.InitialPriority | Ticket initial priority (0-100). |
| RTIR.Ticket.FinalPriority | Ticket final priority (0-100). |
| RTIR.Ticket.Queue | Ticket queue. |
| RTIR.Ticket.Owner | Ticket owner. |
| RTIR.Ticket.IP | Ticket custom field - IP address. |
| RTIR.Ticket.HowReported | Ticket custom field - How ticket was reported. |
| RTIR.Ticket.Customer | Ticket custom field - Customer. |
Command Example
!rtir-search-ticket queue=General created-after=2018-07-10 priority-greater-than=10 status=new
[
{
"Created": "Thu Jul 12 03:56:06 2018",
"Creator": "root",
"Due": "Not set",
"FinalPriority": "0",
"InitialPriority": "0",
"LastUpdated": "Thu Jul 12 03:56:06 2018",
"Owner": "Nobody",
"Priority": "12",
"Queue": "General",
"Requestors": [
""
],
"Resolved": "Not set",
"Started": "Not set",
"Starts": "Not set",
"Status": "new",
"Subject": "unbelievable",
"TimeEstimated": "0",
"TimeLeft": "0",
"TimeWorked": "0",
"Told": "Not set",
"id": "ticket/21"
}
}
]
Context Example
{
"RTIR": {
"Ticket": {
{
"Created": "Thu Jul 12 03:56:06 2018",
"Creator": "root",
"FinalPriority": 0,
"ID": 21,
"InitialPriority": 0,
"Owner": "Nobody",
"Priority": 12,
"Queue": "General",
"State": "new",
"Subject": "unbelievable"
}
}
}
3. Close a resolved ticket
Closes a ticket that has been resolved.
Base Command
rtir-resolve-ticket
Input
| Argument Name | Description |
| ticket-id | Ticket ID of the ticket to close. |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.State | Ticket state. |
Command Example
!rtir-resolve-ticket ticket-id=121
Raw Output
Ticket 121 was closed successfully.
Context Example
{
"RTIR":{
"Ticket":{
"ID":"121",
"State":"resolved"
}
}
}
4. Edit a ticket
Edit a specific ticket. Ticket ID specifies which ticket to edit.
Base Command
rtir-edit-ticket
Input
| Input Parameter | Description |
| ticket-id | Ticket ID of the ticket you want to edit. |
| subject | Modified ticket subject. |
| priority | Modified ticket priority (0-100). |
| final-priority | Modified ticket final priority (0-100). |
| owner | Modified ticket owner. |
| status | Modified ticket status. |
| member-of | Modified ticket MembersOF ID |
| members | Modified ticket Members ID |
| depends-on | Modified ticket DependedOn ID |
| depended-on-by | Modified ticket DependedOnBy ID |
| refers-to | Modified ticket RefersTo ID |
| referred-to-by | Modified ticket ReferredToBy ID |
| due |
Modified ticket due date, in the following format: YYYY-MM-DD. For example: 2011-02-24 |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.FinalPriority | Ticket final priority (0-100). |
| RTIR.Ticket.Priority | Ticket priority (0-100). |
| RTIR.Ticket.Owner | Ticket owner. |
| RTIR.Ticket.State | Ticket state. |
| RTIR.Ticket.Subject | Ticket subject. |
Command Example
!rtir-edit-ticket ticket-id=115 final-priority=100 status=open subject=NewTicketSubject
Raw Output
Ticket 115 was edited successfully.
Context Example
{
"RTIR": {
"Ticket": {
"FinalPriority": 100,
"ID": 115,
"Owner": "root",
"Priority": 0,
"State": "open",
"Subject": "NewTicketSubject"
}
}
}
5. Get the history of a ticket
Get the history of a specified ticket.
Base Command
rtir-ticket-history
Input
| Input Parameter | Description |
| ticket-id | Ticket ID for which to retrieve the history. |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.History.Content | Ticket history content. |
| RTIR.Ticket.History.Created | Ticket history creation date. |
| RTIR.Ticket.History.Creator | Ticket history creator. |
| RTIR.Ticket.History.Description | Ticket history description. |
| RTIR.Ticket.History.NewValue | Value updated in history transaction. |
Command Example
!rtir-ticket-history ticket-id=1
Raw Output
[
{
"Attachments": [
[
1,
"untitled (4b)"
]
],
"Content": "test\n",
"Created": "2018-07-09 07:25:47",
"Creator": "root",
"Data": "",
"Description": "Ticket created by root",
"Field": "",
"NewValue": "",
"OldValue": "",
"Ticket": "1",
"TimeTaken": "0",
"Type": "Create",
"id": "54"
}
]
Context Example
{
"RTIR": {
"Ticket": {
"History": [
{
"Content": "test\n",
"Created": "2018-07-09 07:25:47",
"Creator": "root",
"Description": "Ticket created by root"
}
],
"ID": 1
}
}
}
6. Get ticket details
Get the details of a specific ticket.
Base Command
rtir-get-ticket
Input
| Input Parameter | Description |
| ticket-id | Ticket ID for which to retrieve details. |
Context Output
| Path | Description |
| RTIR.Ticket.LinkedTo.ID | Linked ticket ID. |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.State | Ticket state. |
| RTIR.Ticket.Creator | Ticket creator. |
| RTIR.Ticket.Subject | Ticket subject. |
| RTIR.Ticket.Created | Ticket creation date. |
| RTIR.Ticket.Priority | Ticket priority (0-100). |
| RTIR.Ticket.InitialPriority | Ticket initial priority (0-100). |
| RTIR.Ticket.FinalPriority | Ticket final priority (0-100). |
| RTIR.Ticket.Queue | Ticket queue. |
| RTIR.Ticket.Owner | Ticket owner. |
| RTIR.Ticket.IP | Ticket custom field - IP address. |
| RTIR.Ticket.HowReported | Ticket custom field - How the ticket was reported. |
| RTIR.Ticket.Customer | Ticket custom field - Customer. |
Command Example
!rtir-get-ticket ticket-id=1
Raw Output
{
"CF.{Customer}": "",
"CF.{How Reported}": "Email",
"CF.{IP}": "8.8.8.8",
"CF.{Reporter Type}": "",
"Created": "Mon Jul 09 03:25:47 2018",
"Creator": "root",
"Due": "Thu Jul 19 07:47:05 2018",
"FinalPriority": "0",
"InitialPriority": "0",
"LastUpdated": "Thu Jul 12 10:20:02 2018",
"Owner": "root",
"Priority": "0",
"Queue": "Incident Reports",
"Requestors": [
""
],
"Resolved": "Not set",
"Started": "Thu Jul 19 00:00:00 2018",
"Starts": "Not set",
"Status": "open",
"Subject": "test",
"TimeEstimated": "0",
"TimeLeft": "0",
"TimeWorked": "0",
"Told": "Not set",
"id": "ticket/1"
}
Context Example
{
"RTIR": {
"Ticket":
"Created": "Mon Jul 09 03:25:47 2018",
"Creator": "root",
"Due": "Thu Jul 19 07:47:05 2018",
"FinalPriority": 0,
"HowReported": "Email",
"ID": 1,
"IP": "8.8.8.8",
"InitialPriority": 0,
"LinkedTo": [
{
"ID": 15
}
],
"Owner": "root",
"Priority": 0,
"Queue": "Incident Reports",
"State": "open",
"Subject": "test"
}
}
}
7. Get ticket attachments
Returns the attachment details of the specified ticket, and the attachment files to download from the War Room.
Base Command
rtir-ticket-attachments
Input
| Input Parameter | Description |
| ticket-id | Ticket ID for which to retrieve attachments. |
Context Output
| Path | Description |
| RTIR.Ticket.ID | Ticket ID. |
| RTIR.Ticket.Attachment.ID | Attachment ID. |
| RTIR.Ticket.Attachment.Name | Attachment file name. |
| RTIR.Ticket.Attachment.Size | Attachment file size. |
| RTIR.Ticket.Attachment.Type | Attachment file type. |
| File.EntryID | Cortex XSOAR entry ID of the attachment. |
Command Example
!rtir-ticket-attachments ticket-id=41
Raw Output
[
{
"ID": 77,
"Name": "pdf.pdf",
"Size": "423.8k",
"Type": "application/octet-stream"
},
{
"ID": 78,
"Name": "SampleTextFile_10kb.txt",
"Size": "9.2k",
"Type": "text/plain"
}
]
Context Example
{
"RTIR": {
"Ticket": {
"Attachment": [
{
"ID": 77,
"Name": "pdf.pdf",
"Size": "423.8k",
"Type": "application/octet-stream"
},
{
"ID": 78,
"Name": "SampleTextFile_10kb.txt",
"Size": "9.2k",
"Type": "text/plain"
}
],
"ID": 41
}
}
}
8. Add a comment to a ticket
Add a textual comment to a specified ticket.
Base Command
rtir-add-comment
Input
| Input Parameter | Description |
| ticket-id | Ticket ID to add a comment to. |
| text | Text of the comment. |
| attachment |
CSV list of attachment entry IDs to add to the ticket. For example: entryID1,entryID2 |
Context Output
There is no context output for this command.
Command Example
!rtir-add-comment text=CommentText ticket-id=113 attachment=1336@cc6f4232-d87e-496e-82b5-6bbeab422243
Raw Output
Added comment to ticket 113 successfully.
Context Example
There is no context example for this command.
9. Add a reply to a ticket
Add a textual reply to a specified ticket.
Base Command
rtir-add-reply
Input
| Input Parameter | Description |
| ticket-id | Ticket ID to add a comment to. |
| text | Text of the comment. |
| cc |
Email of the user to send the reply. |
Context Output
There is no context output for this command.
Command Example
!rtir-add-reply text=replyText ticket-id=113
Raw Output
Added reply to ticket 113 successfully.
Context Example
There is no context example for this command.
Configuration parameters
server— Server URL (e.g. http://192.168.0.1) (required)credentials— Usernametoken—certificate— Certificateunsecure— Trust any certificate (not secure)proxy— Use system proxy settingsisFetch— Fetch incidentsincidentType— Incident typeincidentFetchInterval— Incidents Fetch Intervalfetch_status— Fetch incidents of the following status:fetch_priority— Fetch incidents with priority greater or equal to:fetch_queue— Queue name to fetch incidents fromreferer— Referer request headerfetch_limit— Fetch incidents limit (the max amount of incidents per fetch iteration)
Commands (9)
-
rtir-add-commentAdd a comment to an existing ticket.
-
rtir-add-replySend a reply from an existing ticket to the user.
-
rtir-create-ticketCreate new ticket on RTIR.
-
rtir-edit-ticketModify a ticket on RTIR.
-
rtir-get-ticketGets the data for a single ticket.
-
rtir-resolve-ticketSets a ticket as resolved on RTIR.
-
rtir-search-ticketSearch for tickets on RTIR.
-
rtir-ticket-attachmentsGets a list of all attachments details and data content related to the ticket.
-
rtir-ticket-historyGets a list of all the history items for a given ticket.
import demistomock as demisto import pytest import requests from CommonServerPython import DemistoException class DotDict(dict): """dot.notation access to dictionary attributes""" __getattr__ = dict.get __setattr__ = dict.__setitem__ # noqa: type: ignore[assignment] __delattr__ = dict.__delitem__ # noqa: type: ignore[assignment] def test_query_formatting(mocker): args = {"ticket-id": 1111} params = { "server": "test", "credentials": {"identifier": "test", "password": "test"}, "fetch_priority": 1, "fetch_status": "test", "fetch_queue": "test", "proxy": True, } mocker.patch.object(requests, "session", return_value=DotDict({})) mocker.patch.object(demisto, "args", return_value=args) mocker.patch.object(demisto, "params", return_value=params) from RTIR import build_search_query query = build_search_query() assert not query.endswith(("+OR+", "+AND+")) RAW_HISTORY = """ RT/4.4.2 200 Ok # 24/24 (id/80/total) id: 80 Ticket: 5 TimeTaken: 0 Type: Create Field: OldValue: NewValue: some new value Data: Description: Ticket created by root Content: Some Multi line Content Creator: root Created: 2018-07-09 11:25:59 Attachments: """ def test_parse_history_response(): from RTIR import parse_history_response parsed_history = parse_history_response(RAW_HISTORY) assert parsed_history == { "ID": "80", "Ticket": "5", "TimeTaken": "0", "Type": "Create", "Field": "", "OldValue": "", "NewValue": "some new value", "Data": "", "Description": "Ticket created by root", "Content": "Some\nMulti line\nContent", "Creator": "root", "Created": "2018-07-09 11:25:59", "Attachments": "", } RAW_LINKS = """RT/4.4.4 200 Ok id: ticket/68315/links Members: some-url.com/ticket/65461, some-url.com/ticket/65462, some-url.com/ticket/65463""" def test_parse_ticket_links(): from RTIR import parse_ticket_links response = parse_ticket_links(RAW_LINKS) expected = [{"ID": "65461"}, {"ID": "65462"}, {"ID": "65463"}] assert response == expected def test_build_ticket_id_in_headers(): """ Given: - A ticket containing 'ID' in its keys When: - building a search ticket Then: - Validate the ticket ID parsed correctly """ from RTIR import build_ticket ticket = build_ticket(["ID: ticket/1"]) expected = {"ID": 1} assert expected == ticket def test_build_ticket_contains_id_in_headers(): """ Given: - A ticket contains a key with 'ID' substring. When: - building a search ticket Then: - Validate nothing returns """ from RTIR import build_ticket ticket = build_ticket(["ThisIsAID: ofNotID"]) assert ticket == {} RAW_ATTACHMENTS_LIST = """ RT/4.4.2 200 Ok id: ticket/6325/attachments Attachments: 504: mimecast-get-remediation-incident.log (text/plain / 3.5k) 505: mimecast-get-remediation-incident2.log (text/plain / 3.6k)""" def test_parse_attachments_list(): """ Test attachment list parsing Given: - Attachment list raw response When: - Trying to parse that response Then: - Ensure response is parsed into a list of tuples with id, name, type, size """ from RTIR import parse_attachments_list response = parse_attachments_list(RAW_ATTACHMENTS_LIST) expected = [ ("504", "mimecast-get-remediation-incident.log", "text/plain", "3.5k"), ("505", "mimecast-get-remediation-incident2.log", "text/plain", "3.6k"), ] assert response == expected RAW_ATTACHMENT_CONTENT = """From: root@localhost Subject: <ticket subject> X-RT-Interface: REST Content-Type: text/plain Content-Disposition: form-data; name="attachment_1"; filename="mimecast-get-remediation-incident.log"; filename="mimecast-get-remediation-incident.log" Content-Transfer-Encoding: binary Content-Length: <length of the content> Content: some multiline attachment content""" def test_parse_attachment_content(): """ Test attachment content Given: - Attachment content raw response When: - Trying to parse that response Then: - Ensure response is parsed into a string with all that comes after the "Content: " """ from RTIR import parse_attachment_content response = parse_attachment_content("1234", RAW_ATTACHMENT_CONTENT) expected = "some multiline\nattachment content" assert response == expected def test_add_reply(mocker): """ Test sending a reply from an existing ticket to the user. Given: - Valid ticket id and text - Valid response When: - Sending a reply to the user Then: - Ensure the reply is sent successfully """ from RTIR import add_reply mocker.patch.object(demisto, "args", return_value={"ticket-id": "1234", "text": "some text"}) mocked_response = requests.Response() mocked_response._content = b"200" mocked_response.status_code = 200 mocker.patch("RTIR.add_reply_request", return_value=mocked_response) mocked_demisto_results = mocker.patch.object(demisto, "results") add_reply() mocked_demisto_results.assert_called_with("Replied successfully to ticket 1234.") def test_add_reply_fail(mocker): """ Test failure in sending a reply from an existing ticket to the user. Given: - Invalid response When: - Sending a reply to the user Then: - Ensure the reply fails with an error message. """ from RTIR import add_reply mocker.patch.object(demisto, "args", return_value={"ticket-id": "1234", "text": "some text"}) mocked_response = requests.Response() mocked_response._content = b"400" mocked_response.status_code = 400 mocker.patch("RTIR.add_reply_request", return_value=mocked_response) mocker.patch("RTIR.demisto.error") with pytest.raises(DemistoException) as e: add_reply() assert str(e.value) == "Failed to reply" def test_add_comment(mocker): """ Test adding a comment to an existing ticket to the user. Given: - Valid ticket id and text - Valid response When: - Adding a comment Then: - Ensure the comment is added sent successfully """ from RTIR import add_comment mocker.patch.object(demisto, "args", return_value={"ticket-id": "1234", "text": "some text"}) mocked_response = requests.Response() mocked_response._content = b"200" mocked_response.status_code = 200 mocker.patch("RTIR.add_comment_request", return_value=mocked_response) mocked_demisto_results = mocker.patch.object(demisto, "results") add_comment() mocked_demisto_results.assert_called_with("Added comment to ticket 1234 successfully.") def test_add_comment_fail(mocker): """ Test failure in adding a comment to an existing ticket. Given: - Args for a comment When: - Getting a failed response Then: - Ensure the command fails with an error message. """ from RTIR import add_comment mocker.patch.object(demisto, "args", return_value={"ticket-id": "1234", "text": "some text"}) mocked_response = requests.Response() mocked_response._content = b"400" mocked_response.status_code = 400 mocker.patch("RTIR.add_comment_request", return_value=mocked_response) with pytest.raises(DemistoException) as e: add_comment() assert str(e.value) == "Failed to add comment" def test_edit_ticket(mocker): """ Test failure in edit a ticket if no fields was given. Given: - ticket id When: - editing a ticket Then: - Ensure the command fails with an error message. """ from RTIR import edit_ticket mocker.patch.object(demisto, "args", return_value={"ticket-id": "1234"}) try: edit_ticket() except Exception as ex: assert ex.message == "No arguments were given to edit the ticket." def test_create_ticket_409_failure(mocker): args = { "queue": "test", "subject": "Test Ticket", "requestor": "test@example.com", "priority": "High", "text": "This is a test ticket", } mock_response = DotDict({"status_code": 200, "text": "RT/5.0.3 409 Syntax Error\nTicket creation failed"}) mocker.patch.object(demisto, "args", return_value=args) mocker.patch("RTIR.create_ticket_request", return_value=mock_response) from RTIR import create_ticket with pytest.raises(DemistoException) as e: create_ticket() assert "Ticket creation failed" in str(e.value) assert "RT/5.0.3 409 Syntax Error" in str(e.value)