Ejemplo n.º 1
0
  def _flush(self, parent_relationship):
    """Manually INSERT generated automappings."""
    if not self.auto_mappings:
      return
    with benchmark("Automapping flush"):
      current_user_id = login.get_current_user_id()
      automapping_result = db.session.execute(
          Automapping.__table__.insert().values(
              relationship_id=parent_relationship.id,
              source_id=parent_relationship.source_id,
              source_type=parent_relationship.source_type,
              destination_id=parent_relationship.destination_id,
              destination_type=parent_relationship.destination_type,
              modified_by_id=current_user_id,
          )
      )
      automapping_id = automapping_result.inserted_primary_key[0]
      self.automapping_ids.add(automapping_id)
      now = datetime.utcnow()
      # We are doing an INSERT IGNORE INTO here to mitigate a race condition
      # that happens when multiple simultaneous requests create the same
      # automapping. If a relationship object fails our unique constraint
      # it means that the mapping was already created by another request
      # and we can safely ignore it.
      inserter = Relationship.__table__.insert().prefix_with("IGNORE")
      original = self.order(Stub.from_source(parent_relationship),
                            Stub.from_destination(parent_relationship))
      db.session.execute(inserter.values([{
          "id": None,
          "modified_by_id": current_user_id,
          "created_at": now,
          "updated_at": now,
          "source_id": src.id,
          "source_type": src.type,
          "destination_id": dst.id,
          "destination_type": dst.type,
          "context_id": None,
          "status": None,
          "parent_id": parent_relationship.id,
          "automapping_id": automapping_id,
          "is_external": False}
          for src, dst in self.auto_mappings
          if (src, dst) != original]))  # (src, dst) is sorted

      self._set_audit_id_for_issues(automapping_id)

      cache = Cache.get_cache(create=True)
      if cache:
        # Add inserted relationships into new objects collection of the cache,
        # so that they will be logged within event and appropriate revisions
        # will be created.
        cache.new.update(
            (relationship, relationship.log_json())
            for relationship in Relationship.query.filter_by(
                automapping_id=automapping_id,
            )
        )
Ejemplo n.º 2
0
  def _flush(self, parent_relationship):
    """Manually INSERT generated automappings."""
    if not self.auto_mappings:
      return
    with benchmark("Automapping flush"):
      current_user_id = login.get_current_user_id()
      automapping_result = db.session.execute(
          Automapping.__table__.insert().values(
              relationship_id=parent_relationship.id,
              source_id=parent_relationship.source_id,
              source_type=parent_relationship.source_type,
              destination_id=parent_relationship.destination_id,
              destination_type=parent_relationship.destination_type,
          )
      )
      automapping_id = automapping_result.inserted_primary_key[0]
      self.automapping_ids.add(automapping_id)
      now = datetime.utcnow()
      # We are doing an INSERT IGNORE INTO here to mitigate a race condition
      # that happens when multiple simultaneous requests create the same
      # automapping. If a relationship object fails our unique constraint
      # it means that the mapping was already created by another request
      # and we can safely ignore it.
      inserter = Relationship.__table__.insert().prefix_with("IGNORE")
      original = self.order(Stub.from_source(parent_relationship),
                            Stub.from_destination(parent_relationship))
      db.session.execute(inserter.values([{
          "id": None,
          "modified_by_id": current_user_id,
          "created_at": now,
          "updated_at": now,
          "source_id": src.id,
          "source_type": src.type,
          "destination_id": dst.id,
          "destination_type": dst.type,
          "context_id": None,
          "status": None,
          "parent_id": parent_relationship.id,
          "automapping_id": automapping_id,
          "is_external": False}
          for src, dst in self.auto_mappings
          if (src, dst) != original]))  # (src, dst) is sorted

      self._set_audit_id_for_issues(automapping_id)

      cache = Cache.get_cache(create=True)
      if cache:
        # Add inserted relationships into new objects collection of the cache,
        # so that they will be logged within event and appropriate revisions
        # will be created.
        cache.new.update(
            (relationship, relationship.log_json())
            for relationship in Relationship.query.filter_by(
                automapping_id=automapping_id,
            )
        )
