Skip to content

Commit

Permalink
Merge pull request #6 from splunk-soar-connectors/next
Browse files Browse the repository at this point in the history
Merging next to main for release 1.1.0
  • Loading branch information
mhikedrop authored Mar 9, 2023
2 parents 401ce41 + fcf2646 commit c8cd1b7
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 68 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/generate-doc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Generate Readme Doc
on:
workflow_dispatch:
push:
paths:
- '*.json'
- 'readme.html'
tags-ignore:
- '**'
branches-ignore:
- next
- main
jobs:
generate-doc:
runs-on: ubuntu-latest
steps:
- uses: 'phantomcyber/dev-cicd-tools/github-actions/generate-doc@main'
with:
GITHUB_TOKEN: ${{ secrets.SOAR_APPS_TOKEN }}
22 changes: 22 additions & 0 deletions .github/workflows/review-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Review Release
concurrency:
group: app-release
cancel-in-progress: true
permissions:
contents: read
id-token: write
statuses: write
on:
workflow_dispatch:
inputs:
task_token:
description: 'StepFunction task token'
required: true

jobs:
review:
uses: 'phantomcyber/dev-cicd-tools/.github/workflows/review-release.yml@main'
with:
task_token: ${{ inputs.task_token }}
secrets:
resume_release_role_arn: ${{ secrets.RESUME_RELEASE_ROLE_ARN }}
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
repos:
- repo: https://github.com/phantomcyber/dev-cicd-tools
rev: v1.13
rev: v1.16
hooks:
- id: org-hook
- id: package-app-dependencies
- repo: https://github.com/Yelp/detect-secrets
rev: v1.2.0
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--no-verify']
45 changes: 23 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Link

Publisher: Mhike
Connector Version: 1\.0\.1
Connector Version: 1\.1\.0
Product Vendor: Mhike
Product Name: Link
Product Version Supported (regex): "\.\*"
Expand Down Expand Up @@ -66,13 +66,14 @@ The below configuration variables are required for this Connector to operate. T
VARIABLE | REQUIRED | TYPE | DESCRIPTION
-------- | -------- | ---- | -----------
**https\_port** | optional | string | Splunk SOAR HTTPS port if your instance uses one other than 443
**auth\_token** | optional | string | Splunk SOAR auth token if your instance requires auth for internal 127\.0\.0\.1 calls
**debug** | optional | boolean | Print debugging statements to log

