def _create_issuetracker_info(assessment, issue_tracker_info):
  """Creates an entry for IssueTracker model."""
  if not issue_tracker_info.get('title'):
    issue_tracker_info['title'] = assessment.title
  if not issue_tracker_info.get('due_date'):
    issue_tracker_info['due_date'] = assessment.start_date
  issue_tracker_info['status'] = ASSESSMENT_STATUSES_MAPPING.get(
      assessment.status
  )

  if (issue_tracker_info.get('enabled') and
          _is_issue_tracker_enabled(audit=assessment.audit)):
    try:
      issue_id = _create_issuetracker_issue(assessment, issue_tracker_info)
    except integrations_errors.Error as error:
      logger.error(
          'Unable to create a ticket while creating assessment ID=%d: %s',
          assessment.id, error)
      issue_tracker_info = {
          'enabled': False,
      }
      assessment.add_warning('Unable to create a ticket.')
    else:
      issue_url = integration_utils.build_issue_tracker_url(issue_id)
      issue_tracker_info['issue_id'] = issue_id
      issue_tracker_info['issue_url'] = issue_url
  else:
    issue_tracker_info = {
        'enabled': False,
    }

  all_models.IssuetrackerIssue.create_or_update_from_dict(
      assessment, issue_tracker_info)
示例#2
0
def create_ticket_for_new_issue(obj, issue_tracker_info):
  """Create new IssueTracker ticket for issue"""
  builder = issue_tracker_params_builder.IssueParamsBuilder()
  issue_tracker_params = builder.build_create_issue_tracker_params(
      obj,
      issue_tracker_info
  )

  if issue_tracker_params.is_empty():
    return

  # Query to IssueTracker.
  issue_tracker_query = issue_tracker_params.get_issue_tracker_params()

  # Parameters for creation IssuetrackerIssue object in GGRC.
  issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object()

  try:
    res = issues.Client().create_issue(issue_tracker_query)

    issue_url = integration_utils.build_issue_tracker_url(res["issueId"])
    issuetracker_issue_params["issue_url"] = issue_url
    issuetracker_issue_params["issue_id"] = res["issueId"]
  except integrations_errors.Error as error:
    logger.error(
        "Unable to create a ticket while creating object ID=%d: %s",
        obj.id, error
    )
    obj.add_warning("Unable to create a ticket in issue tracker.")
    issuetracker_issue_params["enabled"] = False

  # Create object in GGRC with info about issue tracker integration.
  all_models.IssuetrackerIssue.create_or_update_from_dict(
      obj, issuetracker_issue_params
  )
示例#3
0
def create_ticket_for_new_issue(obj, issue_tracker_info):
    """Create new IssueTracker ticket for issue"""
    builder = issue_tracker_params_builder.IssueParamsBuilder()
    issue_tracker_params = builder.build_create_issue_tracker_params(
        obj, issue_tracker_info)

    if issue_tracker_params.is_empty():
        return

    # Query to IssueTracker.
    issue_tracker_query = issue_tracker_params.get_issue_tracker_params()

    # Parameters for creation IssuetrackerIssue object in GGRC.
    issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object(
    )

    try:
        res = issues.Client().create_issue(issue_tracker_query)

        issue_url = integration_utils.build_issue_tracker_url(res["issueId"])
        issuetracker_issue_params["issue_url"] = issue_url
        issuetracker_issue_params["issue_id"] = res["issueId"]
    except integrations_errors.Error as error:
        logger.error(
            "Unable to create a ticket while creating object ID=%d: %s",
            obj.id, error)
        obj.add_warning("Unable to create a ticket in issue tracker.")
        issuetracker_issue_params["enabled"] = False

    # Create object in GGRC with info about issue tracker integration.
    all_models.IssuetrackerIssue.create_or_update_from_dict(
        obj, issuetracker_issue_params)
示例#4
0
 def _process_result(result, issue_json):
     """Process result of issuetracker synchronization."""
     if result and not issue_json.get("issue_id"):
         issue_json["enabled"] = True
         issue_json["issue_id"] = result.get("issueId")
         issue_json[
             "issue_url"] = integration_utils.build_issue_tracker_url(
                 result.get("issueId"))
     elif not result and not issue_json.get("issue_id"):
         raise integrations_errors.Error("Unknown error")
