Skip to content

Commit

Permalink
chore: test for import_observations (#722)
Browse files Browse the repository at this point in the history
* chore: test for import_observations

* chore: check references and evidences

* chore black

* chore: don't copy files

* chore: add epss mock
  • Loading branch information
StefanFl authored Nov 1, 2023
1 parent 00d33f8 commit a215967
Show file tree
Hide file tree
Showing 8 changed files with 590 additions and 22 deletions.
2 changes: 1 addition & 1 deletion backend/application/core/queries/observation.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def get_observations_for_vulnerability_check(
filename: str,
api_configuration_name: str,
) -> QuerySet[Observation]:
return get_observations().filter(
return Observation.objects.filter(
product=product,
branch=branch,
upload_filename=filename,
Expand Down
45 changes: 25 additions & 20 deletions backend/application/import_observations/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,38 @@ def register_module(self, module_name):
from application.commons.services.log_message import ( # pylint: disable=import-outside-toplevel
format_log_message,
)
from application.import_observations.parsers.base_parser import ( # pylint: disable=import-outside-toplevel
BaseParser,
)
from application.import_observations.services.parser_registry import ( # noqa E501 pylint: disable=import-outside-toplevel
register_parser,
)

try:
# Check if it is a Python module
if find_spec(
f"application.import_observations.parsers.{module_name}.parser"
):
# Import the module and register the classname
module = import_module( # nosemgrep
f"application.import_observations.parsers.{module_name}.parser"
)
# nosemgrep because of rule python.lang.security.audit.non-literal-import.non-literal-import
# This is the price you pay for a dynamic parser registry. We accept the risk.
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if (
isclass(attribute)
and issubclass(attribute, BaseParser)
and attribute is not BaseParser
):
register_parser(attribute)
_register_parser(module_name)
except Exception:
logger.exception( # noqa: F401 pylint: disable=import-outside-toplevel,unused-import
format_log_message(message=f"Failed to load {module_name}")
)


def _register_parser(module_name):
from application.import_observations.parsers.base_parser import ( # pylint: disable=import-outside-toplevel
BaseParser,
)
from application.import_observations.services.parser_registry import ( # noqa E501 pylint: disable=import-outside-toplevel
register_parser,
)

# Import the module and register the classname
module = import_module( # nosemgrep
f"application.import_observations.parsers.{module_name}.parser"
)
# nosemgrep because of rule python.lang.security.audit.non-literal-import.non-literal-import
# This is the price you pay for a dynamic parser registry. We accept the risk.
for attribute_name in dir(module):
attribute = getattr(module, attribute_name)
if (
isclass(attribute)
and issubclass(attribute, BaseParser)
and attribute is not BaseParser
):
register_parser(attribute)
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import os
from dataclasses import dataclass
from typing import Optional, Tuple

Expand Down Expand Up @@ -84,7 +85,9 @@ def file_upload_observations(
imported_observations = parser_instance.get_observations(data)

filename = (
file_upload_parameters.file.name if file_upload_parameters.file.name else ""
os.path.basename(file_upload_parameters.file.name)
if file_upload_parameters.file.name
else ""
)

import_parameters = ImportParameters(
Expand Down
127 changes: 127 additions & 0 deletions backend/unittests/fixtures/data_1/bandit.sarif
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
{
"runs": [
{
"tool": {
"driver": {
"name": "Bandit",
"rules": [
{
"id": "B104",
"name": "hardcoded_bind_all_interfaces",
"helpUri": "https://bandit.readthedocs.io/en/1.7.4/plugins/b104_hardcoded_bind_all_interfaces.html"
}
]
}
},
"invocations": [
{
"executionSuccessful": true,
"endTimeUtc": "2022-10-21T04:19:27Z"
}
],
"results": [
{
"message": {
"text": "Possible binding to all interfaces (dist)."
},
"locations": [
{
"physicalLocation": {
"region": {
"snippet": {
"text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n"
},
"startLine": 14
},
"artifactLocation": {
"uri": "backend/config/settings/dist.py"
},
"contextRegion": {
"snippet": {
"text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n"
},
"endLine": 15,
"startLine": 13
}
}
}
],
"properties": {
"issue_confidence": "MEDIUM",
"issue_severity": "MEDIUM"
},
"ruleId": "B104",
"ruleIndex": 0
},
{
"message": {
"text": "Possible binding to all interfaces (local)."
},
"locations": [
{
"physicalLocation": {
"region": {
"snippet": {
"text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n"
},
"startLine": 14
},
"artifactLocation": {
"uri": "backend/config/settings/local.py"
},
"contextRegion": {
"snippet": {
"text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n"
},
"endLine": 15,
"startLine": 13
}
}
}
],
"properties": {
"issue_confidence": "MEDIUM",
"issue_severity": "MEDIUM"
},
"ruleId": "B104",
"ruleIndex": 0
},
{
"message": {
"text": "Possible binding to all interfaces (dev)."
},
"locations": [
{
"physicalLocation": {
"region": {
"snippet": {
"text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n"
},
"startLine": 14
},
"artifactLocation": {
"uri": "backend/config/settings/dev.py"
},
"contextRegion": {
"snippet": {
"text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n"
},
"endLine": 15,
"startLine": 13
}
}
}
],
"properties": {
"issue_confidence": "MEDIUM",
"issue_severity": "HIGH"
},
"ruleId": "B104",
"ruleIndex": 0
}
]
}
],
"version": "2.1.0",
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json"
}
61 changes: 61 additions & 0 deletions backend/unittests/fixtures/data_2/bandit.sarif
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"runs": [
{
"tool": {
"driver": {
"name": "Bandit",
"rules": [
{
"id": "B104",
"name": "hardcoded_bind_all_interfaces",
"helpUri": "https://bandit.readthedocs.io/en/1.7.4/plugins/b104_hardcoded_bind_all_interfaces.html"
}
]
}
},
"invocations": [
{
"executionSuccessful": true,
"endTimeUtc": "2022-10-21T04:19:27Z"
}
],
"results": [
{
"message": {
"text": "Possible binding to all interfaces (local)."
},
"locations": [
{
"physicalLocation": {
"region": {
"snippet": {
"text": "ALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n"
},
"startLine": 14
},
"artifactLocation": {
"uri": "backend/config/settings/local.py"
},
"contextRegion": {
"snippet": {
"text": "# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts\nALLOWED_HOSTS = env(\"ALLOWED_HOSTS\", default=[\"localhost\", \"0.0.0.0\", \"127.0.0.1\"])\n\n"
},
"endLine": 15,
"startLine": 13
}
}
}
],
"properties": {
"issue_confidence": "MEDIUM",
"issue_severity": "HIGH"
},
"ruleId": "B104",
"ruleIndex": 0
}
]
}
],
"version": "2.1.0",
"$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json"
}
98 changes: 98 additions & 0 deletions backend/unittests/fixtures/import_observations_fixtures.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
[
{
"model": "access_control.user",
"pk": 1,
"fields": {
"password": "",
"last_login": null,
"is_superuser": false,
"username": "-product-1-api_token-",
"first_name": "",
"last_name": "",
"email": "",
"is_staff": false,
"is_active": true,
"date_joined": "2022-12-12T18:48:08.514Z",
"full_name": "-product-1-api_token-",
"is_external": true,
"groups": [],
"user_permissions": []
}
},
{
"model": "access_control.api_token",
"pk": 1,
"fields": {
"api_token_hash": "argon2$argon2id$v=19$m=102400,t=2,p=8$bUc4bk13R2RLSElVMlVoRENLeGoyaA$NMzcg5d9N6jufieKF+nADLa4AdLGdMb5lFVPN8zKPm0",
"user": 1
}
},
{
"model": "core.product",
"pk": 1,
"fields": {
"name": "db_product_import",
"description": "",
"repository_prefix": "",
"repository_default_branch": 1,
"security_gate_passed": true,
"security_gate_active": null,
"security_gate_threshold_critical": null,
"security_gate_threshold_high": null,
"security_gate_threshold_medium": null,
"security_gate_threshold_low": null,
"security_gate_threshold_none": null,
"security_gate_threshold_unkown": null,
"apply_general_rules": true,
"notification_ms_teams_webhook": "",
"last_observation_change": "2022-12-16T16:13:18.283Z",
"product_group": null
}
},
{
"model": "core.branch",
"pk": 1,
"fields": {
"product": 1,
"name": "db_branch_import"
}
},
{
"model": "core.product_member",
"pk": 1,
"fields": {
"product": 1,
"user": 5,
"role": 5
}
},
{
"model": "core.parser",
"pk": 1,
"fields": {
"name": "SARIF",
"type": "SAST",
"source": "File"
}
},
{
"model": "rules.rule",
"pk": 1,
"fields": {
"name": "db_product_rule_import",
"description": "",
"product": 1,
"parser": 1,
"scanner_prefix": "",
"title": "",
"origin_component_name_version": "",
"origin_docker_image_name_tag": "",
"origin_endpoint_url": "",
"origin_service_name": "",
"origin_source_file": ".*dev.*",
"new_severity": "",
"new_status": "Not affected",
"enabled": true
}
}
]
Empty file.
Loading

0 comments on commit a215967

Please sign in to comment.