### Supported Actions
[add url](#action-add-url) - Generate a widget with clickable links
[add link](#action-add-link) - Generate a widget with clickable links
[test connectivity](#action-test-connectivity) - Test connectivity to local SOAR instance

## action: 'add url'
## action: 'add link'
Generate a widget with clickable links

Type: **generic**
Expand All @@ -90,19 +91,19 @@ PARAMETER | REQUIRED | DESCRIPTION | TYPE | CONTAINS
**sort** | optional | Sort links alphabetically | boolean |

#### Action Output
DATA PATH | TYPE | CONTAINS
--------- | ---- | --------
action\_result\.status | string |
action\_result\.parameter\.append | string |
action\_result\.parameter\.description | string |
action\_result\.parameter\.linkset | string |
action\_result\.parameter\.sort | string |
action\_result\.parameter\.url | string |
action\_result\.data\.\*\.linkset | string |
action\_result\.summary | string |
action\_result\.message | string |
summary\.total\_objects | numeric |
summary\.total\_objects\_successful | numeric |
DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES
--------- | ---- | -------- | --------------
action\_result\.status | string | | success failed
action\_result\.parameter\.append | string | |
action\_result\.parameter\.description | string | |
action\_result\.parameter\.linkset | string | |
action\_result\.parameter\.sort | string | |
action\_result\.parameter\.url | string | |
action\_result\.data\.\*\.linkset | string | |
action\_result\.summary | string | |
action\_result\.message | string | |
summary\.total\_objects | numeric | |
summary\.total\_objects\_successful | numeric | |

## action: 'test connectivity'
Test connectivity to local SOAR instance
Expand All @@ -114,9 +115,9 @@ Read only: **True**
No parameters are required for this action

#### Action Output
DATA PATH | TYPE | CONTAINS
--------- | ---- | --------
action\_result\.status | string |
action\_result\.message | string |
summary\.total\_objects | numeric |
summary\.total\_objects\_successful | numeric |
DATA PATH | TYPE | CONTAINS | EXAMPLE VALUES
--------- | ---- | -------- | --------------
action\_result\.status | string | | success failed
action\_result\.message | string | |
summary\.total\_objects | numeric | |
summary\.total\_objects\_successful | numeric | |
19 changes: 13 additions & 6 deletions link.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"publisher": "Mhike",
"type": "devops",
"main_module": "link_connector.py",
"app_version": "1.0.1",
"utctime_updated": "2022-06-12T14:23:35.606945Z",
"app_version": "1.1.0",
"utctime_updated": "2023-03-09T14:03:35.000000Z",
"package_name": "phantom_link",
"product_vendor": "Mhike",
"product_name": "Link",
Expand All @@ -29,18 +29,25 @@
"name": "https_port",
"id": 0
},
"auth_token": {
"description": "Splunk SOAR auth token if your instance requires auth for internal 127.0.0.1 calls",
"data_type": "string",
"order": 1,
"name": "auth_token",
"id": 1
},
"debug": {
"description": "Print debugging statements to log",
"data_type": "boolean",
"default": false,
"order": 1,
"order": 2,
"name": "debug",
"id": 1
"id": 2
}
},
"actions": [
{
"action": "add url",
"action": "add link",
"description": "Generate a widget with clickable links",
"verbose": "Adds the specified links with the descriptor as the link text. Links are added to the existing link widget if one exists, otherwise a new widget will be generated.",
"type": "generic",
Expand Down Expand Up @@ -191,4 +198,4 @@
"executable": "spawn3",
"disabled": false,
"custom_made": true
}
}
88 changes: 52 additions & 36 deletions link_connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,46 @@

class LinkConnector(phantom.BaseConnector):

print_debug = None

def __init__(self):
super(LinkConnector, self).__init__()
return

def __print(self, value, is_debug):
print_debug = False
try:
print_debug = self.get_config()['debug']
except Exception as e:
self.debug_print("Exception occurred while getting debug key. Exception: {}".format(e))
pass
def __print(self, value, is_debug=False):
if self.print_debug is None:
self.print_debug = False
try:
self.print_debug = self.get_config()['debug']
except Exception as e:
self.debug_print("Exception occurred while getting debug key. Exception: {}".format(e))
message = 'Failed to cast message to string'
try:
message = str(value)
except Exception as e:
self.debug_print("Exception occurred while converting message into string. Exception: {}".format(e))
pass
if is_debug and not print_debug:
if is_debug and not self.print_debug:
return
else:
self.save_progress(message)

def _get_headers(self):
self.__print('_get_headers()', is_debug=True)
try:
auth_token = self.get_config()['auth_token']
if auth_token:
HEADERS = {"ph-auth-token": auth_token}
return HEADERS
else:
return {}
except Exception as e:
self.__print('Failed to retrieve auth token from config')
self.__print(e)
return {}

def _get_previous_links(self):
self.__print('_get_previous_links()', True)
self.__print('_get_previous_links()', is_debug=True)
current_links = []
try:
query_url = ('{0}/rest/container/{1}/actions'
Expand All @@ -53,26 +69,26 @@ def _get_previous_links(self):
'&order=desc'
'&page_size=1'
'&include_expensive').format(self._get_base_url(), self.get_container_id())
self.__print(query_url, True)
response = phantom.requests.get(query_url, verify=False, timeout=30)
self.__print(response.status_code, True)
self.__print(query_url, is_debug=True)
response = phantom.requests.get(query_url, headers=self._get_headers(), verify=False, timeout=30)
self.__print(response.status_code, is_debug=True)
action_id = json.loads(response.text)['data'][0]['id']
results_url = '{0}/rest/action_run/{1}/app_runs?include_expensive'.format(self._get_base_url(), action_id)
self.__print(results_url, True)
response = phantom.requests.get(results_url, verify=False, timeout=30)
self.__print(response.status_code, True)
self.__print(json.loads(response.text)['data'][0]['result_data'][0]['data'][0]['linkset'], True)
self.__print(results_url, is_debug=True)
response = phantom.requests.get(results_url, headers=self._get_headers(), verify=False, timeout=30)
self.__print(response.status_code, is_debug=True)
self.__print(json.loads(response.text)['data'][0]['result_data'][0]['data'][0]['linkset'], is_debug=True)
links = json.loads(response.text)['data'][0]['result_data'][0]['data'][0]['linkset']
for link in links:
current_links.append(link)
self.__print(link, True)
self.__print(link, is_debug=True)
except Exception as e:
self.__print("Exception thrown while gathering previous links", False)
self.__print(e, False)
self.__print("Exception thrown while gathering previous links")
self.__print(e)
return current_links

def _sort_links(self, links):
self.__print('_sort_links()', True)
self.__print('_sort_links()', is_debug=True)
descriptors = []
for link in links:
if link['descriptor'] not in descriptors:
Expand All @@ -88,10 +104,10 @@ def _sort_links(self, links):

def _handle_add_link(self, param):
self.debug_print("In action handler for: {0}".format(self.get_action_identifier()))
self.__print('_link()', True)
self.__print('Single URL: {}'.format(param.get('url')), True)
self.__print('Single Description: {}'.format(param.get('description')), True)
self.__print('Link Set: {}'.format(param.get('linkset')), True)
self.__print('_link()', is_debug=True)
self.__print('Single URL: {}'.format(param.get('url')), is_debug=True)
self.__print('Single Description: {}'.format(param.get('description')), is_debug=True)
self.__print('Link Set: {}'.format(param.get('linkset')), is_debug=True)
action_result = self.add_action_result(ActionResult(dict(param)))
sorting = False
try:
Expand All @@ -111,12 +127,12 @@ def _handle_add_link(self, param):
all_links = all_links.replace('\\', '%5C')
all_links = json.loads(all_links)
for link_set in all_links:
self.__print(link_set, True)
self.__print(link_set, is_debug=True)
try:
if 'descriptor' in link_set and 'url' in link_set and link_set['descriptor'] and link_set['url']:
processed_links.append(link_set)
except:
self.__print('Missing or null values in link: {}'.format(link_set), False)
self.__print('Missing or null values in link: {}'.format(link_set))
if processed_links:
if param.get('append'):
current_links = self._get_previous_links()
Expand All @@ -127,18 +143,18 @@ def _handle_add_link(self, param):
if sorting:
processed_links = self._sort_links(processed_links)
action_result.add_data({'linkset': processed_links})
self.__print('Successfully processed links', False)
self.__print('Successfully processed links')
self.debug_print("Successfully processed links")
action_result.set_status(phantom.APP_SUCCESS, 'Successfully processed links')
return action_result.get_status()
else:
self.debug_print("Failed to process any links from the input")
self.__print('Failed to process any links from the input', False)
self.__print('Failed to process any links from the input')
action_result.set_status(phantom.APP_ERROR, 'Failed to process any links from the input')
return action_result.get_status()

def _get_base_url(self):
self.__print("_get_base_url()", True)
self.__print("_get_base_url()", is_debug=True)
port = 443
try:
port = self.get_config()['https_port']
Expand All @@ -148,30 +164,30 @@ def _get_base_url(self):
return f'https://127.0.0.1:{port}'

def _handle_test_connectivity(self, param):
self.__print("_handle_test_connectivity", True)
self.__print("_handle_test_connectivity", is_debug=True)
self.save_progress("Connecting to endpoint")
action_result = self.add_action_result(ActionResult(dict(param)))
test_url = f'{self._get_base_url()}/rest/version'
self.__print(f'Attempting http get for {test_url}', False)
self.__print(f'Attempting http get for {test_url}')
response = None
try:
response = phantom.requests.get(test_url, verify=False, timeout=30)
self.__print(response.status_code, True)
response = phantom.requests.get(test_url, headers=self._get_headers(), verify=False, timeout=30)
self.__print(response.status_code, is_debug=True)
except Exception as e:
self.debug_print("Exception occured while rest call. Exception: {}".format(e))
pass
if response and 199 < response.status_code < 300:
version = json.loads(response.text)['version']
self.__print(f'Successfully retrieved platform version: {version}', False)
self.__print(f'Successfully retrieved platform version: {version}')
self.save_progress("Test Connectivity Passed.")
return action_result.set_status(phantom.APP_SUCCESS)
else:
self.__print(f'Failed to reach test url: {test_url}\nCheck your hostname config value', False)
self.__print(f'Failed to reach test url: {test_url}\nCheck your hostname config value')
self.save_progress("Test Connectivity Failed.")
return action_result.set_status(phantom.APP_ERROR, f'Failed to reach test url {test_url}')

def handle_action(self, param):
self.__print('handle_action()', True)
self.__print('handle_action()', is_debug=True)
ret_val = phantom.APP_SUCCESS
if self.get_action_identifier() == 'test_connectivity':
ret_val = self._handle_test_connectivity(param)
Expand Down
5 changes: 3 additions & 2 deletions link_widget_view.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{% extends 'widgets/widget_template.html' %}
{% load custom_template %}

<!-- File: link_widget_view.html
Copyright (c) Mhike, 2022
Licensed under the Apache License, Version 2.0 (the "License");
Expand All @@ -9,8 +12,6 @@
either express or implied. See the License for the specific language governing permissions
and limitations under the License.
-->
{% extends 'widgets/widget_template.html' %}
{% load custom_template %}

{% block custom_title_prop %}{% if title_logo %}style="background-size: auto 60%; background-position: 50%; background-repeat: no-repeat; background-image: url('/app_resource/{{ title_logo }}');"{% endif %}{% endblock %}
{% block title1 %}{{ title1 }}{% endblock %}
Expand Down
4 changes: 4 additions & 0 deletions release_notes/1.1.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* Added optional auth token config input to asset for users that need to authenticate internal calls to 127.0.0.1
* Update debug lines to make print code more clear
* Moved copyright notice in django html template below the load calls to fix the widget display issue
* Renamed add url action to add link to fix append bug introduced by initial release

0 comments on commit c8cd1b7

Please sign in to comment.