示例#5
0
def link_issue(obj, ticket_id, issue_tracker_info):
  """Link issue to existing IssueTracker ticket"""

  if _is_already_linked(ticket_id):
    logger.error(
        "Unable to link a ticket while creating object ID=%d: %s ticket ID is "
        "already linked to another GGRC object",
        obj.id,
        ticket_id,
    )
    obj.add_warning(
        "This ticket was already linked to another GGRC issue, assessment "
        "or review object. Linking the same ticket to multiple objects is not "
        "allowed due to potential for conflicting updates."
    )
    return

  builder = issue_tracker_params_builder.IssueParamsBuilder()
  issue_tracker_container = builder.build_params_for_issue_link(
      obj,
      ticket_id,
      issue_tracker_info,
  )

  if issue_tracker_container.is_empty():
    return

  # Query to IssueTracker.
  issue_tracker_query = issue_tracker_container.get_issue_tracker_params()

  # Parameters for creation IssuetrackerIssue object in GGRC.
  issuetracker_issue_params = \
      issue_tracker_container.get_params_for_ggrc_object()

  try:
    issues.Client().update_issue(ticket_id, issue_tracker_query)

    ticket_url = integration_utils.build_issue_tracker_url(ticket_id)
    issuetracker_issue_params["issue_url"] = ticket_url
    issuetracker_issue_params["issue_id"] = ticket_id
    update_initial_issue(obj, issue_tracker_container)
  except integrations_errors.Error as error:
    logger.error("Unable to update a ticket ID=%s while deleting"
                 " issue ID=%d: %s",
                 ticket_id, obj.id, error)
    obj.add_warning("Unable to update a ticket in issue tracker.")
    issuetracker_issue_params["enabled"] = False
    return

  if issuetracker_issue_params:
    all_models.IssuetrackerIssue.create_or_update_from_dict(
        obj, issuetracker_issue_params
    )
示例#6
0
def link_issue(obj, ticket_id, issue_tracker_info):
  """Link issue to existing IssueTracker ticket"""

  if _is_already_linked(ticket_id):
    logger.error(
        "Unable to link a ticket while creating object ID=%d: %s ticket ID is "
        "already linked to another GGRC object",
        obj.id,
        ticket_id,
    )
    obj.add_warning(
        "This ticket was already linked to another GGRC issue, assessment "
        "or review object. Linking the same ticket to multiple objects is not "
        "allowed due to potential for conflicting updates."
    )
    return

  builder = issue_tracker_params_builder.IssueParamsBuilder()
  issue_tracker_container = builder.build_params_for_issue_link(
      obj,
      ticket_id,
      issue_tracker_info,
  )

  if issue_tracker_container.is_empty():
    return

  # Query to IssueTracker.
  issue_tracker_query = issue_tracker_container.get_issue_tracker_params()

  # Parameters for creation IssuetrackerIssue object in GGRC.
  issuetracker_issue_params = \
      issue_tracker_container.get_params_for_ggrc_object()

  try:
    issues.Client().update_issue(ticket_id, issue_tracker_query)

    ticket_url = integration_utils.build_issue_tracker_url(ticket_id)
    issuetracker_issue_params["issue_url"] = ticket_url
    issuetracker_issue_params["issue_id"] = ticket_id
    update_initial_issue(obj, issue_tracker_container)
  except integrations_errors.Error as error:
    logger.error("Unable to update a ticket ID=%s while deleting"
                 " issue ID=%d: %s",
                 ticket_id, obj.id, error)
    obj.add_warning("Unable to update a ticket in issue tracker.")
    issuetracker_issue_params["enabled"] = False
    return

  if issuetracker_issue_params:
    all_models.IssuetrackerIssue.create_or_update_from_dict(
        obj, issuetracker_issue_params
    )
  def _process_result(result, issue_json):
    """Process result of issuetracker synchronization."""
    if result and not issue_json.get("issue_id"):
      issue_json["enabled"] = True
      issue_json["issue_id"] = result.get("issueId")
      issue_json["issue_url"] = integration_utils.build_issue_tracker_url(
          result.get("issueId")
      )
    elif not result and not issue_json.get("issue_id"):
      raise integrations_errors.Error("Unknown error")

    if not issue_json.get("assignee") and result:
      issue_json["assignee"] = result.get("issueState", {}).get("assignee")
    if not issue_json.get("reporter") and result:
      issue_json["reporter"] = result.get("issueState", {}).get("reporter")
