|
| 1 | +''' |
| 2 | +tickets |
| 3 | +===== |
| 4 | +The following methods allow for interaction into the Tenable.sc |
| 5 | +:sc-api:`Ticket <Ticket.html>` API. These items are typically seen under the |
| 6 | +Worklow --> Tickets section of Tenable.sc. |
| 7 | +Methods available on ``sc.tickets``: |
| 8 | +.. rst-class:: hide-signature |
| 9 | +.. autoclass:: TicketAPI |
| 10 | + .. automethod:: create |
| 11 | + .. automethod:: details |
| 12 | + .. automethod:: edit |
| 13 | + .. automethod:: list |
| 14 | + Note: you cannot delete tickets, must set them to resolved and they will be auto-purged via system configured retention period |
| 15 | +''' |
| 16 | +from .base import SCEndpoint |
| 17 | + |
| 18 | +class TicketAPI(SCEndpoint): |
| 19 | + def _constructor(self, **kw): |
| 20 | + ''' |
| 21 | + Handles parsing the keywords and returns a ticket document |
| 22 | + ''' |
| 23 | + |
| 24 | + # Validate as dict and pass to assignee |
| 25 | + if 'assignee' in kw: |
| 26 | + kw['assignee'] = self._check('assignee', kw['assignee'], dict) |
| 27 | + |
| 28 | + # all of the following keys are string values and do not require any |
| 29 | + # case conversion. We will simply iterate through them and verify that |
| 30 | + # they are in fact strings. |
| 31 | + keys = ['name', 'description', 'notes'] |
| 32 | + for k in keys: |
| 33 | + if k in kw: |
| 34 | + self._check(k, kw[k], str) |
| 35 | + |
| 36 | + if 'classification' in kw: |
| 37 | + # Verify that classification is one of the correct possible values. |
| 38 | + kw['classification'] = self._check( |
| 39 | + 'classification', |
| 40 | + kw['classification'], |
| 41 | + str, |
| 42 | + choices=[ |
| 43 | + 'Information', |
| 44 | + 'Configuration', |
| 45 | + 'Patch', |
| 46 | + 'Disable', |
| 47 | + 'Firewall', |
| 48 | + 'Schedule', |
| 49 | + 'IDS', |
| 50 | + 'Other', |
| 51 | + 'Accept Risk', |
| 52 | + 'Recast Risk', |
| 53 | + 'Re-scan Request', |
| 54 | + 'False Positive', |
| 55 | + 'System Probe', |
| 56 | + 'External Probe', |
| 57 | + 'Investigation Needed', |
| 58 | + 'Compromised System', |
| 59 | + 'Virus Incident', |
| 60 | + 'Bad Credentials', |
| 61 | + 'Unauthorized Software', |
| 62 | + 'Unauthorized System', |
| 63 | + 'Unauthorized User' |
| 64 | + ] |
| 65 | + ) |
| 66 | + |
| 67 | + if 'status' in kw: |
| 68 | + # Verify that status is one of the correct possible values |
| 69 | + kw['status'] = self._check( |
| 70 | + 'status', |
| 71 | + kw['status'], |
| 72 | + str, |
| 73 | + choices=[ |
| 74 | + 'Assigned', |
| 75 | + 'Resolved', |
| 76 | + 'More Information', |
| 77 | + 'Not Applicable', |
| 78 | + 'Duplicate', |
| 79 | + 'Closed' |
| 80 | + ] |
| 81 | + ) |
| 82 | + return kw |
| 83 | + |
| 84 | + def create(self, name, assignee, **kw): |
| 85 | + ''' |
| 86 | + Creates a ticket. |
| 87 | + :sc-api:`ticket: create <Ticket.html#ticket_POST>` |
| 88 | + Args: |
| 89 | + name (str): |
| 90 | + Required: The name for the ticket |
| 91 | + assignee (dict): |
| 92 | + Required: A dictionary containing one key (id) for the user the ticket is being assigned to |
| 93 | + status (str, optional): |
| 94 | + Optional status of the ticket: assigned, resolved, etc. |
| 95 | + classification (str, optional): |
| 96 | + Optional classification of the ticket type, i.e. Information, Other, etc. |
| 97 | + description (str, optional): |
| 98 | + Optional description for the ticket |
| 99 | + notes (str, optional): |
| 100 | + Optional notes associated with the ticket |
| 101 | + queries (list, optional): |
| 102 | + Optional list of IDs of queries to associate with the ticket |
| 103 | + query (object, optional): |
| 104 | + Optional query object |
| 105 | + Returns: |
| 106 | + :obj:`dict`: |
| 107 | + The newly created ticket. |
| 108 | + Examples: |
| 109 | + >>> ticket = sc.tickets.create('Example Ticket', {'id':1}, status='assigned', classification='information', description='This is an example ticket', notes='Example notes') |
| 110 | + ''' |
| 111 | + kw['name'] = name |
| 112 | + kw['assignee'] = assignee |
| 113 | + payload = self._constructor(**kw) |
| 114 | + return self._api.post('ticket', json=payload).json()['response'] |
| 115 | + |
| 116 | + def details(self, id, fields=None): |
| 117 | + ''' |
| 118 | + Returns the details for a specific ticket. |
| 119 | + :sc-api:`ticket: details <Ticket.html#TicketRESTReference-/ticket/{id}>` |
| 120 | + Args: |
| 121 | + id (int): |
| 122 | + Required: the unique identifier for the ticket to be returned |
| 123 | + fields (list): |
| 124 | + An optional list of attributes to return. |
| 125 | + Returns: |
| 126 | + :obj:`dict`: |
| 127 | + The ticket resource record. |
| 128 | + Examples: |
| 129 | + >>> ticket = sc.tickets.details(1) |
| 130 | + >>> pprint(ticket) |
| 131 | + ''' |
| 132 | + params = {} |
| 133 | + if fields: |
| 134 | + params['fields'] = ','.join([self._check('field', f, str) for f in fields]) |
| 135 | + ticket_id = self._check('id', id, int) |
| 136 | + return self._api.get(f'ticket/{ticket_id}', params=params).json()['response'] |
| 137 | + |
| 138 | + def edit(self, id, **kw): |
| 139 | + ''' |
| 140 | + Edits a ticket. |
| 141 | + :sc-api:`ticket: edit <Ticket.html#ticket_id_PATCH>` |
| 142 | + Args: |
| 143 | + id (int): |
| 144 | + Required: unique identifier of the ticket to be edited |
| 145 | + name (str): |
| 146 | + Optional name for the ticket. Must not be blank. |
| 147 | + assignee (dict): |
| 148 | + Optional dictionary containing one key (id) for the user the ticket is being assigned to |
| 149 | + status (str, optional): |
| 150 | + Optional status of the ticket: assigned, resolved, etc. Must not be blank. |
| 151 | + classification (str, optional): |
| 152 | + Optional classification of the ticket type, i.e. Information, Other, etc. Must not be blank. |
| 153 | + description (str, optional): |
| 154 | + Optional description for the ticket |
| 155 | + notes (str, optional): |
| 156 | + Optional notes associated with the ticket |
| 157 | + queries (list, optional): |
| 158 | + Optional list of IDs of queries to associate with the ticket |
| 159 | + query (object, optional): |
| 160 | + Optional query object |
| 161 | +
|
| 162 | + Returns: |
| 163 | + :obj:`dict`: |
| 164 | + The newly updated ticket. |
| 165 | + Examples: |
| 166 | + >>> ticket = sc.tickets.edit(1, status='Resolved', notes='ran updates') |
| 167 | + ''' |
| 168 | + payload = self._constructor(**kw) |
| 169 | + ticket_id = self._check('id', id, int) |
| 170 | + return self._api.patch(f'ticket/{ticket_id}', json=payload).json()['response'] |
| 171 | + |
| 172 | + def list(self, fields=None): |
| 173 | + ''' |
| 174 | + Outputs a dictionary of usable and manageable tickets, within which is a list of tickets. |
| 175 | + :sc-api:`ticket: list <Ticket.html#ticket_GET>` |
| 176 | + Args: |
| 177 | + fields (list): |
| 178 | + Optional list of attributes to return for each ticket, e.g. ["name","description"]. If not specified, only a list of ticket IDs will return |
| 179 | + Returns: |
| 180 | + :obj:`dict`: |
| 181 | + A dictionary with two lists of ticket resources. |
| 182 | + Examples: |
| 183 | + >>> for ticket in sc.tickets.list(): |
| 184 | + ... pprint(ticket) |
| 185 | + ''' |
| 186 | + params = {} |
| 187 | + if fields: |
| 188 | + params['fields'] = ','.join([self._check('field', f, str) |
| 189 | + for f in fields]) |
| 190 | + |
| 191 | + return self._api.get('ticket', params=params).json()['response'] |
0 commit comments