Skip to content

Commit

Permalink
Penfield AI Pull Request 2 (#16028)
Browse files Browse the repository at this point in the history
* Penfield AI Pull Request 2 (#15523)

* penfield init

* issue 1: remove unowned files from pack-ignore

* address pull request issues

* address pull request issues 2

* remove code comment

* udpate command results

* change healthy response code

* xflake and unittest work

* Update penfield content pack metadata with company info

* Update to use string as analyst_ids arg

* Add Penfield Assign playbook

* Add playbook README with the playbook image (#2)

* use argToList helper instead of split

* Update Packs/PenfieldAI/Playbooks/Penfield_Assign.yml

Update fromversion to 6.0.0

Co-authored-by: Darya Koval <72339940+daryakoval@users.noreply.github.com>

Co-authored-by: the-naturel <84140868+the-naturel@users.noreply.github.com>
Co-authored-by: Long <long@penfield.ai>
Co-authored-by: Long Tan <8885550+L-Tan@users.noreply.github.com>
Co-authored-by: Darya Koval <72339940+daryakoval@users.noreply.github.com>

* formatting files

Co-authored-by: penfield-chan <84140868+penfield-chan@users.noreply.github.com>
Co-authored-by: the-naturel <84140868+the-naturel@users.noreply.github.com>
Co-authored-by: Long <long@penfield.ai>
Co-authored-by: Long Tan <8885550+L-Tan@users.noreply.github.com>
Co-authored-by: Darya Koval <72339940+daryakoval@users.noreply.github.com>
Co-authored-by: Darya Koval <dkoval@paloaltonetworks.com>
  • Loading branch information
7 people committed Nov 30, 2021
1 parent 8ac76f8 commit 992d942
Show file tree
Hide file tree
Showing 25 changed files with 1,191 additions and 0 deletions.
Empty file added Packs/PenfieldAI/.pack-ignore
Empty file.
88 changes: 88 additions & 0 deletions Packs/PenfieldAI/.secrets-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
FE80:0000:0000:0000:0202:B3FF:FE1E:8329
2001:0db8:85a3:0000:0000:8a2e:0370:7334
2001:0db8:85a3:1337:0000:8a2e:0370:7334
2001:db8:a0b:12f0::1
1.1.1.1
user@example.com
8.8.8.8
192.168.1.1
192.168.1.12
6.6.6.6
2001:db8:a0b:12f0::1aaa
http://example.com
2001:db8:a0b:12f0::98aa
FE80::0202:B3FF:FE1E:8329
10.10.10.10
https://exchange.xforce.ibmcloud.com
user@example.com
8.8.8.8
https://google.com
https://example.com
https://docs.microsoft.com
192.168.0.0
10.0.0.0
172.16.0.0
127.0.0.0
169.254.0.0
https://192.12.12.3
192.12.12.3
192.168.2.1
https://some_url.com
xsoar.pan.dev
@test.com
registrar@test.com
11.111.11.11
::deb
http://www.letsseeifyoucanfindthisone4444.co.il
111.11.11.111
https://www.a.com
http://www.c.com
mt.kb.user@gmail.com
@pytest.mark.parametrize
1::6:7:8
1:2:3:4:5:6::8
1:2::8
1:2:3:4::8
['::2:3:4:5:6:7:8', '1::3:4:5:6:7:8']
::2:3:4:5:6:7:8
1::3:4:5:6:7:8
a@gmail.com
1a:2b::4c:5:6:7:8
1a:2b::4c:5abc
['1a:2b::4c:5:6:7:8', '1a:2b::4c:5abc']
DBotScoreType.FILE,
2.5.29.17
2.5.29.14
2.5.29.15
2.5.29.37
2.5.29.35
2.5.29.31
2.5.29.32
['1.3.6.1', '5.5.7.1']
2.5.29.19
1.3.6.1
:attr:`Retry.BACKOFF_MAX`.
dict_safe_get(dict,['something',
http://crl3.digicert.com
http://crl4.digicert.com
https://www.digicert.com
http://ocsp.digicert.com
http://cacerts.digicert.com
KEY-----\\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFw'
KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFw'
key_identifier="0f80611c823161d52f28e78d4638b42ce1c6d9e2"
digest="b34972bb12121b8851cd5564ff9656dcbca3f288",
log_id="f65c942fd1773022145418083094568ee34d131933bfdf0c2f200bcc4ef164e3",
log_id="5cdc4392fee6ab4544b15e9ad456e61037fbd5fa47dca17394b25ee6f6c70eca",
sha256='bc33cf76519f1ec5ae7f287f321df33a7afd4fd553f364cf3c753f91ba689f8d',
sha1='2392ea5cd4c2a61e51547570634ef887ab1942e9',
spki_sha256='94b716aeda21cd661949cfbf3f55457a277da712cdce0ab31989a4f288fad9b9',
"2392ea5cd4c2a61e51547570634ef887ab1942e9",
"94b716aeda21cd661949cfbf3f55457a277da712cdce0ab31989a4f288fad9b9",
2.23.140.1
'53e6baa124f54462786f1122e98e38ff1be3de82fe2a96b1849a8637043fd847eec7e0f53307bddf7a066565292d500c36c941f1f3bb9dcac807b2f4a0bfce1b',
http://proxy
http://testproxy
https://testproxy
http://165.225.225.99
165.225.225.99
Binary file added Packs/PenfieldAI/Author_image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
112 changes: 112 additions & 0 deletions Packs/PenfieldAI/Integrations/Penfield/Penfield.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import urllib3
import traceback
import demistomock as demisto
from CommonServerPython import * # pylint: disable=unused-wildcard-import
from CommonServerUserPython import * # noqa


# Disable insecure warnings
urllib3.disable_warnings()

''' CLIENT CLASS '''


class Client(BaseClient):
def live_assign_get(self, analyst_ids, category, created, arg_id, name, severity) -> str:
params = assign_params(
analyst_ids=analyst_ids,
category=category,
created=created,
id=arg_id,
name=name,
severity=severity
)
response = self._http_request(
method='POST',
url_suffix='/api/v1/xsoar_live_assign/',
params=params
)
return response['analyst']

def test(self) -> str:
response = self._http_request(
method='GET',
url_suffix='/api/v1/xsoar_live_assign/'
)
return response


''' HELPER FUNCTIONS '''


def get_assignee(client: Client, args) -> CommandResults:
analyst_ids = argToList(args.get('analyst_ids'))
category = args.get('category')
created = args.get('created')
arg_id = args.get('id')
name = args.get('name')
severity = args.get('severity')
analyst = client.live_assign_get(analyst_ids, category, created, arg_id, name, severity)
human_readable = tableToMarkdown(
'Analyst Penfield Recommends',
analyst,
headers=['Recommendation'],
headerTransform=pascalToSpace,
removeNull=True
)
return CommandResults(
readable_output=human_readable,
outputs_prefix='Penfield.Recommended',
outputs_key_field='Analyst',
outputs=analyst
)


def test_api(client: Client):
return client.test()


''' MAIN FUNCTION '''


def main() -> None:
api_key = demisto.params().get('apikey')
base_url = urljoin(demisto.params()['url'], '')
verify_certificate = not demisto.params().get('insecure', False)
proxy = demisto.params().get('proxy', False)

demisto.debug(f'Command being called is {demisto.command()}')
try:
headers = {
'Authorization': f'Bearer {api_key}'
}
client = Client(
base_url=base_url,
verify=verify_certificate,
headers=headers,
proxy=proxy
)

if demisto.command() == 'test-module':
result = test_api(client)
if int(result) == 0:
return_results('ok')
else:
raise RuntimeError('Penfield API cannot be reached')

elif demisto.command() == 'penfield-get-assignee':
result = get_assignee(client, demisto.args())
return_results(result)

# Log exceptions and return errors
except Exception as e:
demisto.error(traceback.format_exc()) # print the traceback
return_error(
f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}'
)


''' ENTRY POINT '''

if __name__ in ('__main__', '__builtin__', 'builtins'):
main()
74 changes: 74 additions & 0 deletions Packs/PenfieldAI/Integrations/Penfield/Penfield.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
category: Case Management
commonfields:
id: Penfield
version: -1
configuration:
- defaultvalue: https://example.com/
display: Your server URL
name: url
required: true
type: 0
- display: API Key
additionalinfo: The API Key to use for connection
name: apikey
required: true
type: 4
- display: Trust any certificate (not secure)
name: insecure
required: false
type: 8
- display: Use system proxy settings
name: proxy
required: false
type: 8
description: "The penfield-get-assignee command takes in necessary context data, and\
\ returns the analyst that Penfield believes the incident should be assigned to\
\ based on Penfield's models of skill and process. The test command verfies that\
\ the endpoint is reachable."
display: 'Penfield'
name: Penfield
script:
commands:
- name: penfield-get-assignee
description: 'Calls the Penfield API and returns the analyst Penfield recommends
assigning the incident to. This information is saved in the output, but the
incident will not be automatically assigned.'
outputs:
- contextPath: Penfield.Recommended.Analyst
description: The XSOAR analyst Penfield recommends assigning the incident to.
type: String
arguments:
- name: analyst_ids
description: 'An array of XSOAR analyst IDs for Penfield to choose from when
determining who to assign to.'
required: true
isArray: true
- name: category
required: true
description: 'The category of the incident to assign. Can be taken from incident
Context Data.'
- name: created
required: true
description: 'The creation_date of the incident to assign. Can be taken from
incident Context Data.'
- name: id
required: true
description: 'The id of the incident to assign. Can be taken from incident Context
Data.'
- name: name
required: true
description: 'The name of the incident to assign. Can be taken from incident
Context Data.'
- name: severity
required: true
description: 'The severity of the incident to assign. Can be taken from incident
Context Data.'
isfetch: false
runonce: false
script: '-'
type: python
subtype: python3
dockerimage: demisto/python3:3.9.8.24399
fromversion: 6.0.0
tests:
- No tests (auto formatted)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Integration Help

For this integration, you will need to have a deployed instance of PenfieldCore. Please contact Penfield to get this done. During the setup process, Penfield will provide an API key and the URL of the endpoint, which will vary depending upon how the setup was performed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
56 changes: 56 additions & 0 deletions Packs/PenfieldAI/Integrations/Penfield/Penfield_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import demistomock as demisto
from Penfield import main, get_assignee, Client
import json
import io


def util_load_json(path):
with io.open(path, mode='r', encoding='utf-8') as f:
return json.loads(f.read())


def test_main(mocker):
mock_users = "username1,username2"
mock_incident = util_load_json('test_data/test_incident.json')

mocker.patch.object(demisto, 'command', return_value="penfield-get-assignee")
mocker.patch.object(demisto, 'args', return_value={'analysts': mock_users, 'incident': mock_incident})
mocker.patch('Penfield.get_assignee', return_value="test")
mocker.patch.object(demisto, 'results')
mocker.patch.object(demisto, 'params', return_value={'url': 'https://fakeurl.ai/api/v1/xsoar_live_assign/'})

main()

assert demisto.results.call_args.args[0] == 'test'


def test_get_assignee(mocker):

mock_users = "username1,username2"

mocker.patch.object(demisto, 'args', return_value={
'analyst_ids': mock_users,
'category': 'test_category',
'created': '2021-03-02',
'arg_id': 123,
'name': 'test name',
'severity': 'high'
})
mocker.patch('Penfield.Client.live_assign_get', return_value="test_cr_response")

api_key = demisto.params().get('apikey')
base_url = 'https://test.com'
verify_certificate = not demisto.params().get('insecure', False)
proxy = demisto.params().get('proxy', False)

headers = {
'Authorization': f'Bearer {api_key}'
}
client = Client(
base_url=base_url,
verify=verify_certificate,
headers=headers,
proxy=proxy
)

assert type(get_assignee(client, demisto.args())).__name__ == "CommandResults"
18 changes: 18 additions & 0 deletions Packs/PenfieldAI/Integrations/Penfield/Pipfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pylint = "*"
pytest = "==5.0.1"
pytest-mock = "*"
requests-mock = "*"
pytest-asyncio = "*"

[packages]
pytest = "*"
requests = "*"

[requires]
python_version = "3.7"
Loading

0 comments on commit 992d942

Please sign in to comment.