def test_put_report_tracking_status_json_not_dict_error( self, YesWeHackRawApiClientMock: MagicMock, YesWeHackRawApiReportMock: MagicMock, ) -> None: YesWeHackRawApiClientMock.return_value.login.return_value = True RequestsResponseMock = create_autospec(requests.models.Response) RequestsResponseMock.return_value.json.return_value = 'I am an API response' YesWeHackRawApiReportMock.return_value.put_tracking_status.return_value = RequestsResponseMock() client = YesWeHackApiClient( configuration=YesWeHackConfiguration(), ) raw_report = YesWeHackRawApiReportMock( ywh_api=None, lazy=True, id=123, ) report = Report( raw_report=raw_report, report_id='123', title='A bug report', local_id='YWH-123', bug_type=BugType( name='bug-type', link='http://bug.example.com/type', remediation_link='http://bug.example.com/type/remediation', ), scope='', cvss=Cvss( criticity='critical', score=9.0, vector='vector', ), end_point='/', vulnerable_part='post', part_name='param', payload_sample='abcde', technical_environment='', description_html='This is a bug', attachments=[], hunter=Author( username='******', ), logs=[], status='accepted', tracking_status='AFI', program=ReportProgram( title='My program', slug='my-program', ), ) with self.assertRaises(YesWeHackApiClientError): client.put_report_tracking_status( report=report, tracker_name='tracker', issue_id='foo', issue_url='https://tracker.example.com/issues/foo', status='T', comment='Tracker synchronized.', )
def test_send_report_issue_create_error( self, client_mock_class: MagicMock, incident_model_mock_class: MagicMock, session_mock_class: MagicMock, ) -> None: response = create_autospec(ResponseSpec, spec_set=True) response.data = { 'sys_id': '456', 'number': 'INC0123', } client = client_mock_class(address=ANY, ) client.get_session.return_value = session_mock_class() incident_model = incident_model_mock_class(client=client, ) incident_model.__aenter__.return_value = incident_model incident_model.create.side_effect = AiosnowException tracker_client = ServiceNowTrackerClient( configuration=ServiceNowConfiguration( host='my-instance.servicenow.local', ), ) raw_report = YesWeHackRawApiReport( ywh_api=None, lazy=True, id=123, ) report = Report( raw_report=raw_report, report_id='123', title='A bug report', local_id='YWH-123', bug_type=BugType( name='bug-type', link='http://bug.example.com/type', remediation_link='http://bug.example.com/type/remediation', ), scope='', cvss=Cvss( criticity='critical', score=9.0, vector='vector', ), end_point='/', vulnerable_part='post', part_name='param', payload_sample='abcde', technical_environment='', description_html='This is a bug', attachments=[], hunter=Author(username='******', ), logs=[], status='accepted', tracking_status='AFI', program=ReportProgram( title='My program', slug='my-program', ), ) with self.assertRaises(ServiceNowTrackerClientError): tracker_client.send_report(report=report, )
def test_already_tracked(self, ) -> None: report = self._build_report( report_id=123, tracking_status='T', logs=[ TrackingStatusLog( created_at='2021-01-01T00:00:00+00:00', log_id=1, log_type='tracking-status', private=True, author=Author(username='******', ), message_html='Tracked', attachments=[], tracker_name='my-tracker', tracker_url='http://tracker/issue/1', tracker_id='1', ), ], ) ywh_api_client_mock = create_autospec(YesWeHackApiClient, spec_set=True) tracker_client_mock = create_autospec(TrackerClient, spec_set=True) tracker_client_mock.tracker_type = 'MyTracker' tracker_client_mock.get_tracker_issue.return_value = TrackerIssue( tracker_url='http://tracker/issue/1', project='my-project', issue_id='1', issue_url='http://tracker/issue/1', closed=False, ) Given( case=self, report=report, yeswehack_client=ywh_api_client_mock, tracker_name='my-tracker', tracker_client=tracker_client_mock, synchronize_options=SynchronizeOptions( upload_private_comments=True, upload_public_comments=True, upload_details_updates=True, upload_rewards=True, upload_status_updates=True, ), feedback_options=FeedbackOptions(), message_formatter=SimpleMessageFormatter( tracking_status_update_format= 'issue url: {tracker_issue.issue_url}', synchronization_done_format= 'issue url: {send_logs_result.tracker_issue.issue_url}', download_comment_format='comment: {comment}', status_update_comment_format='comment: {comment}', ), ).when_synchronize_report().then_assert_no_error( ).then_assert_has_result().then_assert_is_existing_issue( ).then_assert_tracker_client_send_report_not_called( ).then_assert_tracker_client_send_logs_not_called( ).then_assert_yeswehack_client_put_report_tracking_status_not_called()
def _map_raw_author( context: MappingContext, raw_author: Union[YesWeHackRawApiAuthor, Dict[str, Any]], ) -> Author: default_username = '******' if isinstance(raw_author, YesWeHackRawApiAuthor): username = raw_author.username or default_username else: username = raw_author.get('username', default_username) return Author(username=username, )
def test_send_report_error_project_not_found( self, gitlab_mock_class: MagicMock, project_manager_mock_class: MagicMock, project_mock_class: MagicMock, project_issues_manager_mock_class: MagicMock, project_issue_mock_class: MagicMock, ) -> None: project_manager_mock = project_manager_mock_class(gl=ANY) gitlab_mock_class.return_value.projects = project_manager_mock project_manager_mock.get.side_effect = GitlabError('Project not found') client = GitLabTrackerClient(configuration=GitLabConfiguration( project='my-project', ), ) raw_report = YesWeHackRawApiReport( ywh_api=None, lazy=True, id=123, ) report = Report( raw_report=raw_report, report_id='123', title='A bug report', local_id='YWH-123', bug_type=BugType( name='bug-type', link='http://bug.example.com/type', remediation_link='http://bug.example.com/type/remediation', ), scope='', cvss=Cvss( criticity='critical', score=9.0, vector='vector', ), end_point='/', vulnerable_part='post', part_name='param', payload_sample='abcde', technical_environment='', description_html='This is a bug', attachments=[], hunter=Author(username='******', ), logs=[], status='accepted', tracking_status='AFI', program=ReportProgram( title='My program', slug='my-program', ), ) with self.assertRaises(GitLabTrackerClientError): client.send_report(report=report, )
def _build_report( self, report_id: int, tracking_status: str = 'AFI', attachments: Optional[List[Attachment]] = None, logs: Optional[List[Log]] = None, ) -> Report: raw_report = YesWeHackRawApiReport( ywh_api=create_autospec(YesWeHackRawApi), lazy=True, id=report_id, ) return Report( raw_report=raw_report, report_id=str(report_id), title='A bug report', local_id=f'YWH-{report_id}', bug_type=BugType( name='bug-type', link='http://bug.example.com/type', remediation_link='http://bug.example.com/type/remediation', ), scope='', cvss=Cvss( criticity='critical', score=9.0, vector='vector', ), end_point='/', vulnerable_part='post', part_name='param', payload_sample='abcde', technical_environment='', description_html='This is a bug', attachments=attachments or [], hunter=Author(username='******', ), logs=logs or [], status='accepted', tracking_status=tracking_status, program=ReportProgram( title='Program 1', slug='program1', ), )
def map_raw_log( # noqa: WPS210,WPS212,WPS231 context: MappingContext, raw_log: YesWeHackRawApiLog, ) -> Log: """ Map a raw API log to a local log. Args: context: a mapping context raw_log: a raw log Returns: a local log """ created_at = raw_log.created_at log_id = raw_log.id log_type = raw_log.type private = raw_log.private author = _map_raw_author( context=context, raw_author=raw_log.author, ) if raw_log.author else Author(username='******', ) message_html = cleanup_ywh_redirects_from_html( ywh_domain=context.yeswehack_domain, html=raw_log.message_html or '', ) attachments = _map_raw_attachments( context=context, raw_attachments=raw_log.attachments, ) if raw_log.type == 'comment': return CommentLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, ) if raw_log.type == 'details-update': return DetailsUpdateLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, old_details=raw_log.old_details, new_details=raw_log.new_details, ) if raw_log.type == 'reward': return RewardLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, reward_type=raw_log.reward_type, ) if raw_log.type == 'status-update': return StatusUpdateLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, old_status=raw_log.old_status, new_status=raw_log.status, ) if raw_log.type == 'tracking-status': return TrackingStatusLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, tracker_name=raw_log.tracker_name, tracker_url=cleanup_ywh_redirects_from_text( ywh_domain=context.yeswehack_domain, text=raw_log.tracker_url, ) if raw_log.tracker_url else None, tracker_id=raw_log.tracker_id, ) if raw_log.type == 'tracker-update': return TrackerUpdateLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, tracker_name=raw_log.tracker_name, tracker_url=cleanup_ywh_redirects_from_text( ywh_domain=context.yeswehack_domain, text=raw_log.tracker_url, ) if raw_log.tracker_url else None, tracker_id=raw_log.tracker_id, tracker_token=raw_log.tracker_token, ) if raw_log.type == 'tracker-message': return TrackerMessageLog( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, tracker_name=raw_log.tracker_name, tracker_url=cleanup_ywh_redirects_from_text( ywh_domain=context.yeswehack_domain, text=raw_log.tracker_url, ) if raw_log.tracker_url else None, tracker_id=raw_log.tracker_id, ) return Log( created_at=created_at, log_id=log_id, log_type=log_type, private=private, author=author, message_html=message_html, attachments=attachments, )
def test_send_report( self, jira_mock_class: MagicMock, issue_mock_class: MagicMock, ) -> None: issue_mock = issue_mock_class(options=ANY, session=ANY) issue_mock.key = '456' issue_mock.permalink.return_value = 'http://tracker/issue/456' jira_mock_class.return_value.create_issue.return_value = issue_mock client = JiraTrackerClient( configuration=JiraConfiguration( project='my-project', ), ) raw_report = YesWeHackRawApiReport( ywh_api=None, lazy=True, id=123, ) report = Report( raw_report=raw_report, report_id='123', title='A bug report', local_id='YWH-123', bug_type=BugType( name='bug-type', link='http://bug.example.com/type', remediation_link='http://bug.example.com/type/remediation', ), scope='', cvss=Cvss( criticity='critical', score=9.0, vector='vector', ), end_point='/', vulnerable_part='post', part_name='param', payload_sample='abcde', technical_environment='', description_html='This is a bug', attachments=[], hunter=Author( username='******', ), logs=[], status='accepted', tracking_status='AFI', program=ReportProgram( title='My program', slug='my-program', ), ) issue = client.send_report( report=report, ) self.assertIsInstance(issue, TrackerIssue) self.assertEqual('456', issue.issue_id) self.assertEqual('http://tracker/issue/456', issue.issue_url) self.assertEqual('my-project', issue.project) self.assertFalse(issue.closed)
def test_send_logs( self, jira_mock_class: MagicMock, issue_mock_class: MagicMock, comment_mock_class: MagicMock, ) -> None: issue_comment_mock = comment_mock_class(options=ANY, session=ANY) issue_comment_mock.id = '147' issue_comment_mock.created = '2020-11-02T15:17:23.420Z' issue_comment_mock.body = 'This is a comment' issue_comment_mock.author = PropertyHolder(raw=None) issue_comment_mock.author.displayName = 'user1' issue_mock = issue_mock_class(options=ANY, session=ANY) issue_mock.key = '456' issue_mock.permalink.return_value = 'http://tracker/issue/456' issue_mock.fields = PropertyHolder(raw=None) issue_mock.fields.status = None jira_mock_class.return_value.issue.return_value = issue_mock jira_mock_class.return_value.add_comment.return_value = issue_comment_mock client = JiraTrackerClient( configuration=JiraConfiguration( project='my-project', ), ) tracker_issue = TrackerIssue( tracker_url='http://tracker/issue/456', project='my-project', issue_id='456', issue_url='http://tracker/issue/456', closed=False, ) logs = [ Log( created_at='2021-01-28 16:00:54.140843', log_id=987, log_type='comment', private=False, author=Author( username='******', ), message_html='This is a comment', attachments=[], ), ] send_logs_result = client.send_logs( tracker_issue=tracker_issue, logs=logs, ) self.assertIsInstance(send_logs_result, SendLogsResult) self.assertEqual(tracker_issue, send_logs_result.tracker_issue) self.assertEqual(1, len(send_logs_result.added_comments)) tracker_issue_comment = send_logs_result.added_comments[0] self.assertEqual('147', tracker_issue_comment.comment_id) self.assertEqual('user1', tracker_issue_comment.author) created_at = datetime.datetime( year=2020, month=11, day=2, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ) self.assertEqual(created_at, tracker_issue_comment.created_at)
def test_send_logs( self, client_mock_class: MagicMock, incident_model_mock_class: MagicMock, session_mock_class: MagicMock, journal_model_mock_class: MagicMock, ) -> None: incident_response = create_autospec(ResponseSpec, spec_set=True) incident_response.data = { 'sys_id': '456', 'number': 'INC0123', 'state': IntegerMapping( key=1, value='New', ), } journal_response = create_autospec(ResponseSpec, spec_set=True) journal_response.data = { 'sys_id': '147', 'sys_created_on': datetime.datetime( year=2020, month=11, day=2, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ), 'sys_created_by': 'user1', 'goo': 'ga' } client = client_mock_class(address=ANY, ) client.get_session.return_value = session_mock_class() incident_model = incident_model_mock_class(client=client, ) incident_model.__aenter__.return_value = incident_model incident_model.get_one.return_value = incident_response journal_model = journal_model_mock_class(client=client, ) journal_model.__aenter__.return_value = journal_model journal_model.get_one.return_value = journal_response tracker_client = ServiceNowTrackerClient( configuration=ServiceNowConfiguration( host='my-instance.servicenow.local', ), ) tracker_issue = TrackerIssue( tracker_url= 'https://my-instance.servicenow.local/nav_to.do?uri=%2Fincident.do%3Fsys_id%3D456', project='my-project', issue_id='456', issue_url= 'https://my-instance.servicenow.local/nav_to.do?uri=%2Fincident.do%3Fsys_id%3D456', closed=False, ) logs = [ Log( created_at='2021-01-28 16:00:54.140843', log_id=987, log_type='comment', private=False, author=Author(username='******', ), message_html='This is a comment', attachments=[], ), ] send_logs_result = tracker_client.send_logs( tracker_issue=tracker_issue, logs=logs, ) self.assertIsInstance(send_logs_result, SendLogsResult) self.assertEqual(tracker_issue, send_logs_result.tracker_issue) self.assertEqual(1, len(send_logs_result.added_comments)) tracker_issue_comment = send_logs_result.added_comments[0] self.assertEqual('147', tracker_issue_comment.comment_id) self.assertEqual('user1', tracker_issue_comment.author) created_at = datetime.datetime( year=2020, month=11, day=2, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ) self.assertEqual(created_at, tracker_issue_comment.created_at)
def test_partially_synced(self, ) -> None: comment_log1 = CommentLog( created_at='2021-01-01T00:00:00+00:00', log_id=1, log_type='comment', private=True, author=Author(username='******', ), message_html='This is a comment', attachments=[], ) tracking_status = TrackingStatusLog( created_at='2021-01-01T00:30:00+00:00', log_id=1, log_type='tracking-status', private=True, author=Author(username='******', ), message_html='Tracked', attachments=[], tracker_name='my-tracker', tracker_url='http://tracker/issue/1', tracker_id='1', ) tracker_update_log1 = TrackerUpdateLog( created_at='2021-01-01T01:00:00+00:00', log_id=2, log_type='tracker-update', private=True, author=Author(username='******', ), message_html='This is a a tracker update', attachments=[], tracker_name='my-tracker', tracker_id='1', tracker_url='http://tracker/issue/1', tracker_token=StateEncryptor.encrypt( key='123', state=TrackerIssueState( closed=False, bugtracker_name='my-tracker', ), ), ) comment_log2 = CommentLog( created_at='2021-01-01T02:00:00+00:00', log_id=3, log_type='comment', private=True, author=Author(username='******', ), message_html='This is another comment', attachments=[], ) report = self._build_report( report_id=123, tracking_status='T', logs=[ comment_log1, tracking_status, tracker_update_log1, comment_log2, ], ) ywh_api_client_mock = create_autospec(YesWeHackApiClient, spec_set=True) tracker_client_mock = create_autospec(TrackerClient, spec_set=True) tracker_client_mock.tracker_type = 'MyTracker' issue = TrackerIssue( tracker_url='http://tracker/issue/1', project='my-project', issue_id='1', issue_url='http://tracker/issue/1', closed=False, ) tracker_client_mock.get_tracker_issue.return_value = issue tracker_client_mock.send_logs.return_value = SendLogsResult( tracker_issue=issue, added_comments=[ TrackerIssueComment( created_at=datetime.datetime( year=2020, month=1, day=1, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ), author='tracker-user', comment_id='456', body='', attachments={}, ), ], ) Given( case=self, report=report, yeswehack_client=ywh_api_client_mock, tracker_name='my-tracker', tracker_client=tracker_client_mock, synchronize_options=SynchronizeOptions( upload_private_comments=True, upload_public_comments=True, upload_details_updates=True, upload_rewards=True, upload_status_updates=True, ), feedback_options=FeedbackOptions(), message_formatter=SimpleMessageFormatter( tracking_status_update_format= 'issue url: {tracker_issue.issue_url}', synchronization_done_format= 'issue url: {send_logs_result.tracker_issue.issue_url}', download_comment_format='comment: {comment}', status_update_comment_format='comment: {comment}', ), ).when_synchronize_report().then_assert_no_error( ).then_assert_has_result().then_assert_is_existing_issue( ).then_assert_tracker_client_send_report_not_called( ).then_assert_tracker_client_send_logs_called_once_with( tracker_issue=issue, logs=[ comment_log2, ], ).then_assert_yeswehack_client_post_report_tracker_update_called_once_with( report=report, tracker_name='my-tracker', issue_id='1', issue_url='http://tracker/issue/1', comment='issue url: http://tracker/issue/1', token=StateEncryptor.encrypt( key='123', state=TrackerIssueState(closed=False, bugtracker_name='my-tracker', downloaded_comments=['456']), ), )
def test_send_logs( self, gitlab_mock_class: MagicMock, project_manager_mock_class: MagicMock, project_mock_class: MagicMock, project_issues_manager_mock_class: MagicMock, project_issue_mock_class: MagicMock, project_issue_note_manager_mock_class: MagicMock, project_issue_note_mock_class: MagicMock, ) -> None: issue_manager_mock = project_issues_manager_mock_class(gl=ANY) project_manager_mock = project_manager_mock_class(gl=ANY) gitlab_mock_class.return_value.projects = project_manager_mock project_mock = project_mock_class(manager=ANY, attrs=ANY) project_mock.issues = issue_manager_mock project_manager_mock.get.return_value = project_mock issue_mock = project_issue_mock_class(manager=ANY, attrs=ANY) issue_mock.id = 456 issue_mock.web_url = 'http://tracker/issue/456' issue_mock.state = 'opened' issue_manager_mock.list.return_value = [issue_mock] project_issue_note_manager_mock = project_issue_note_manager_mock_class( gl=ANY) issue_mock.notes = project_issue_note_manager_mock project_issue_note_mock = project_issue_note_mock_class(manager=ANY, attrs=ANY) project_issue_note_mock.id = 147 project_issue_note_mock.created_at = '2020-11-02T15:17:23.420Z' project_issue_note_mock.author = { 'name': 'user1', } project_issue_note_mock.body = 'This is a comment' project_issue_note_manager_mock.create.return_value = project_issue_note_mock client = GitLabTrackerClient(configuration=GitLabConfiguration( project='my-project', ), ) tracker_issue = TrackerIssue( tracker_url='http://tracker/issue/456', project='my-project', issue_id='456', issue_url='http://tracker/issue/456', closed=False, ) logs = [ Log( created_at='2021-01-28 16:00:54.140843', log_id=987, log_type='comment', private=False, author=Author(username='******', ), message_html='This is a comment', attachments=[], ), ] send_logs_result = client.send_logs( tracker_issue=tracker_issue, logs=logs, ) self.assertIsInstance(send_logs_result, SendLogsResult) self.assertEqual(tracker_issue, send_logs_result.tracker_issue) self.assertEqual(1, len(send_logs_result.added_comments)) tracker_issue_comment = send_logs_result.added_comments[0] self.assertEqual('147', tracker_issue_comment.comment_id) self.assertEqual('user1', tracker_issue_comment.author) created_at = datetime.datetime( year=2020, month=11, day=2, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ) self.assertEqual(created_at, tracker_issue_comment.created_at)
def test_send_logs( self, github_mock_class: MagicMock, named_user_mock_class: MagicMock, repository_mock_class: MagicMock, issue_mock_class: MagicMock, issue_comment_mock_class: MagicMock, ) -> None: created_at = datetime.datetime( year=2020, month=11, day=2, hour=15, minute=17, second=23, microsecond=420000, tzinfo=datetime.timezone.utc, ) user_mock = named_user_mock_class(requester=ANY, headers=ANY, attributes=ANY, completed=ANY) user_mock.id = 1 user_mock.name = 'user1' issue_comment_mock = issue_comment_mock_class(requester=ANY, headers=ANY, attributes=ANY, completed=ANY) issue_comment_mock.id = 147 issue_comment_mock.user = user_mock issue_comment_mock.created_at = created_at issue_comment_mock.body = 'This is a comment' issue_mock = issue_mock_class(requester=ANY, headers=ANY, attributes=ANY, completed=ANY) issue_mock.id = 456 issue_mock.html_url = 'http://tracker/issue/456' issue_mock.closed_at = None issue_mock.create_comment.return_value = issue_comment_mock repository_mock = repository_mock_class(requester=ANY, headers=ANY, attributes=ANY, completed=ANY) repository_mock.get_issues.return_value = [issue_mock] github_mock_class.return_value.get_repo.return_value = repository_mock github_mock_class.return_value.get_user.return_value = user_mock client = GitHubTrackerClient(configuration=GitHubConfiguration( project='my-project', ), ) tracker_issue = TrackerIssue( tracker_url='http://tracker/issue/456', project='my-project', issue_id='456', issue_url='http://tracker/issue/456', closed=False, ) logs = [ Log( created_at='2021-01-28 16:00:54.140843', log_id=987, log_type='comment', private=False, author=Author(username='******', ), message_html='This is a comment', attachments=[], ), ] send_logs_result = client.send_logs( tracker_issue=tracker_issue, logs=logs, ) self.assertIsInstance(send_logs_result, SendLogsResult) self.assertEqual(tracker_issue, send_logs_result.tracker_issue) self.assertEqual(1, len(send_logs_result.added_comments)) tracker_issue_comment = send_logs_result.added_comments[0] self.assertEqual('147', tracker_issue_comment.comment_id) self.assertEqual('user1', tracker_issue_comment.author) self.assertEqual(created_at, tracker_issue_comment.created_at)