def _link_assessment(assessment, issue_tracker_info):
    """Link Assessment to existing IssueTracker ticket"""
    ticket_id = issue_tracker_info['issue_id']
    if integration_utils.is_already_linked(ticket_id):
        logger.error(
            "Unable to link a ticket while creating object ID=%d: %s ticket ID is "
            "already linked to another GGRC object",
            assessment.id,
            ticket_id,
        )
        assessment.add_warning(
            "This ticket was already linked to another GGRC issue, assessment or "
            "review object. Linking the same ticket to multiple objects is not "
            "allowed due to potential for conflicting updates.")
        return

    try:
        response = issues.Client().get_issue(ticket_id)
    except integrations_errors.Error as error:
        logger.error(
            "Unable to link a ticket while creating object ID=%d: %s",
            assessment.id,
            error,
        )
        assessment.add_warning(
            "Ticket tracker ID does not exist or you do not have access to it."
        )
        return

    issue_params = prepare_issue_json(assessment, issue_tracker_info, True)
    issuetracker_ccs = response.get("issueState", {}).get("ccs", [])
    grouped_ccs = group_cc_emails(object_ccs=issue_params.get("ccs", []),
                                  additional_ccs=issuetracker_ccs)
    issue_params["ccs"] = grouped_ccs
    try:
        issues.Client().update_issue(ticket_id, issue_params)
    except integrations_errors.Error as error:
        logger.error(
            'Unable to link a ticket while creating assessment ID=%d: %s',
            assessment.id, error)
        issue_tracker_info['enabled'] = False
        assessment.add_warning('Unable to link a ticket.')
    else:
        issue_url = integration_utils.build_issue_tracker_url(ticket_id)
        issue_tracker_info['issue_url'] = issue_url
        all_models.IssuetrackerIssue.create_or_update_from_dict(
            assessment, issue_tracker_info)
  def test_update_issuetracker_title(self, mocked_update_issue):
    """Test title sync in case it has been updated."""
    with mock.patch.object(
        assessment_integration.AssessmentTrackerHandler,
        '_is_tracker_enabled',
        return_value=True
    ):
      iti_issue_id = []
      iti = factories.IssueTrackerIssueFactory(
          enabled=True,
          component_id='123123',
          issue_severity='S2',
          issue_priority='P2'
      )
      iti_issue_id.append(iti.issue_id)
      asmt = iti.issue_tracked_obj
      new_title = "New Title"
      self.api.put(
          asmt,
          {
              "issue_tracker": {
                  "component_id": iti.component_id,
                  "enabled": True,
                  "issue_priority": iti.issue_priority,
                  "issue_severity": iti.issue_severity,
                  "issue_type": constants.DEFAULT_ISSUETRACKER_VALUES[
                      "issue_type"
                  ],
                  "title": new_title,
                  "issue_id": iti.issue_id,
                  "issue_url": integration_utils.build_issue_tracker_url(
                      iti.issue_id
                  )
              }
          })
      kwargs = {'status': 'ASSIGNED',
                'component_id': int(iti.component_id),
                'severity': iti.issue_severity,
                'title': new_title,
                'hotlist_ids': [],
                'priority': iti.issue_priority}
      mocked_update_issue.assert_called_once_with(iti_issue_id[0], kwargs)

      issue = db.session.query(models.IssuetrackerIssue).get(iti.id)
      self.assertEqual(issue.title, new_title)
示例#10
0
def _create_new_issuetracker_ticket(assessment, issue_tracker_info):
    """Create new IssueTracker ticket for assessment"""
    issue_tracker_request = prepare_issue_json(assessment,
                                               issue_tracker_info,
                                               create_issuetracker=True)
    try:
        res = issues.Client().create_issue(issue_tracker_request)
    except integrations_errors.Error as error:
        logger.error(
            'Unable to create a ticket while creating assessment ID=%d: %s',
            assessment.id, error)
        issue_tracker_info['enabled'] = False
        assessment.add_warning('Unable to create a ticket.')
    else:
        issue_id = res['issueId']
        issue_url = integration_utils.build_issue_tracker_url(issue_id)
        issue_tracker_info['issue_id'] = issue_id
        issue_tracker_info['issue_url'] = issue_url
