diff --git a/conf/logs.json b/conf/logs.json index 86a2e3d10..c4ba22800 100644 --- a/conf/logs.json +++ b/conf/logs.json @@ -30,6 +30,7 @@ "acsRegion", "referencedResources", "recipientAccountId", + "requestParameters", "userAgent", "additionalEventData" ] @@ -1811,9 +1812,9 @@ ] } }, - "fleet:results":{ + "fleet:results": { "schema": { - "name":"string", + "name": "string", "hostIdentifier": "string", "calendarTime": "string", "unixTime": "integer", @@ -2094,4 +2095,4 @@ ] } } -} +} \ No newline at end of file diff --git a/docs/source/app-configuration.rst b/docs/source/app-configuration.rst index 43fda7412..65ca3b8c8 100644 --- a/docs/source/app-configuration.rst +++ b/docs/source/app-configuration.rst @@ -54,6 +54,10 @@ Supported Services - Access Logs - Integrations Logs +* `Intercom `_ + +- Admin Activity Logs + * *More to come* @@ -163,3 +167,11 @@ The Aliyun API requires an access key and access key secret for an authorized us To obtain the access key and access key secret, an authorized user of the Aliyun account should follow their directions to `Create an Access Key `_. Additionly, the user for whom the access key was created must have sufficient privileges to make use of ActionTrail; follow the directions on the `Grant ActionTrail permissions to RAM users `_ page. + +How to set up the Intercom App +------------------------------ + +The Intercom API requires an access token. Get an access token by following these `instructions `_. + +To specify an API version, follow `these instructions `_ to do so through Intercom's Developer Hub. +The default will be the latest stable version. The Intercom app works on versions 1.2 or later. diff --git a/requirements-top-level.txt b/requirements-top-level.txt index 14b2fabf5..d0cf96194 100644 --- a/requirements-top-level.txt +++ b/requirements-top-level.txt @@ -1,4 +1,4 @@ -aliyun-python-sdk-core==2.8.5 +aliyun-python-sdk-core==2.13.5 aliyun-python-sdk-actiontrail==2.0.0 autoflake autopep8 diff --git a/requirements.txt b/requirements.txt index 99119bb19..c8c0b7d39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,52 +1,39 @@ -aliyun-python-sdk-core==2.8.5 -aliyun-python-sdk-actiontrail==2.0.0 -autoflake==1.2 -autopep8==1.4.3 -backoff==1.7.0 -bandit==1.5.1 -boto3==1.9.50 -boxsdk==2.0.0a11 -cbapi==1.3.6 -coverage==4.5.2 -coveralls==1.5.1 -google-api-python-client==1.6.4 -jmespath==0.9.3 -jsonlines==1.2.0 -mock==2.0.0 -moto==1.3.7 -netaddr==0.7.19 -nose==1.3.7 -nose-timer==0.7.3 -pathlib2==2.3.2 -policyuniverse==1.3.2.0 -pyfakefs==3.5.3 -pylint==1.9.3 -requests==2.20.1 -Sphinx==1.8.2 -sphinx-rtd-theme==0.4.2 -ushlex==0.99.1 -yapf==0.25.0 -## The following requirements were added by pip freeze: alabaster==0.7.12 +aliyun-python-sdk-actiontrail==2.0.0 +aliyun-python-sdk-core==2.13.5 asn1crypto==0.24.0 astroid==1.6.5 attrdict==2.0.0 +attrs==19.1.0 +autoflake==1.3.1 +autopep8==1.4.4 +aws-sam-translator==1.13.1 aws-xray-sdk==0.95 Babel==2.6.0 +backoff==1.8.0 backports.functools-lru-cache==1.5 backports.ssl-match-hostname==3.5.0.1 backports.tempfile==1.0 backports.weakref==1.0.post1 +bandit==1.6.2 boto==2.49.0 -botocore==1.12.50 +boto3==1.9.208 +botocore==1.12.208 +boxsdk==2.0.0a11 cachetools==3.0.0 +cbapi==1.5.1 certifi==2018.10.15 cffi==1.11.5 +cfn-lint==0.23.3 chainmap==1.0.2 chardet==3.0.4 configparser==3.5.0 cookies==2.2.1 +coverage==4.5.4 +coveralls==1.8.2 cryptography==2.4.2 +DateTime==4.3 +decorator==4.4.0 docker==3.5.1 docker-pycreds==0.3.0 docopt==0.6.2 @@ -54,25 +41,39 @@ docutils==0.14 ecdsa==0.13 enum34==1.1.6 funcsigs==1.0.2 +functools32==3.2.3.post2 future==0.17.1 futures==3.2.0 gitdb2==2.0.5 GitPython==2.1.11 +google-api-python-client==1.6.4 httplib2==0.12.0 idna==2.7 imagesize==1.1.0 ipaddress==1.0.22 isort==4.3.4 -Jinja2==2.10 -jsondiff==1.1.1 +Jinja2==2.10.1 +jmespath==0.9.4 +jsondiff==1.1.2 +jsonlines==1.2.0 +jsonpatch==1.24 jsonpickle==1.0 +jsonpointer==2.0 +jsonschema==3.0.2 lazy-object-proxy==1.3.1 MarkupSafe==1.1.0 mccabe==0.6.1 +mock==3.0.5 +moto==1.3.13 +netaddr==0.7.19 +nose==1.3.7 +nose-timer==0.7.5 oauth2client==4.1.3 packaging==18.0 +pathlib2==2.3.4 pbr==5.1.1 pika==0.12.0 +policyuniverse==1.3.2.0 prompt-toolkit==2.0.7 protobuf==3.6.1 pyaml==18.11.0 @@ -81,31 +82,43 @@ pyasn1-modules==0.2.2 pycodestyle==2.4.0 pycparser==2.19 pycryptodome==3.7.1 +pyfakefs==3.6 pyflakes==2.0.0 Pygments==2.3.0 PyJWT==1.6.4 +pylint==1.9.5 pyOpenSSL==18.0.0 pyparsing==2.3.0 +pyrsistent==0.15.4 python-dateutil==2.7.5 python-jose==2.0.2 pytz==2018.7 -PyYAML==3.13 +PyYAML==5.1.2 +requests==2.22.0 requests-toolbelt==0.8.0 responses==0.10.4 rsa==4.0 -s3transfer==0.1.13 +s3transfer==0.2.1 scandir==1.9.0 singledispatch==3.4.0.3 six==1.11.0 smmap2==2.0.5 snowballstemmer==1.2.1 +solrq==1.1.1 +Sphinx==1.8.5 +sphinx-rtd-theme==0.4.3 sphinxcontrib-websupport==1.1.0 +sshpubkeys==3.1.0 stevedore==1.30.0 typing==3.6.6 uritemplate==3.0.0 -urllib3==1.24.1 +urllib3==1.24.2 +ushlex==0.99.1 +validators==0.13.0 wcwidth==0.1.7 websocket-client==0.54.0 Werkzeug==0.14.1 wrapt==1.10.11 xmltodict==0.11.0 +yapf==0.28.0 +zope.interface==4.6.0 diff --git a/stream_alert/__init__.py b/stream_alert/__init__.py index b930a4f5a..11c5faeb9 100644 --- a/stream_alert/__init__.py +++ b/stream_alert/__init__.py @@ -1,2 +1,2 @@ """StreamAlert version.""" -__version__ = '2.2.1' +__version__ = '2.3.0' diff --git a/stream_alert/apps/_apps/README.rst b/stream_alert/apps/_apps/README.rst index 38f1f10b1..27bea5053 100644 --- a/stream_alert/apps/_apps/README.rst +++ b/stream_alert/apps/_apps/README.rst @@ -7,6 +7,14 @@ To obtain the access key and access key secret, an authorized user of the Aliyun Additionly, the user for whom the access key was created must have sufficient privileges to make use of ActionTrail; follow the directions on the `Grant ActionTrail permissions to RAM users `_ page. +How to set up the intercom app +############################## + +The Intercom API requires an access token. Get an access token by following `these instructions `_. + +To specify an API version, follow `these instructions `_ to do so through Intercom's Developer Hub. +The default will be the latest stable version. The Intercom app works on versions 1.2 or later. + How to set up the slack app ########################### diff --git a/stream_alert/apps/_apps/aliyun-python-sdk-actiontrail==2.0.0_dependencies.zip b/stream_alert/apps/_apps/aliyun-python-sdk-actiontrail==2.0.0_dependencies.zip index d3c8abc10..228f6c7c2 100644 Binary files a/stream_alert/apps/_apps/aliyun-python-sdk-actiontrail==2.0.0_dependencies.zip and b/stream_alert/apps/_apps/aliyun-python-sdk-actiontrail==2.0.0_dependencies.zip differ diff --git a/stream_alert/apps/_apps/intercom.py b/stream_alert/apps/_apps/intercom.py new file mode 100644 index 000000000..7ce99c1a4 --- /dev/null +++ b/stream_alert/apps/_apps/intercom.py @@ -0,0 +1,105 @@ +import calendar +import time +import re + +import requests + +from . import AppIntegration, StreamAlertApp, get_logger + + +LOGGER = get_logger(__name__) + + +@StreamAlertApp +class IntercomApp(AppIntegration): + """Intercom StreamAlert app""" + _INTERCOM_LOGS_URL = 'https://api.intercom.io/admins/activity_logs' + + def __init__(self, event, config): + super(IntercomApp, self).__init__(event, config) + self._next_page = None + + @classmethod + def _type(cls): + return 'admin_activity_logs' + + @classmethod + def service(cls): + return 'intercom' + + @classmethod + def _required_auth_info(cls): + return { + 'token': { + 'description': 'the access token for this Intercom app', + 'format': re.compile(r'^dG9r([0-9A-Za-z+\/=]*)$') + } + } + + def _sleep_seconds(self): + """Return the number of seconds this polling function should sleep for + between requests to avoid failed requests. Intercom API allows for a default of 500 requests + every minute, distributed over 10 seconds periods. This means for a default rate limit of + 500 per minute, you can send a maximum of 83 operations per 10 second period. It's unlikely + we will hit that limit, so this can default to 0. + + Resource(s): + https://developers.intercom.com/intercom-api-reference/reference#rate-limiting + + Returns: + int: Number of seconds that this function should sleep for between requests + """ + return 0 + + def _gather_logs(self): + # Generate headers + headers = {'Authorization': "Bearer %s" % self._config.auth['token'], + 'Accept': 'application/json'} + + # Results are paginated with a page url field provided that is used in subsequent queries. + # If this field exists, make a a query to the page url, and if not, make a fresh query to + # the default _INTERCOM_LOGS_URL with the required created_at_before and created_at_after + # parameters + if self._next_page: + params = None + url = self._next_page + else: + params = {'created_at_before': int(calendar.timegm(time.gmtime())), + 'created_at_after': self._last_timestamp} + url = self._INTERCOM_LOGS_URL + + LOGGER.info("Requesting events from: %s params: %s", url, params) + + try: + result, response = self._make_get_request(url, headers=headers, params=params) + except requests.exceptions.ConnectionError: + LOGGER.exception('Received bad response from Intercom') + return False + + if not result: + return False + + activities = [ + activity + for activity + in response['activity_logs'] + if int(activity['created_at']) > self._last_timestamp] + + if not activities: + return False + + # Save next page url if any for paginated results + if response['pages']['next'] is not None: + self._more_to_poll = True + self._next_page = response['pages']['next'] + else: + self._more_to_poll = False + self._next_page = None + + most_recent_timestamp = max(int(activity['created_at']) for activity in activities) + + # Save most recent time stamp for the next query + if most_recent_timestamp > self._last_timestamp: + self._last_timestamp = most_recent_timestamp + + return activities diff --git a/stream_alert/apps/_apps/onelogin.py b/stream_alert/apps/_apps/onelogin.py index c384fde52..5d9fd6746 100644 --- a/stream_alert/apps/_apps/onelogin.py +++ b/stream_alert/apps/_apps/onelogin.py @@ -25,7 +25,7 @@ class OneLoginApp(AppIntegration): """OneLogin StreamAlert App""" _ONELOGIN_EVENTS_URL = 'https://api.{}.onelogin.com/api/1/events' - _ONELOGIN_TOKEN_URL = 'https://api.{}.onelogin.com/auth/oauth2/v2/token' + _ONELOGIN_TOKEN_URL = 'https://api.{}.onelogin.com/auth/oauth2/v2/token' # nosec _ONELOGIN_RATE_LIMIT_URL = 'https://api.{}.onelogin.com/auth/rate_limit' # OneLogin API returns 50 events per page _MAX_EVENTS_LIMIT = 50 diff --git a/stream_alert/apps/_apps/salesforce.py b/stream_alert/apps/_apps/salesforce.py index d54a1a61a..7bc1dbc9c 100644 --- a/stream_alert/apps/_apps/salesforce.py +++ b/stream_alert/apps/_apps/salesforce.py @@ -57,7 +57,7 @@ class SalesforceApp(AppIntegration): ReportExport: events contain details about reports that a user exported. """ - _SALESFORCE_TOKEN_URL = 'https://login.salesforce.com/services/oauth2/token' + _SALESFORCE_TOKEN_URL = 'https://login.salesforce.com/services/oauth2/token' # nosec _SALESFORCE_QUERY_URL = ('{instance_url}/services/data/v{api_version}/' '{query}{start_time}{event_type}') # Use the Query resource to retrieve log files. diff --git a/stream_alert_cli/manage_lambda/package.py b/stream_alert_cli/manage_lambda/package.py index 30bd5b41d..dfbec8b74 100644 --- a/stream_alert_cli/manage_lambda/package.py +++ b/stream_alert_cli/manage_lambda/package.py @@ -43,17 +43,17 @@ class LambdaPackage(object): # Define a package dict to support pinning versions across all subclasses PACKAGE_LIBS = { 'aliyun-python-sdk-actiontrail': 'aliyun-python-sdk-actiontrail==2.0.0', - 'backoff': 'backoff==1.7.0', - 'boto3': 'boto3==1.9.50', + 'backoff': 'backoff==1.8.0', + 'boto3': 'boto3==1.9.208', 'boxsdk[jwt]': 'boxsdk[jwt]==2.0.0a11', - 'cbapi': 'cbapi==1.3.6', + 'cbapi': 'cbapi==1.5.1', 'google-api-python-client': 'google-api-python-client==1.6.4', - 'jmespath': 'jmespath==0.9.3', + 'jmespath': 'jmespath==0.9.4', 'jsonlines': 'jsonlines==1.2.0', 'netaddr': 'netaddr==0.7.19', 'oauth2client': 'oauth2client==4.1.3', 'policyuniverse': 'policyuniverse==1.3.2.0', - 'requests': 'requests==2.20.1', + 'requests': 'requests==2.22.0', } def __init__(self, config): diff --git a/stream_alert_cli/test/results.py b/stream_alert_cli/test/results.py index b9aa1f190..848f59b85 100644 --- a/stream_alert_cli/test/results.py +++ b/stream_alert_cli/test/results.py @@ -64,7 +64,7 @@ class TestResult(object): _PASS_STRING = format_green('Pass') _FAIL_STRING = format_red('Fail') _SIMPLE_TEMPLATE = '{header}:' - _PASS_TEMPLATE = '{header}: {pass}' + _PASS_TEMPLATE = '{header}: {pass}' # nosec _DESCRIPTION_LINE = ( ''' Description: {description}''' diff --git a/tests/unit/stream_alert_apps/test_apps/test_aliyun.py b/tests/unit/stream_alert_apps/test_apps/test_aliyun.py index 87fc01c7f..9f36fc915 100644 --- a/tests/unit/stream_alert_apps/test_apps/test_aliyun.py +++ b/tests/unit/stream_alert_apps/test_apps/test_aliyun.py @@ -99,5 +99,5 @@ def test_gather_logs_entries(self, client_mock): '"StartTime":"2018-06-23T19:28:30Z"}' logs = self._app._gather_logs() assert_equal(2, len(logs)) - assert self._app._more_to_poll + assert self._app._more_to_poll # nosec assert_equal(self._app.request.get_NextToken(), "20") diff --git a/tests/unit/stream_alert_apps/test_apps/test_app_base.py b/tests/unit/stream_alert_apps/test_apps/test_app_base.py index d384a3d29..3bc4ed49c 100644 --- a/tests/unit/stream_alert_apps/test_apps/test_app_base.py +++ b/tests/unit/stream_alert_apps/test_apps/test_app_base.py @@ -56,6 +56,7 @@ def test_get_all_apps(self): 'gsuite_rules', 'gsuite_saml', 'gsuite_token', + 'intercom_admin_activity_logs', 'onelogin_events', 'salesforce_console', 'salesforce_login', diff --git a/tests/unit/stream_alert_apps/test_apps/test_duo.py b/tests/unit/stream_alert_apps/test_apps/test_duo.py index 8711e68e4..291ac538c 100644 --- a/tests/unit/stream_alert_apps/test_apps/test_duo.py +++ b/tests/unit/stream_alert_apps/test_apps/test_duo.py @@ -75,7 +75,7 @@ def _get_sample_logs(count, base_time): 'device': '+1 123 456 1234', 'factor': 'Duo Push', 'integration': 'Test Access', - 'ip': '0.0.0.0', + 'ip': '0.0.0.0', # nosec 'location': {}, 'new_enrollment': False, 'reason': 'No response', diff --git a/tests/unit/stream_alert_apps/test_apps/test_intercom.py b/tests/unit/stream_alert_apps/test_apps/test_intercom.py new file mode 100644 index 000000000..f0e889d3a --- /dev/null +++ b/tests/unit/stream_alert_apps/test_apps/test_intercom.py @@ -0,0 +1,237 @@ +import os + +from mock import Mock, patch +from moto import mock_ssm +from nose.tools import ( + assert_equal, assert_false, assert_items_equal, assert_is_none +) +# import requests + +from stream_alert.apps._apps.intercom import IntercomApp +from tests.unit.stream_alert_apps.test_helpers import ( + get_event, + put_mock_params +) +from tests.unit.stream_alert_shared.test_config import get_mock_lambda_context + + +@mock_ssm +class TestIntercomApp(object): + """Test class for the IntercomApp""" + # pylint: disable=protected-access + + @patch.dict(os.environ, {'AWS_DEFAULT_REGION': 'us-east-1'}) + def setup(self): + """Setup before each method""" + # pylint: disable=abstract-class-instantiated,attribute-defined-outside-init + self._test_app_name = 'intercom' + put_mock_params(self._test_app_name) + self._event = get_event(self._test_app_name) + self._context = get_mock_lambda_context(self._test_app_name) + self._app = IntercomApp(self._event, self._context) + self._app._config.auth['token'] = 'good_token' # nosec + + def test_required_auth_info(self): + """IntercomApp - Required Auth Info""" + assert_items_equal(self._app._required_auth_info().keys(), + {'token'}) + + @staticmethod + def _get_sample_access_logs(): + """Sample logs""" + return { + 'type': 'activity_log.list', + 'pages': { + 'type': 'pages', + 'next': None, + 'page': 1, + 'per_page': 20, + 'total_pages': 1 + }, + 'activity_logs': [ + { + 'id': '1234', + 'performed_by': { + 'type': 'admin', + 'id': '4321', + 'email': 'cool.admin@company.com', + 'ip': '10.27.91.27' + }, + 'metadata': { + 'sign_in_method': 'email' + }, + 'created_at': '1537130098', + 'activity_type': 'admin_login_success', + 'activity_description': 'Cool Admin successfully logged in.' + }, + { + 'id': '1235', + 'performed_by': { + 'type': 'admin', + 'id': '5321', + 'email': 'also.cool.admin@company.com', + 'ip': '79.120.152.79' + }, + 'metadata': { + 'message': { + 'id': '5678', + 'title': 'All things cool' + }, + 'before': 'draft', + 'after': 'live' + }, + 'created_at': '1537218403', + 'activity_type': 'message_state_change', + 'activity_description': + 'Also Cool Admin changed your All things cool message from draft to live.' + }, + ] + } + + def test_headers(self): + return {'Authorization': "Bearer %s" % self._app._config.auth['token'], + 'Accept': 'application/json'} + + @patch('requests.get') + def test_gather_intercom_logs_bad_response(self, requests_mock): + """IntercomApp - Gather Logs, Bad Response""" + requests_mock.return_value = Mock( + status_code=404, + content='something went wrong') + + assert_false(self._app._gather_logs()) + + # The .json should be called on the response once, to return the response. + assert_equal(requests_mock.return_value.json.call_count, 1) + + @patch('calendar.timegm') + @patch('requests.get') + def test_gather_intercom_logs_no_pagination(self, requests_mock, time_mock): + """IntercomApp - Gather Logs No Pagination""" + logs = self._get_sample_access_logs() + requests_mock.return_value = Mock( + status_code=200, + json=Mock(return_value=logs) + ) + + time_mock.return_value = 100 + + gathered_logs = self._app._gather_logs() + + params = { + 'created_at_before': 100, + 'created_at_after': 0 + } + + assert_equal(len(gathered_logs), 2) + assert_false(self._app._more_to_poll) + assert_is_none(self._app._next_page) + requests_mock.assert_called_once_with( + self._app._INTERCOM_LOGS_URL, + headers=self.test_headers(), + params=params, + timeout=self._app._DEFAULT_REQUEST_TIMEOUT) + + @patch('calendar.timegm') + @patch('requests.get') + def test_gather_intercom_logs_response_with_next_page(self, requests_mock, time_mock): + """IntercomApp - Gather Logs Next Page""" + logs = self._get_sample_access_logs() + logs['pages']['next'] = '1234abc' + requests_mock.return_value = Mock( + status_code=200, + json=Mock(return_value=logs) + ) + + time_mock.return_value = 100 + + gathered_logs = self._app._gather_logs() + + params = { + 'created_at_before': 100, + 'created_at_after': 0 + } + + assert_equal(len(gathered_logs), 2) + assert_equal(self._app._more_to_poll, True) + assert_equal(self._app._next_page, '1234abc') + requests_mock.assert_called_once_with( + self._app._INTERCOM_LOGS_URL, + headers=self.test_headers(), + params=params, + timeout=self._app._DEFAULT_REQUEST_TIMEOUT) + + @patch('requests.get') + def test_gather_intercom_logs_pagination(self, requests_mock): + """IntercomApp - Gather Logs Pagination""" + logs = self._get_sample_access_logs() + self._app._next_page = '567cde' + requests_mock.return_value = Mock( + status_code=200, + json=Mock(return_value=logs) + ) + + gathered_logs = self._app._gather_logs() + + assert_equal(len(gathered_logs), 2) + requests_mock.assert_called_once_with( + '567cde', + headers=self.test_headers(), + params=None, + timeout=self._app._DEFAULT_REQUEST_TIMEOUT) + + @patch('calendar.timegm') + @patch('requests.get') + def test_gather_intercom_logs_setting_last_timestamp(self, requests_mock, time_mock): + """IntercomApp - Gather Logs Setting _last_timestamp""" + logs = self._get_sample_access_logs() + requests_mock.return_value = Mock( + status_code=200, + json=Mock(return_value=logs) + ) + + time_mock.return_value = 100 + assert_equal(self._app._last_timestamp, 0) + + gathered_logs = self._app._gather_logs() + + params = { + 'created_at_before': 100, + 'created_at_after': 0 + } + + assert_equal(len(gathered_logs), 2) + assert_equal(self._app._last_timestamp, 1537218403) + requests_mock.assert_called_once_with( + self._app._INTERCOM_LOGS_URL, + headers=self.test_headers(), + params=params, + timeout=self._app._DEFAULT_REQUEST_TIMEOUT) + + @patch('calendar.timegm') + @patch('requests.get') + def test_gather_intercom_logs_by_last_timestamp(self, requests_mock, time_mock): + """IntercomApp - Gather Logs Filtering By _last_timestamp""" + logs = self._get_sample_access_logs() + self._app._last_timestamp = 1537218402 + requests_mock.return_value = Mock( + status_code=200, + json=Mock(return_value=logs) + ) + + time_mock.return_value = 100 + + gathered_logs = self._app._gather_logs() + + params = { + 'created_at_before': 100, + 'created_at_after': 1537218402 + } + + assert_equal(len(gathered_logs), 1) + assert_equal(self._app._last_timestamp, 1537218403) + requests_mock.assert_called_once_with( + self._app._INTERCOM_LOGS_URL, + headers=self.test_headers(), + params=params, + timeout=self._app._DEFAULT_REQUEST_TIMEOUT) diff --git a/tests/unit/stream_alert_apps/test_apps/test_onelogin.py b/tests/unit/stream_alert_apps/test_apps/test_onelogin.py index 7709b6216..5378422b1 100644 --- a/tests/unit/stream_alert_apps/test_apps/test_onelogin.py +++ b/tests/unit/stream_alert_apps/test_apps/test_onelogin.py @@ -98,7 +98,7 @@ def _get_sample_events(count, next_link): 'user_id': 321, 'event_type_id': 4321, 'notes': 'Notes', - 'ipaddr': '0.0.0.0', + 'ipaddr': '0.0.0.0', # nosec 'actor_user_id': 987, 'assuming_acting_user_id': 654, 'role_id': 456, diff --git a/tests/unit/stream_alert_apps/test_apps/test_slack.py b/tests/unit/stream_alert_apps/test_apps/test_slack.py index d336be747..0d57f9a60 100644 --- a/tests/unit/stream_alert_apps/test_apps/test_slack.py +++ b/tests/unit/stream_alert_apps/test_apps/test_slack.py @@ -228,14 +228,14 @@ def test_gather_logs_before_parameter(self, requests_mock): self._app._last_timestamp = 1522922593 gathered_logs = self._app._gather_logs() - assert 'before' not in requests_mock.call_args[1]['data'].keys() + assert 'before' not in requests_mock.call_args[1]['data'].keys() # nosec assert_equal(len(gathered_logs), 0) assert_equal(self._app._next_page, 1) assert_equal(True, self._app._more_to_poll) assert_equal(self._app._before_time, logs['logins'][-1]['date_first']) self._app._gather_logs() - assert 'before' in requests_mock.call_args[1]['data'].keys() + assert 'before' in requests_mock.call_args[1]['data'].keys() # nosec @mock_ssm diff --git a/tests/unit/stream_alert_shared/test_aws_api_client.py b/tests/unit/stream_alert_shared/test_aws_api_client.py index 6f7c1a88f..218ed2b41 100644 --- a/tests/unit/stream_alert_shared/test_aws_api_client.py +++ b/tests/unit/stream_alert_shared/test_aws_api_client.py @@ -31,7 +31,7 @@ class TestAwsKms(object): @mock_kms def test_encrypt_decrypt(): """AwsApiClient - AwsKms - encrypt/decrypt - Encrypt and push creds, then pull them down""" - secret = 'shhhhhh' + secret = 'shhhhhh' # nosec ciphertext = AwsKms.encrypt(secret, region=REGION, key_alias=KMS_ALIAS) response = AwsKms.decrypt(ciphertext, region=REGION) diff --git a/tests/unit/stream_alert_shared/test_rule.py b/tests/unit/stream_alert_shared/test_rule.py index 4d19f1182..01a426aa5 100644 --- a/tests/unit/stream_alert_shared/test_rule.py +++ b/tests/unit/stream_alert_shared/test_rule.py @@ -61,7 +61,7 @@ def {}(_): return False """.format(rule_name) - exec custom_rule_code # pylint: disable=exec-used + exec custom_rule_code # nosec # pylint: disable=exec-used def test_rule_valid(self): """Rule - Create Valid Rule""" @@ -198,7 +198,7 @@ def test_rule_checksum(self): ast_value = 'Return(value=Name(id=\'False\', ctx=Load()))' # The known checksum of the above is # c119f541816c6364ea3e2e884ba18f9c - expected_checksum = hashlib.md5(ast_value).hexdigest() + expected_checksum = hashlib.md5(ast_value).hexdigest() # nosec # Test rule without a docstring rule.Rule(_test_checksum, logs=['log_type'])