Ejemplo n.º 3
0
    def generate_automappings(self, relationship):
        """Generate Automappings for a given relationship"""
        # pylint: disable=protected-access
        self.auto_mappings = set()
        with benchmark("Automapping generate_automappings"):
            # initial relationship is special since it is already created and
            # processing it would abort the loop so we manually enqueue the
            # neighborhood
            src = Stub.from_source(relationship)
            dst = Stub.from_destination(relationship)
            self._step(src, dst)
            self._step(dst, src)
            while self.queue:
                if len(self.auto_mappings) > self.COUNT_LIMIT:
                    break
                src, dst = entry = self.queue.pop()

                if {src.type, dst.type} != {"Audit", "Issue"}:
                    # Auditor doesn't have edit (+map) permission on the Audit,
                    # but the Auditor should be allowed to Raise an Issue.
                    # Since Issue-Assessment-Audit is the only rule that
                    # triggers Issue to Audit mapping, we should skip the
                    # permission check for it
                    if not (permissions.is_allowed_update(
                            src.type, src.id, None)
                            and permissions.is_allowed_update(
                                dst.type, dst.id, None)):
                        continue

                created = self._ensure_relationship(src, dst)
                self.processed.add(entry)
                if not created:
                    # If the edge already exists it means that auto mappings for it have
                    # already been processed and it is safe to cut here.
                    continue
                self._step(src, dst)
                self._step(dst, src)

            if len(self.auto_mappings) <= self.COUNT_LIMIT:
                self._flush(relationship)
            else:
                relationship._json_extras = {  # pylint: disable=protected-access
                    'automapping_limit_exceeded': True
                }
Ejemplo n.º 4
0
    def generate_automappings(self, relationship):
        """Generate Automappings for a given relationship"""
        self.auto_mappings = set()

        # initial relationship is special since it is already created and
        # processing it would abort the loop so we manually enqueue the
        # neighborhood
        src = Stub.from_source(relationship)
        dst = Stub.from_destination(relationship)
        self._step(src, dst)
        self._step(dst, src)
        while self.queue:
            if len(self.auto_mappings) > self.COUNT_LIMIT:
                break
            src, dst = entry = self.queue.pop()

            if {src.type, dst.type} not in self._AUTOMAP_WITHOUT_PERMISSION:
                # Mapping between some objects should be created even if there is no
                # permission to edit (+map) this objects. Thus permissions check for
                # them should be skipped.
                if not (permissions.is_allowed_update(src.type, src.id, None)
                        and permissions.is_allowed_update(
                            dst.type, dst.id, None)):
                    continue

            created = self._ensure_relationship(src, dst)
            self.processed.add(entry)
            if not created:
                # If the edge already exists it means that auto mappings for it have
                # already been processed and it is safe to cut here.
                continue
            self._step(src, dst)
            self._step(dst, src)

        if len(self.auto_mappings) <= self.COUNT_LIMIT:
            if self.auto_mappings:
                logger.info("Automapping count: count=%s",
                            len(self.auto_mappings))
            self._flush(relationship)
        else:
            logger.error("Automapping limit exceeded: limit=%s, count=%s",
                         self.COUNT_LIMIT, len(self.auto_mappings))
Ejemplo n.º 5
0
  def generate_automappings(self, relationship):
    """Generate Automappings for a given relationship"""
    # pylint: disable=protected-access
    self.auto_mappings = set()
    with benchmark("Automapping generate_automappings"):
      # initial relationship is special since it is already created and
      # processing it would abort the loop so we manually enqueue the
      # neighborhood
      src = Stub.from_source(relationship)
      dst = Stub.from_destination(relationship)
      self._step(src, dst)
      self._step(dst, src)
      while self.queue:
        if len(self.auto_mappings) > self.COUNT_LIMIT:
          break
        src, dst = entry = self.queue.pop()

        if {src.type, dst.type} != {"Audit", "Issue"}:
          # Auditor doesn't have edit (+map) permission on the Audit,
          # but the Auditor should be allowed to Raise an Issue.
          # Since Issue-Assessment-Audit is the only rule that
          # triggers Issue to Audit mapping, we should skip the
          # permission check for it
          if not (permissions.is_allowed_update(src.type, src.id, None) and
                  permissions.is_allowed_update(dst.type, dst.id, None)):
            continue

        created = self._ensure_relationship(src, dst)
        self.processed.add(entry)
        if not created:
          # If the edge already exists it means that auto mappings for it have
          # already been processed and it is safe to cut here.
          continue
        self._step(src, dst)
        self._step(dst, src)

      if len(self.auto_mappings) <= self.COUNT_LIMIT:
        self._flush(relationship)
      else:
        logger.error("Automapping limit exceeded: limit=%s, count=%s",
                     self.COUNT_LIMIT, len(self.auto_mappings))