def test_json_encode_invalid_keys(self): """ Test that _sanitize can accept some invalid json where a function name or some other bad data is passed as a key in the payload dictionary. """ encoder = SanitizingJSONEncoder(keyword_filters=[]) def foo(): return "123" result = json.loads(encoder.encode({foo: "a"})) self.assertTrue(re.match(r'<function.*foo.*', list(result.keys())[0]) is not None) self.assertEqual(list(result.values()), ["a"]) now = datetime.datetime.now() result = json.loads(encoder.encode({now: "a"})) self.assertEqual(list(result.keys())[0], str(now)) self.assertEqual(list(result.values()), ["a"]) class Object(object): pass result = json.loads(encoder.encode({Object(): "a"})) self.assertTrue(re.match(r'<tests.test_utils.*Object.*', list(result.keys())[0]) is not None) self.assertEqual(list(result.values()), ["a"])
def test_json_encode_invalid_keys(self): """ Test that _sanitize can accept some invalid json where a function name or some other bad data is passed as a key in the payload dictionary. """ encoder = SanitizingJSONEncoder(keyword_filters=[]) def foo(): return "123" result = json.loads(encoder.encode({foo: "a"})) self.assertTrue( re.match(r'<function.*foo.*', list(result.keys())[0]) is not None) self.assertEqual(list(result.values()), ["a"]) now = datetime.datetime.now() result = json.loads(encoder.encode({now: "a"})) self.assertEqual(list(result.keys())[0], str(now)) self.assertEqual(list(result.values()), ["a"]) class Object(object): pass result = json.loads(encoder.encode({Object(): "a"})) self.assertTrue( re.match(r'<tests.test_utils.*Object.*', list(result.keys())[0]) is not None) self.assertEqual(list(result.values()), ["a"])
def test_encoding_recursive_repeated(self): """ Test that encoding the same object twice produces the same result """ data = {"Test": ["a", "b", "c"]} data["Self"] = data encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"Test": ["a", "b", "c"], "Self": "[RECURSIVE]"}) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"Test": ["a", "b", "c"], "Self": "[RECURSIVE]"})
def test_encoding_nested_repeated(self): """ Test that encoding the same object within a new object is not incorrectly marked as recursive """ encoder = SanitizingJSONEncoder(keyword_filters=[]) data = {"Test": ["a", "b", "c"]} encoder.encode(data) data = {"Previous": data, "Other": 400} sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"Other": 400, "Previous": {"Test": ["a", "b", "c"]}})
def _payload(self): # Fetch the notifier version from the package notifier_version = package_version("bugsnag") or "unknown" # Construct the payload dictionary filters = self.config.params_filters encoder = SanitizingJSONEncoder(separators=(',', ':'), keyword_filters=filters) return encoder.encode({ "apiKey": self.api_key, "notifier": { "name": self.NOTIFIER_NAME, "url": self.NOTIFIER_URL, "version": notifier_version, }, "events": [{ "payloadVersion": self.PAYLOAD_VERSION, "severity": self.severity, "releaseStage": self.release_stage, "appVersion": self.app_version, "context": self.context, "groupingHash": self.grouping_hash, "exceptions": [{ "errorClass": class_name(self.exception), "message": self.exception, "stacktrace": self.stacktrace, }], "metaData": self.meta_data, "user": self.user, "device": { "hostname": self.hostname }, "projectRoot": self.config.get("project_root"), "libRoot": self.config.get("lib_root") }] })
def test_sanitize_nested_object_filters(self): data = FilterDict({"metadata": {"another_password": "******"}}) encoder = SanitizingJSONEncoder(keyword_filters=["password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"metadata": { "another_password": "******" }})
def test_sanitize_list(self): data = FilterDict({"list": ["carrots", "apples", "peas"], "passwords": ["abc", "def"]}) encoder = SanitizingJSONEncoder(keyword_filters=["credit_card", "passwords"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"list": ["carrots", "apples", "peas"], "passwords": "[FILTERED]"})
def test_encode_filters(self): data = {"credit_card": "123213213123", "password": "******", "cake": True} encoder = SanitizingJSONEncoder(keyword_filters=["credit_card", "password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"credit_card": "[FILTERED]", "password": "******", "cake": True})
def test_decode_bytes(self): if not is_py3: return data = FilterDict({b"metadata": "value"}) encoder = SanitizingJSONEncoder(keyword_filters=["password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"metadata": "value"})
def test_encode_filters(self): data = FilterDict({"credit_card": "123213213123", "password": "******", "cake": True}) encoder = SanitizingJSONEncoder(keyword_filters=["credit_card", "password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"credit_card": "[FILTERED]", "password": "******", "cake": True})
def test_encoding_recursive(self): """ Test that recursive data structures are replaced with '[RECURSIVE]' """ data = {"Test": ["a", "b", "c"]} data["Self"] = data encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"Test": ["a", "b", "c"], "Self": "[RECURSIVE]"})
def _payload(self): # Fetch the notifier version from the package notifier_version = package_version("bugsnag") or "unknown" filters = self.config.params_filters encoder = SanitizingJSONEncoder(separators=(',', ':'), keyword_filters=filters) # Construct the payload dictionary return encoder.encode({ "apiKey": self.api_key, "notifier": { "name": self.NOTIFIER_NAME, "url": self.NOTIFIER_URL, "version": notifier_version, }, "events": [{ "severity": self.severity, "severityReason": self.severity_reason, "unhandled": self.unhandled, "releaseStage": self.release_stage, "app": { "version": self.app_version, "type": self.app_type, }, "context": self.context, "groupingHash": self.grouping_hash, "exceptions": [{ "errorClass": class_name(self.exception), "message": self.exception, "stacktrace": self.stacktrace, }], "metaData": FilterDict(self.metadata), "user": FilterDict(self.user), "device": FilterDict({ "hostname": self.hostname, "runtimeVersions": self.runtime_versions }), "projectRoot": self.config.project_root, "libRoot": self.config.lib_root, "session": self.session }] })
def test_filter_dict_with_inner_dict(self): """ Test that nested dict uniqueness checks work and are not recycled when a reference to a nested dict goes out of scope """ data = { 'level1-key1': { 'level2-key1': FilterDict({ 'level3-key1': { 'level4-key1': 'level4-value1' }, 'level3-key4': { 'level4-key3': 'level4-value3' }, }), 'level2-key2': FilterDict({ 'level3-key2': 'level3-value1', 'level3-key3': { 'level4-key2': 'level4-value2' }, 'level3-key5': { 'level4-key4': 'level4-value4' }, }), } } encoder = SanitizingJSONEncoder(keyword_filters=['password']) sane_data = json.loads(encoder.encode(data)) self.assertEqual( sane_data, { 'level1-key1': { 'level2-key1': { 'level3-key1': { 'level4-key1': 'level4-value1' }, 'level3-key4': { 'level4-key3': 'level4-value3' } }, 'level2-key2': { 'level3-key2': 'level3-value1', 'level3-key3': { 'level4-key2': 'level4-value2' }, 'level3-key5': { 'level4-key4': 'level4-value4' }, }, } })
def test_encoding_oversized_recursive(self): """ Test that encoding an object which requires trimming clips recursion correctly """ data = {"Test": ["a" * 128 * 1024, "b", "c"], "Other": {"a": 300}} data["Self"] = data encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"Test": ["a" * 1024, "b", "c"], "Self": "[RECURSIVE]", "Other": {"a": 300}})
def __deliver(self, sessions: List[Dict]): if not sessions: bugsnag.logger.debug("No sessions to deliver") return if not self.config.api_key: bugsnag.logger.debug("Not delivering due to an invalid api_key") return if not self.config.should_notify(): bugsnag.logger.debug("Not delivering due to release_stages") return notifier_version = package_version('bugsnag') or 'unknown' payload = { 'notifier': { 'name': Event.NOTIFIER_NAME, 'url': Event.NOTIFIER_URL, 'version': notifier_version }, 'device': FilterDict({ 'hostname': self.config.hostname, 'runtimeVersions': self.config.runtime_versions }), 'app': { 'releaseStage': self.config.release_stage, 'version': self.config.app_version }, 'sessionCounts': sessions } try: filters = self.config.params_filters encoder = SanitizingJSONEncoder(separators=(',', ':'), keyword_filters=filters) encoded_payload = encoder.encode(payload) self.config.delivery.deliver_sessions(self.config, encoded_payload) except Exception as e: bugsnag.logger.exception('Sending sessions failed %s', e)
def __deliver(self, sessions): if not sessions: bugsnag.logger.debug("No sessions to deliver") return if not self.config.api_key: bugsnag.logger.debug("Not delivering due to an invalid api_key") return if not self.config.should_notify: bugsnag.logger.debug("Not delivering due to release_stages") return notifier_version = package_version('bugsnag') or 'unknown' payload = { 'notifier': { 'name': Notification.NOTIFIER_NAME, 'url': Notification.NOTIFIER_URL, 'version': notifier_version }, 'device': FilterDict({ 'hostname': self.config.get('hostname'), }), 'app': { 'releaseStage': self.config.get('release_stage'), 'version': self.config.get('app_version') }, 'sessionCounts': sessions } try: filters = self.config.params_filters encoder = SanitizingJSONEncoder(separators=(',', ':'), keyword_filters=filters) encoded_payload = encoder.encode(payload) self.config.delivery.deliver_sessions(self.config, encoded_payload) except Exception as e: bugsnag.logger.exception('Sending sessions failed %s', e)
def test_json_encode(self): payload = {"a": u("a") * 512 * 1024} expected = {"a": u("a") * 1024} encoder = SanitizingJSONEncoder(keyword_filters=[]) self.assertEqual(json.loads(encoder.encode(payload)), expected)
def test_unfiltered_encode(self): data = {"metadata": {"another_password": "******"}} encoder = SanitizingJSONEncoder(keyword_filters=["password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, data)
def test_sanitize_bad_utf8_object(self): data = {"bad_utf8": u("test \xe9")} encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, data)
def test_sanitize_unencoded_object(self): data = {"exc": Exception()} encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"exc": ""})
def test_sanitize_valid_unicode_object(self): data = {"item": u('\U0001f62c')} encoder = SanitizingJSONEncoder(keyword_filters=[]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, data)
def test_sanitize_nested_object_filters(self): data = FilterDict({"metadata": {"another_password": "******"}}) encoder = SanitizingJSONEncoder(keyword_filters=["password"]) sane_data = json.loads(encoder.encode(data)) self.assertEqual(sane_data, {"metadata": {"another_password": "******"}})