示例#11
0
def create_issue_handler(obj, issue_tracker_info):
  """Event handler for issue object creation."""
  if not issue_tracker_info or not issue_tracker_info.get("enabled"):
    return

  # We need in flush here because we need object id for URL generation.
  db.session.flush()

  builder = issue_tracker_params_builder.IssueParamsBuilder()
  issue_tracker_params = builder.build_create_issue_tracker_params(
      obj,
      issue_tracker_info
  )

  if issue_tracker_params.is_empty():
    return

  # Query to IssueTracker.
  issue_tracker_query = issue_tracker_params.get_issue_tracker_params()

  # Parameters for creation IssuetrackerIssue object in GGRC.
  issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object()

  try:
    res = issues.Client().create_issue(issue_tracker_query)

    issue_url = integration_utils.build_issue_tracker_url(res["issueId"])
    issuetracker_issue_params["issue_url"] = issue_url
    issuetracker_issue_params["issue_id"] = res["issueId"]
  except integrations_errors.Error as error:
    logger.error(
        "Unable to create a ticket while creating object ID=%d: %s",
        obj.id, error
    )
    obj.add_warning("Unable to create a ticket in issue tracker.")
    issuetracker_issue_params["enabled"] = False

  # Create object in GGRC with info about issue tracker integration.
  all_models.IssuetrackerIssue.create_or_update_from_dict(
      obj, issuetracker_issue_params
  )
 def test_issue_tracker_error(self, issue_tracker_enabled, issue_id,
                              issue_enabled):
   """Test that issue tracker does not change state
   in case receiving an error."""
   del issue_enabled  # Unused
   with mock.patch.object(
       sync_utils,
       'update_issue'
   ) as update_issue_mock:
     error_data = integrations_errors.Error('data')
     update_issue_mock.side_effect = error_data
     issue = factories.IssueTrackerIssueFactory(
         enabled=issue_tracker_enabled,
         issue_id=issue_id
     )
     src = {
         'issue_tracker': {
             'enabled': issue_tracker_enabled,
             'issue_id': issue_id,
             'issue_url': integration_utils.build_issue_tracker_url(
                 issue_id
             ),
             'component_id': '1111',
             'issue_type': 'PROCESS',
             'issue_priority': 'P2',
             'issue_severity': 'S2',
             'title': 'Title'
         }
     }
     assessment_integration._hook_assmt_issue_update(
         sender=None,
         obj=issue.issue_tracked_obj,
         src=src,
         initial_state=issue.issue_tracked_obj
     )
     update_issue_mock.assert_called_once()
     issue_obj = models.IssuetrackerIssue.get_issue(
         "Assessment",
         issue.issue_tracked_obj.id
     )
     self.assertEqual(issue_obj.enabled, issue_tracker_enabled)
