示例#1
0
 async def _parse_source_responses(self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the issues."""
     value = 0
     entities = Entities()
     for response in responses:
         json = await response.json()
         value += int(json.get("total", 0))
         entities.extend([await self._entity(issue) for issue in json.get("issues", [])])
     return SourceMeasurement(value=str(value), entities=entities)
示例#2
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the cards."""
     api_url = await self._api_url()
     board_slug = self._board["slug"]
     entities = Entities()
     for lst in self._lists:
         for card in self._cards.get(lst["_id"], []):
             entities.append(
                 self.__card_to_entity(card, api_url, board_slug,
                                       lst["title"]))
     return entities
示例#3
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the dependencies from the XML."""
     landing_url = await self._landing_url(responses)
     entities = Entities()
     for response in responses:
         tree, namespaces = await parse_source_response_xml_with_namespace(
             response, self.allowed_root_tags)
         entities.extend([
             self._parse_entity(dependency, index, namespaces, landing_url)
             for (index, dependency
                  ) in enumerate(self._dependencies(tree, namespaces))
         ])
     return entities
示例#4
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the jobs/pipelines."""
     entities = Entities()
     for job in (await responses[0].json())["value"]:
         if not self._include_job(job):
             continue
         name = self.__job_name(job)
         url = job["_links"]["web"]["href"]
         build_status = self._latest_build_result(job)
         build_date_time = self._latest_build_date_time(job)
         entities.append(
             Entity(key=name, name=name, url=url, build_date=str(build_date_time.date()), build_status=build_status)
         )
     return entities
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the security warnings from the JSON."""
     entities = Entities()
     for response in responses:
         entities.extend([
             Entity(
                 key=warning[self.KEY],
                 package=warning[self.PACKAGE],
                 installed=warning[self.INSTALLED],
                 affected=warning[self.AFFECTED],
                 vulnerability=warning[self.VULNERABILITY],
             ) for warning in await response.json(content_type=None)
         ])
     return entities
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the Anchore security warnings."""
     severities = self._parameter("severities")
     entities = Entities()
     for response in responses:
         json = await response.json(content_type=None)
         vulnerabilities = json.get("vulnerabilities", []) if isinstance(json, dict) else []
         entities.extend(
             [
                 self._create_entity(vulnerability, response.filename)
                 for vulnerability in vulnerabilities
                 if vulnerability["severity"] in severities
             ]
         )
     return entities
示例#7
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the violations."""
     entity_attributes = []
     for response in responses:
         json = await response.json(content_type=None)
         url = json["url"]
         for violation in json.get("violations", []):
             for node in violation.get("nodes", []):
                 tags = violation.get("tags", [])
                 impact = node.get("impact")
                 if self.__include_violation(impact, tags):
                     entity_attributes.append(
                         dict(
                             description=violation.get("description"),
                             element=node.get("html"),
                             help=violation.get("helpUrl"),
                             impact=impact,
                             page=url,
                             url=url,
                             tags=", ".join(sorted(tags)),
                             violation_type=violation.get("id"),
                         ))
     return Entities(
         Entity(key=self.__create_key(attributes), **attributes)
         for attributes in entity_attributes)
class SnykSecurityWarnings(JSONFileSourceCollector):
    """Snyk collector for security warnings."""

    async def _parse_entities(self, responses: SourceResponses) -> Entities:
        """Parse the direct dependencies with vulnerabilities from the responses."""
        selected_severities = self._parameter("severities")
        severities: dict[str, set[Severity]] = {}
        nr_vulnerabilities: dict[str, int] = {}
        example_vulnerability = {}
        for response in responses:
            json = await response.json(content_type=None)
            vulnerabilities = json.get("vulnerabilities", [])
            for vulnerability in vulnerabilities:
                if (severity := vulnerability["severity"]) not in selected_severities:
                    continue
                dependency = vulnerability["from"][1] if len(vulnerability["from"]) > 1 else vulnerability["from"][0]
                severities.setdefault(dependency, set()).add(severity)
                nr_vulnerabilities[dependency] = nr_vulnerabilities.get(dependency, 0) + 1
                path = " ➜ ".join(str(dependency) for dependency in vulnerability["from"])
                example_vulnerability[dependency] = (vulnerability["id"], path)

        entities = Entities()
        for dependency in severities:
            entities.append(
                Entity(
                    key=dependency,
                    dependency=dependency,
                    nr_vulnerabilities=nr_vulnerabilities[dependency],
                    example_vulnerability=example_vulnerability[dependency][0],
                    url=f"https://snyk.io/vuln/{example_vulnerability[dependency][0]}",
                    example_path=example_vulnerability[dependency][1],
                    highest_severity=self.__highest_severity(severities[dependency]),
                )
            )
        return entities
示例#9
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the sprint values from the responses."""
     api_url = await self._api_url()
     board_id = parse_qs(urlparse(str(
         responses.api_url)).query)["rapidViewId"][0]
     entity_url = URL(
         f"{api_url}/secure/RapidBoard.jspa?rapidView={board_id}&view=reporting&chart=sprintRetrospective&sprint="
     )
     json = await responses[0].json()
     # The JSON contains a list with sprints and a dict with the committed and completed points, indexed by sprint id
     sprints, points = json["sprints"], json["velocityStatEntries"]
     velocity_type = str(self._parameter("velocity_type"))
     nr_sprints = int(str(self._parameter("velocity_sprints")))
     # Get the points, either completed, committed, or completed minus committed, as determined by the velocity type
     sprint_values = [
         self.__velocity(points[str(sprint["id"])], velocity_type)
         for sprint in sprints[:nr_sprints]
     ]
     entities = Entities(
         self.__entity(sprint, points[str(sprint["id"])], velocity_type,
                       entity_url) for sprint in sprints)
     return SourceMeasurement(
         value=str(round(sum(sprint_values) /
                         len(sprint_values))) if sprint_values else "0",
         entities=entities)
示例#10
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the violations from the OJAudit XML."""
     severities = cast(list[str], self._parameter("severities"))
     count = 0
     entities = Entities()
     for response in responses:
         tree, namespaces = await parse_source_response_xml_with_namespace(
             response)
         entities.extend(self.__violations(tree, namespaces, severities))
         for severity in severities:
             count += int(
                 tree.findtext(f"./ns:{severity}-count",
                               default="0",
                               namespaces=namespaces))
     return SourceMeasurement(value=str(count), entities=entities)
示例#11
0
 def __violations(self, tree: Element, namespaces: Namespaces,
                  severities: list[str]) -> Entities:
     """Return the violations."""
     models = self.__model_file_paths(tree, namespaces)
     violation_elements = tree.findall(".//ns:violation", namespaces)
     violations = Entities()
     for element in violation_elements:
         violation = self.__violation(element, namespaces, models,
                                      severities)
         if violation is not None:
             violations.append(violation)
     # Add the duplication counts
     for violation in violations:
         violation["count"] = str(self.violation_counts[str(
             violation["key"])])
     return violations
示例#12
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the security warnings from the OpenVAS XML."""
     entities = Entities()
     severities = cast(list[str], self._parameter("severities"))
     for response in responses:
         tree = await parse_source_response_xml(response)
         entities.extend([
             Entity(
                 key=result.attrib["id"],
                 name=result.findtext("name", default=""),
                 description=result.findtext("description", default=""),
                 host=result.findtext("host", default=""),
                 port=result.findtext("port", default=""),
                 severity=result.findtext("threat", default=""),
             ) for result in self.__results(tree, severities)
         ])
     return entities
示例#13
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the merge requests."""
     merge_requests = []
     for response in responses:
         merge_requests.extend(await response.json())
     return Entities(
         self._create_entity(mr) for mr in merge_requests
         if self._include_merge_request(mr))
示例#14
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the issues from the JSON."""
     json = await responses[0].json()
     cards = json["cards"]
     lists = {lst["id"]: lst["name"] for lst in json["lists"]}
     return Entities(
         self.__card_to_entity(card, lists) for card in cards
         if not self.__ignore_card(card, lists))
示例#15
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the security warnings from the JSON."""
     entities = Entities()
     for response in responses:
         json = await response.json(content_type=None)
         vulnerabilities = json.get("vulnerabilities", [])
         for vulnerability in vulnerabilities:
             key = md5_hash(
                 f'{vulnerability["title"]}:{vulnerability["description"]}')
             entities.append(
                 Entity(
                     key=key,
                     title=vulnerability["title"],
                     description=vulnerability["description"],
                     severity=vulnerability["severity"],
                 ))
     return entities
示例#16
0
 async def _entities(self, metrics: dict[str, str]) -> Entities:
     """Override to return the effort entities."""
     entities = Entities()
     api_values = self._data_model["sources"][
         self.source_type]["parameters"]["effort_types"]["api_values"]
     for effort_type in self.__effort_types():
         effort_type_description = [
             param for param, api_key in api_values.items()
             if effort_type == api_key
         ][0]
         entities.append(
             Entity(
                 key=effort_type,
                 effort_type=effort_type_description,
                 effort=metrics[effort_type],
                 url=await self.__effort_type_landing_url(effort_type),
             ))
     return entities
示例#17
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the merge requests from the responses."""
     merge_requests = []
     for response in responses:
         merge_requests.extend((await response.json())["value"])
     landing_url = (await self._landing_url(responses)).rstrip("s")
     return Entities(
         self._create_entity(mr, landing_url) for mr in merge_requests
         if self._include_merge_request(mr))
示例#18
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to get the unmerged branches from the unmerged branches method that subclasses should implement."""
     return Entities(
         Entity(
             key=branch["name"],
             name=branch["name"],
             commit_date=str(self._commit_datetime(branch).date()),
             url=str(self._branch_landing_url(branch)),
         ) for branch in await self._unmerged_branches(responses))
示例#19
0
 async def _parse_source_responses(self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the tests from the Robot Framework XML."""
     count = 0
     total = 0
     entities = Entities()
     test_results = cast(list[str], self._parameter("test_result"))
     all_test_results = self._data_model["sources"][self.source_type]["parameters"]["test_result"]["values"]
     for response in responses:
         tree = await parse_source_response_xml(response)
         stats = tree.findall("statistics/total/stat")[1]
         for test_result in all_test_results:
             total += int(stats.get(test_result, 0))
             if test_result in test_results:
                 count += int(stats.get(test_result, 0))
                 for test in tree.findall(f".//test/status[@status='{test_result.upper()}']/.."):
                     entities.append(
                         Entity(key=test.get("id", ""), name=test.get("name", ""), test_result=test_result)
                     )
     return SourceMeasurement(value=str(count), total=str(total), entities=entities)
示例#20
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Override to get the issues from the responses."""
     url = URL(str(self._parameter("url")))
     json = await responses[0].json()
     entities = Entities(
         self._create_entity(issue, url)
         for issue in json.get("issues", []) if self._include_issue(issue))
     return SourceMeasurement(value=self._compute_value(entities),
                              entities=entities)
示例#21
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the work items from the WIQL query response."""
     return Entities(
         Entity(
             key=work_item["id"],
             project=work_item["fields"]["System.TeamProject"],
             title=work_item["fields"]["System.Title"],
             work_item_type=work_item["fields"]["System.WorkItemType"],
             state=work_item["fields"]["System.State"],
             url=work_item["url"],
         ) for work_item in await self._work_items(responses))
示例#22
0
 async def _entities(self, metrics: dict[str, str]) -> Entities:
     """Extend to return ncloc per language, if the users picked ncloc to measure."""
     if self._value_key() == "ncloc":
         # Our user picked non-commented lines of code (ncloc), so we can show the ncloc per language, skipping
         # languages the user wants to ignore
         return Entities(
             Entity(key=language,
                    language=self.LANGUAGES.get(language, language),
                    ncloc=ncloc)
             for language, ncloc in self.__language_ncloc(metrics))
     return await super()._entities(metrics)
示例#23
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the jobs."""
     return Entities([
         Entity(
             key=job["name"],
             name=job["name"],
             url=job["url"],
             build_status=self._build_status(job),
             build_date=str(self._build_datetime(job).date())
             if self._build_datetime(job) > datetime.min else "",
         ) for job in self.__jobs((await responses[0].json())["jobs"])
     ])
示例#24
0
 def __init__(self,
              *,
              value: Value = None,
              total: Value = "100",
              entities: Entities = None,
              parse_error: ErrorMessage = None) -> None:
     self.value = str(
         len(entities)) if value is None and entities is not None else value
     self.total = total
     self.entities = entities[:self.MAX_ENTITIES] if entities else Entities(
     )
     self.parse_error = parse_error
示例#25
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the security warnings."""
     severities = self._parameter("severities")
     confidence_levels = self._parameter("confidence_levels")
     entities = Entities()
     for response in responses:
         entities.extend([
             Entity(
                 key=
                 f'{warning["test_id"]}:{warning["filename"]}:{warning["line_number"]}',
                 location=f'{warning["filename"]}:{warning["line_number"]}',
                 issue_text=warning["issue_text"],
                 issue_severity=warning["issue_severity"].capitalize(),
                 issue_confidence=warning["issue_confidence"].capitalize(),
                 more_info=warning["more_info"],
             ) for warning in (await response.json(
                 content_type=None)).get("results", [])
             if warning["issue_severity"].lower() in severities
             and warning["issue_confidence"].lower() in confidence_levels
         ])
     return entities
示例#26
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the LOC from the JSON responses."""
     loc = 0
     entities = Entities()
     languages_to_ignore = self._parameter("languages_to_ignore")
     for response in responses:
         for key, value in (await response.json(content_type=None)).items():
             if key not in ("header", "SUM"
                            ) and not match_string_or_regular_expression(
                                key, languages_to_ignore):
                 loc += value["code"]
                 entities.append(
                     Entity(
                         key=key,
                         language=key,
                         blank=str(value["blank"]),
                         comment=str(value["comment"]),
                         code=str(value["code"]),
                         nr_files=str(value["nFiles"]),
                     ))
     return SourceMeasurement(value=str(loc), entities=entities)
示例#27
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the dependencies from the JSON."""
     installed_dependencies: list[dict[str, str]] = []
     for response in responses:
         installed_dependencies.extend(await response.json(content_type=None))
     return Entities(
         Entity(
             key=f'{dependency["name"]}@{dependency.get("version", "?")}',
             name=dependency["name"],
             version=dependency.get("version", "unknown"),
             latest=dependency.get("latest_version", "unknown"),
         )
         for dependency in installed_dependencies
     )
示例#28
0
 async def _parse_entities(self, responses: SourceResponses) -> Entities:
     """Override to parse the dependencies from the JSOM."""
     installed_dependencies: dict[str, dict[str, str]] = {}
     for response in responses:
         installed_dependencies.update(await
                                       response.json(content_type=None))
     return Entities(
         Entity(
             key=f'{dependency}@{versions.get("current", "?")}',
             name=dependency,
             current=versions.get("current", "unknown"),
             wanted=versions.get("wanted", "unknown"),
             latest=versions.get("latest", "unknown"),
         ) for dependency, versions in installed_dependencies.items())
示例#29
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Override to parse the tests from the JUnit XML."""
     entities = Entities()
     test_statuses_to_count = cast(list[str],
                                   self._parameter("test_result"))
     junit_status_nodes = dict(errored="error",
                               failed="failure",
                               skipped="skipped")
     total = 0
     for response in responses:
         tree = await parse_source_response_xml(response)
         for test_case in tree.findall(".//testcase"):
             for test_result, junit_status_node in junit_status_nodes.items(
             ):
                 if test_case.find(junit_status_node) is not None:
                     break
             else:
                 test_result = "passed"
             if test_result in test_statuses_to_count:
                 entities.append(self.__entity(test_case, test_result))
             total += 1
     return SourceMeasurement(entities=entities, total=str(total))
示例#30
0
 async def _parse_source_responses(
         self, responses: SourceResponses) -> SourceMeasurement:
     """Get the metric entities from the responses."""
     status_to_count = self._parameter("status")
     landing_url = await self._landing_url(responses)
     metrics_and_entities = await self.__get_metrics_and_entities(
         responses[0])
     entities = Entities()
     for metric, entity in metrics_and_entities:
         recent_measurements: Measurements = cast(
             Measurements, metric.get("recent_measurements", []))
         status, value = self.__get_status_and_value(
             metric, recent_measurements[-1] if recent_measurements else {})
         if status in status_to_count:
             entity[
                 "report_url"] = report_url = f"{landing_url}/{metric['report_uuid']}"
             entity[
                 "subject_url"] = f"{report_url}#{metric['subject_uuid']}"
             entity["metric_url"] = f"{report_url}#{entity['key']}"
             entity["metric"] = str(
                 metric.get("name")
                 or self._data_model["metrics"][metric["type"]]["name"])
             entity["status"] = status
             unit = metric.get("unit") or self._data_model["metrics"][
                 metric["type"]]["unit"]
             entity["measurement"] = f"{value or '?'} {unit}"
             direction = str(
                 metric.get("direction") or
                 self._data_model["metrics"][metric["type"]]["direction"])
             direction = {"<": "≦", ">": "≧"}.get(direction, direction)
             target = metric.get("target") or self._data_model["metrics"][
                 metric["type"]]["target"]
             entity["target"] = f"{direction} {target} {unit}"
             entities.append(entity)
     return SourceMeasurement(total=str(len(metrics_and_entities)),
                              entities=entities)