Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix unittests #17

Merged
merged 4 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ jobs:
with:
python-version: '3.8'
cache: 'pip'
- run: pip install .[deepl]
- run: python -m unittest discover -v
- run: pip install .[all]
- run: make test
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
test:
python -m unittest discover -v -s reptor/tests
python -m unittest discover -v
5 changes: 3 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ classifiers = [
]

[project.optional-dependencies]
deepl = ['deepl >= 1.15.0']
gql = ['gql >= 3.4.1']
translate = ['deepl >= 1.15.0']
ghostwriter = ['gql >= 3.4.1']
all = ['reptor[translate,ghostwriter]']

[project.scripts]
reptor = 'reptor.__main__:run'
Expand Down
Empty file added reptor/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions reptor/api/APIClient.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def get(self, url: str) -> requests.models.Response:
Returns:
requests.models.Response: Returns requests Response Object
"""
self.reptor.logger.debug(f"GET URL:{url}")
response = requests.get(
url,
headers=self._get_headers(),
Expand All @@ -69,6 +70,7 @@ def post(
Returns:
requests.models.Response: Requests Responde Object
"""
self.reptor.logger.debug(f"POST URL:{url}")
response = requests.post(
url,
headers=self._get_headers(json_content=json_content),
Expand All @@ -90,6 +92,7 @@ def put(self, url: str, data: object) -> requests.models.Response:
Returns:
requests.models.Response: requests Respone Object
"""
self.reptor.logger.debug(f"PUT URL:{url}")
response = requests.put(
url,
headers=self._get_headers(),
Expand All @@ -110,6 +113,7 @@ def patch(self, url: str, data: object) -> requests.models.Response:
Returns:
requests.models.Response: requests Respone Object
"""
self.reptor.logger.debug(f"PATCH URL:{url}")
response = requests.patch(
url,
headers=self._get_headers(),
Expand Down
7 changes: 5 additions & 2 deletions reptor/api/ProjectsAPI.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)

self.base_endpoint = (
f"{self.reptor.get_config().get_server()}/api/v1/pentestprojects/"
f"{self.reptor.get_config().get_server()}/api/v1/pentestprojects"
)

self.object_endpoint = f"{self.base_endpoint}/{self.project_id}"
self.reptor.get_logger().debug(self.base_endpoint)

def get_projects(self, readonly: bool = False) -> typing.List[Project]:
"""Gets list of projects
Expand Down Expand Up @@ -53,7 +54,9 @@ def search(self, search_term: Optional[str] = "") -> typing.List[Project]:
return return_data

def get_project(self) -> Project:
url = urljoin(self.base_endpoint, f"{self.project_id}/")
if not self.project_id:
raise ValueError("Make sure you have a project specified.")
url = self.object_endpoint
response = self.get(url)
return Project(response.json())

Expand Down
94 changes: 61 additions & 33 deletions reptor/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ class ProjectDesignField(BaseModel):
"""

name: str = ""
type: ProjectFieldTypes = None
type: ProjectFieldTypes
label: str = ""
origin: str = ""
default: str = ""
required: bool = False
spellcheck: bool = None
# Use TypeAlias instead of "typing.List['ProjectDesignField'] = []" due to Python bug
spellcheck: bool = False
# Use Any instead of "typing.List['ProjectDesignField'] = []" due to Python bug
# See: https://bugs.python.org/issue44926
properties: typing.TypeAlias = "ProjectDesignField"
properties: Any = None
choices: typing.List[dict] = []
items: dict = {}
suggestions: typing.List[str] = []
Expand Down Expand Up @@ -356,13 +356,20 @@ class FindingDataExtendedField(ProjectDesignField):
typing.List, # list
bool, # boolean
float, # number
typing.TypeAlias, # "FindingDataExtendedField" for object
Any, # "FindingDataExtendedField" for object
]