示例#13
0
def create_issue_handler(obj, issue_tracker_info):
    """Event handler for issue object creation."""
    if not issue_tracker_info or not issue_tracker_info.get("enabled"):
        return

    # We need in flush here because we need object id for URL generation.
    db.session.flush()

    builder = issue_tracker_params_builder.IssueParamsBuilder()
    issue_tracker_params = builder.build_create_issue_tracker_params(
        obj, issue_tracker_info)

    if issue_tracker_params.is_empty():
        return

    # Query to IssueTracker.
    issue_tracker_query = issue_tracker_params.get_issue_tracker_params()

    # Parameters for creation IssuetrackerIssue object in GGRC.
    issuetracker_issue_params = issue_tracker_params.get_params_for_ggrc_object(
    )

    try:
        res = issues.Client().create_issue(issue_tracker_query)

        issue_url = integration_utils.build_issue_tracker_url(res["issueId"])
        issuetracker_issue_params["issue_url"] = issue_url
        issuetracker_issue_params["issue_id"] = res["issueId"]
    except integrations_errors.Error as error:
        logger.error(
            "Unable to create a ticket while creating object ID=%d: %s",
            obj.id, error)
        obj.add_warning("Unable to create a ticket in issue tracker.")
        issuetracker_issue_params["enabled"] = False

    # Create object in GGRC with info about issue tracker integration.
    all_models.IssuetrackerIssue.create_or_update_from_dict(
        obj, issuetracker_issue_params)
  def test_update_issuetracker_info(self):
    """Test that Issue Tracker issues are updated by the utility."""
    cli_patch = mock.patch.object(sync_utils.issues, 'Client')
    hook_patch = mock.patch.object(
        assessment_integration.AssessmentTrackerHandler,
        '_is_tracker_enabled',
        return_value=True
    )
    with cli_patch, hook_patch:
      iti_issue_id = []
      for _ in xrange(2):
        iti = factories.IssueTrackerIssueFactory()
        iti_issue_id.append(iti.issue_id)
        asmt = iti.issue_tracked_obj
        asmt_id = asmt.id
        audit = asmt.audit
        self.api.modify_object(audit, {
            'issue_tracker': {
                'enabled': True,
                'component_id': '11111',
                'hotlist_id': '222222',
            },
        })
        asmt = db.session.query(models.Assessment).get(asmt_id)
        self.api.modify_object(asmt, {
            'issue_tracker': {
                'enabled': True,
                'component_id': '11111',
                'hotlist_id': '222222',
                'issue_type': 'PROCESS',
                'issue_priority': 'P2',
                'issue_severity': 'S2',
                'title': 'Default Title',
                'issue_id': iti.issue_id,
                'issue_url': integration_utils.build_issue_tracker_url(
                    iti.issue_id
                )
            },
        })
        asmt = db.session.query(models.Assessment).get(asmt_id)
        self.api.modify_object(asmt, {
            'issue_tracker': {
                'enabled': True,
                'component_id': '11111',
                'hotlist_id': '222222',
                'issue_priority': 'P4',
                'issue_type': 'PROCESS',
                'issue_severity': 'S3',
                'title': 'Default Title',
                'issue_id': iti.issue_id,
                'issue_url': integration_utils.build_issue_tracker_url(
                    iti.issue_id
                )
            },
        })
      self.api.delete(asmt)

    cli_mock = mock.MagicMock()
    cli_mock.update_issue.return_value = None
    cli_mock.search.return_value = {
        'issues': [
            {
                'issueId': iti_issue_id[0],
                'issueState': {
                    'status': 'FIXED', 'type': 'bug2',
                    'priority': 'P2', 'severity': 'S2',
                },
            },
        ],
        'next_page_token': None,
    }

    with mock.patch.object(sync_utils.issues, 'Client', return_value=cli_mock):
      synchronization_jobs.sync_assessment_attributes()
      cli_mock.update_issue.assert_called_once_with(
          iti_issue_id[0], {
              'status': 'ASSIGNED',
              'priority': u'P4',
              'type': constants.DEFAULT_ISSUETRACKER_VALUES['issue_type'],
              'severity': u'S3',
              'assignee': '',
              'verifier': '',
              'reporter': '',
              'ccs': [],
              'component_id': 11111
          })
 def test_update_ccs_many_audit_captains(self, mock_update_issue):
   """CCS shouldn't be calculated on update, only synchronization"""
   del mock_update_issue  # Unused
   with mock.patch.object(
       assessment_integration.AssessmentTrackerHandler,
       '_is_tracker_enabled',
       return_value=True
   ):
     audit = factories.AuditFactory()
     audit_captains = factories.PersonFactory.create_batch(2)
     audit_captain_role = all_models.AccessControlRole.query.filter_by(
         name="Audit Captains",
         object_type="Audit"
     ).one()
     self.api.put(
         audit,
         {
             "access_control_list": [
                 {
                     "ac_role_id": audit_captain_role.id,
                     "person": {
                         "id": audit_captain.id,
                         "type": "Person"
                     }
                 } for audit_captain in audit_captains]
         }
     )
     assessment = factories.AssessmentFactory(
         audit=audit
     )
     assessment_issue = factories.IssueTrackerIssueFactory(
         enabled=True,
         issue_tracked_obj=assessment,
         component_id="11111",
         hotlist_id="222222",
     )
     assessment_persons = factories.PersonFactory.create_batch(3)
     assignee_role = all_models.AccessControlRole.query.filter_by(
         name="Assignees",
         object_type="Assessment"
     ).one()
     creator_role = all_models.AccessControlRole.query.filter_by(
         name="Creators",
         object_type="Assessment"
     ).one()
     response_assessment = self.api.put(
         assessment,
         {
             "issue_tracker": {
                 "component_id": "11111",
                 "enabled": True,
                 "hotlist_id": "222222",
                 "issue_priority": "P2",
                 "issue_severity": "S2",
                 "title": "Assessment Title",
                 "issue_type": "PROCESS",
                 "issue_id": assessment_issue.issue_id,
                 "issue_url": integration_utils.build_issue_tracker_url(
                     assessment_issue.issue_id
                 )
             },
             "access_control_list": [
                 {
                     "ac_role_id": creator_role.id
                     if not index else assignee_role.id,
                     "id": index + 1,
                     "person": {
                         "context_id": None,
                         "href": "/api/people/{}".format(
                             person.id
                         ),
                         "id": person.id,
                         "type": "Person"
                     },
                     "person_email": person.email,
                     "person_id": person.id,
                     "person_name": person.name,
                     "type": "AccessControlList"
                 }
                 for index, person in enumerate(assessment_persons)]
         }
     )
     self.assert200(response_assessment)
     issue_tracker_assessment = all_models.IssuetrackerIssue.query.filter_by(
         object_id=assessment.id,
         object_type=assessment.type
     ).one()
     issue_tracker_cc = issue_tracker_assessment.cc_list.split(',')[0]
     self.assertIn(issue_tracker_cc, "")