def __init__(self,
design_field: ProjectDesignField,
value: typing.Union[
str, typing.List, bool, float, typing.TypeAlias,]):
def __init__(
self,
design_field: ProjectDesignField,
value: typing.Union[
str,
typing.List,
bool,
float,
Any,
],
):
project_design_type_hints = typing.get_type_hints(ProjectDesignField)
for attr in project_design_type_hints.items():
self.__setattr__(attr[0], design_field.__getattribute__(attr[0]))
Expand All @@ -372,12 +379,15 @@ def __init__(self,
for property in self.properties:
# property is of type ProjectDesignField
try:
self.value.append(FindingDataExtendedField(
property, value[property.name]))
self.value.append(
FindingDataExtendedField(
property, value[property.name])
)
except KeyError:
self.reptor.logger.fail_with_exit(
f"Object name '{property.name}' not found. Did you mix"
f"mismatched project design with project data?")
f"mismatched project design with project data?"
)
elif self.type == ProjectFieldTypes.list.value:
self.value = list()
for v in value:
Expand All @@ -386,51 +396,65 @@ def __init__(self,
self.value = value

def __setattr__(self, __name: str, __value: Any) -> None:
if __name == 'value' and __value is not None:
if __name == "value" and __value is not None:
if self.type in [
ProjectFieldTypes.combobox.value,
ProjectFieldTypes.cvss.value,
ProjectFieldTypes.string.value,
ProjectFieldTypes.markdown.value]:
ProjectFieldTypes.combobox.value,
ProjectFieldTypes.cvss.value,
ProjectFieldTypes.string.value,
ProjectFieldTypes.markdown.value,
]:
if not isinstance(__value, str):
raise ValueError(
f"'{self.name}' expects a string value (got '{__value}').")
f"'{self.name}' expects a string value (got '{__value}')."
)
elif self.type == ProjectFieldTypes.date.value:
try:
datetime.datetime.strptime(__value, '%Y-%m-%d')
datetime.datetime.strptime(__value, "%Y-%m-%d")
except ValueError:
raise ValueError(
f"'{self.name}' expects date in format 2000-01-01 (got '{__value}').")
f"'{self.name}' expects date in format 2000-01-01 (got '{__value}')."
)
elif self.type == ProjectFieldTypes.enum.value:
valid_enums = [choice['value'] for choice in self.choices]
valid_enums = [choice["value"] for choice in self.choices]
if __value not in valid_enums:
raise ValueError(
f"'{__value}' is not an valid enum choice for '{self.name}'.")
elif self.type in [ProjectFieldTypes.list.value, ProjectFieldTypes.object.value]:
f"'{__value}' is not an valid enum choice for '{self.name}'."
)
elif self.type in [
ProjectFieldTypes.list.value,
ProjectFieldTypes.object.value,
]:
if not isinstance(__value, list):
raise ValueError(
f"Value of '{self.name}' must be list (got '{type(__value)}').")
f"Value of '{self.name}' must be list (got '{type(__value)}')."
)
if not all([isinstance(v, FindingDataExtendedField) for v in __value]):
raise ValueError(
f"Value of '{self.name}' must contain list of FindingDataExtendedFields.")
f"Value of '{self.name}' must contain list of FindingDataExtendedFields."
)
types = set([v.type for v in __value])
if len(types) > 1:
raise ValueError(
f"Values of '{self.name}' must not contain FindingDataExtendedFields"
f"of multiple types (got {','.join(types)}).")
f"of multiple types (got {','.join(types)})."
)
elif self.type == ProjectFieldTypes.boolean.value:
if not isinstance(__value, bool):
raise ValueError(
f"'{self.name}' expects a boolean value (got '{__value}').")
f"'{self.name}' expects a boolean value (got '{__value}')."
)
elif self.type == ProjectFieldTypes.number.value:
if not isinstance(__value, int) and not isinstance(__value, float):
raise ValueError(f"'{self.name}' expects int or float (got '{__value}').")
raise ValueError(
f"'{self.name}' expects int or float (got '{__value}')."
)
elif self.type == ProjectFieldTypes.user.value:
try:
UUID(__value, version=4)
except ValueError:
raise ValueError(
f"'{self.name}' expects v4 uuid (got '{__value}').")
f"'{self.name}' expects v4 uuid (got '{__value}')."
)

return super().__setattr__(__name, __value)

Expand All @@ -452,14 +476,18 @@ class FindingDataExtended(BaseModel):
retest_status: FindingDataExtendedField
evidence: FindingDataExtendedField

def __init__(self,
design_fields: typing.List[ProjectDesignField] = None,
field_data: FindingData = None,):
def __init__(
self,
design_fields: typing.List[ProjectDesignField] = None,
field_data: FindingData = None,
):
for design_field in design_fields:
self.__setattr__(
design_field.name,
FindingDataExtendedField(
design_field, field_data.__getattribute__(design_field.name))
design_field, field_data.__getattribute__(
design_field.name)
),
)


Expand Down
Empty file added reptor/plugins/__init__.py
Empty file.
Empty file.
1 change: 0 additions & 1 deletion reptor/plugins/core/Nmap/tests/test_nmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
class NmapTests(unittest.TestCase):
def setUp(self) -> None:
reptor = Reptor()
reptor._load_config()
Nmap.set_template_vars(os.path.dirname(templates_path))
self.nmap = Nmap(reptor=reptor)

Expand Down
9 changes: 4 additions & 5 deletions reptor/plugins/core/Translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
try:
import deepl
except ImportError:
deepl = None
raise Exception("Make sure you have deepl installed.")


class Translate(Base):
Expand Down Expand Up @@ -152,7 +152,7 @@ def add_arguments(cls, parser, plugin_filepath=None):
def _set_deepl_translator(self) -> None:
if not deepl:
raise ModuleNotFoundError(
'deepl library not found. Install with "pip3 install reptor[deepl]'
'deepl library not found. Install plugin requirements with "pip3 install reptor[translate]'
)

try:
Expand Down Expand Up @@ -210,14 +210,13 @@ def _translate_project(self) -> None:
if self.dry_run:
self._translate = self._dry_run_translate
self.display(f"Translating project name{' (dry run)' if self.dry_run else ''}.")
from_projects_api: ProjectsAPI = ProjectsAPI(reptor=self.reptor)
from_project = from_projects_api.get_project()
from_project = self.reptor.api.projects.get_project()
from_project_name = from_project.name
to_project_title = self._translate(from_project_name)

self.display(f"Duplicating project{' (dry run)' if self.dry_run else ''}.")
if not self.dry_run:
to_project_id = from_projects_api.duplicate().id
to_project_id = self.reptor.api.projects.duplicate().id
self.display(
f"Updating project metadata{' (dry run)' if self.dry_run else ''}."
)
Expand Down
Empty file added reptor/plugins/core/__init__.py
Empty file.
Empty file.
Empty file.
Empty file added reptor/templates/__init__.py
Empty file.
Empty file added reptor/tests/__init__.py
Empty file.