Skip to content

Commit

Permalink
Merge pull request #104 from pablosnt/bugfix/sonar-qube
Browse files Browse the repository at this point in the history
Fix issues reported by SonarQube
  • Loading branch information
pablosnt authored Jan 2, 2023
2 parents b1eec6c + ce907b4 commit e89d44a
Show file tree
Hide file tree
Showing 15 changed files with 43 additions and 50 deletions.
5 changes: 2 additions & 3 deletions rekono/executions/queue/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ def get_findings_from_dependencies(dependencies: list) -> List[BaseInput]:
return findings


def update_new_dependencies(parent_job: str, new_jobs: list, targets: List[BaseInput]) -> None:
def update_new_dependencies(parent_job: str, new_jobs: list) -> None:
'''Update on hold jobs dependencies to include new jobs as dependency. Based on the parent job dependents.
Args:
parent_job (str): Parent job Id, used to get affected on hold jobs
new_jobs (list): Id list of new jobs
targets (List[BaseInput]): Target list. It can include all target types and resources
'''
executions_queue = django_rq.get_queue('executions-queue') # Get execution list
registry = DeferredJobRegistry(queue=executions_queue) # Get on hold jobs registry
Expand Down Expand Up @@ -121,6 +120,6 @@ def process_dependencies(
new_jobs_ids.append(job.id) # Save new Job Id
if new_jobs_ids: # New Jobs has been created
# Update next jobs dependencies based on current job dependents
update_new_dependencies(current_job.id, new_jobs_ids, targets)
update_new_dependencies(current_job.id, new_jobs_ids)
# Return first findings list to be used in the current job
return executions[0] if executions else []
7 changes: 4 additions & 3 deletions rekono/findings/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
from django_rq import job
from email_notifications import sender as email_sender
from executions.models import Execution
from findings.models import Finding, Vulnerability
from findings.nvd_nist import NvdNist
from telegram_bot import sender as telegram_sender
from telegram_bot.messages.execution import notification_messages
from users.enums import Notification

from findings.models import Finding, Vulnerability
from findings.nvd_nist import NvdNist

logger = logging.getLogger() # Rekono logger


Expand Down Expand Up @@ -69,7 +70,7 @@ def consumer(execution: Execution = None, findings: List[Finding] = []) -> None:
)
if execution.task.target.project.defectdojo_synchronization:
try:
report(execution, findings) # Import execution in Defect-Dojo
report(execution, findings) # Import execution in Defect-Dojo
except DefectDojoException:
# Prevent errors during the import in Defect-Dojo
# All the exceptions are managed inside the report function
Expand Down
18 changes: 9 additions & 9 deletions rekono/frontend/src/backend/RekonoApi.vue
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export default {
cveRegex: /^CVE-\d{4}-\d{1,7}$/,
defectDojoKeyRegex: /^[\da-z]{40}$/,
telegramTokenRegex: /^\d{10}:[\w-]{35}$/,
credentialRegex: /^[\d\w./\-=+,:<>¿?¡!#&$()[\]{}*]{1,500}$/,
credentialRegex: /^[\w./\-=+,:<>¿?¡!#&$()[\]{}*]{1,500}$/,
telegramBotName: null,
defectDojoUrl: null,
defectDojoEnabled: null
Expand Down Expand Up @@ -221,7 +221,7 @@ export default {
cleanParams (params) {
if (params) {
let cleanParams = {}
for (var field in params) {
for (let field in params) {
if (![''. null, undefined].includes(params[field])) {
cleanParams[field] = params[field]
}
Expand All @@ -232,7 +232,7 @@ export default {
},
cleanBody (body) {
if (body) {
for (var field in body) {
for (let field in body) {
if (['', null, undefined].includes(body[field])) {
body[field] = null
}
Expand Down Expand Up @@ -281,17 +281,17 @@ export default {
}
},
duration (start, end) {
var startDate = moment(start)
var endDate = moment(end)
var duration = moment.duration(endDate.diff(startDate))
var text = ''
var values = [
const startDate = moment(start)
const endDate = moment(end)
const duration = moment.duration(endDate.diff(startDate))
let text = ''
const values = [
{'value': duration.days(), 'text': 'd'},
{'value': duration.hours(), 'text': 'h'},
{'value': duration.minutes(), 'text': 'm'},
{'value': duration.seconds(), 'text': 's'}
]
for (var index in values) {
for (let index in values) {
if (values[index].value > 0) {
text += values[index].value.toString() + ' ' + values[index].text + ' '
}
Expand Down
2 changes: 1 addition & 1 deletion rekono/frontend/src/components/Projects.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {
mixins: [RekonoApi],
computed: {
projectsFields () {
var fields = [
let fields = [
{ key: 'name', label: 'Project', sortable: true },
{ key: 'tags', sortable: true },
{ key: 'targets.length', label: 'Targets', sortable: true },
Expand Down
2 changes: 1 addition & 1 deletion rekono/frontend/src/components/project/Targets.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {
},
computed: {
targetsFields () {
var fields = [
let fields = [
{ key: 'target', sortable: true },
{ key: 'type', sortable: true },
{ key: 'target_ports.length', label: 'Target Ports', sortable: true },
Expand Down
6 changes: 2 additions & 4 deletions rekono/frontend/src/modals/Task.vue
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export default {
if (this.configurationId) {
data.configuration_id = this.configurationId
}
for (var index in this.targetIds) {
for (let index in this.targetIds) {
data.target_id = this.targetIds[index]
this.post('/api/tasks/', data, this.selectedTool ? this.selectedTool.name : this.selectedProcess.name, 'Execution requested successfully')
.catch(task => { return Promise.resolve(task) })
Expand All @@ -248,9 +248,7 @@ export default {
}
}
})
}
return
}
},
clean () {
this.processes = []
Expand Down
2 changes: 1 addition & 1 deletion rekono/frontend/src/modals/targets/Target.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default {
confirm (event) {
event.preventDefault()
if (this.check()) {
for (var index in this.targets) {
for (let index in this.targets) {
this.post('/api/targets/', { project: this.projectId, target: this.targets[index] }, this.targets[index], 'New target created successfully')
.catch(() => { return Promise.resolve(false) })
.then(() => {
Expand Down
2 changes: 1 addition & 1 deletion rekono/frontend/src/views/Settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ export default {
handleSettings (event) {
event.preventDefault()
if (this.checkSettings()) {
var data = {
let data = {
upload_files_max_mb: this.uploadFilesMaxMb,
defect_dojo_url: this.defectDojoUrl,
defect_dojo_verify_tls: this.defectDojoVerifyTls,
Expand Down
3 changes: 2 additions & 1 deletion rekono/security/input_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@

logger = logging.getLogger() # Rekono logger

IP_RANGE_REGEX = r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}-\d{1,3}' # Regex for IP ranges like 10.10.10.1-20
NAME_REGEX = r'[\wÀ-ÿ\s\.\-\[\]()]{0,100}' # Regex for names validation
TEXT_REGEX = r'[\wÀ-ÿ\s\.:,+\-\'"?¿¡!#%$€\[\]()]{0,300}' # Regex for text validation
PATH_REGEX = r'[\w\./#?&%$\\]{0,500}' # Regex for path validation
CVE_REGEX = r'CVE-\d{4}-\d{1,7}' # Regex for CVE validation
DD_KEY_REGEX = r'[\da-z]{40}' # Regex for Defect-Dojo key validation
TELEGRAM_TOKEN_REGEX = r'\d{10}:[\w\-]{35}' # Regex for Telegram token validation
CREDENTIAL_REGEX = r'[\d\w\./\-=\+,:<>¿?¡!#&$()\[\]\{\}\*]{1,500}' # Regex for credentials validation
CREDENTIAL_REGEX = r'[\w\./\-=\+,:<>¿?¡!#&$()\[\]\{\}\*]{1,500}' # Regex for credentials validation


def validate_text_value(value: str, regex: str) -> None:
Expand Down
4 changes: 1 addition & 3 deletions rekono/targets/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@
import socket

from django.core.exceptions import ValidationError
from security.input_validation import IP_RANGE_REGEX

from targets.enums import TargetType

# Regex to match IP ranges like 10.10.10.1-20
IP_RANGE_REGEX = '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}-[0-9]{1,3}'

logger = logging.getLogger() # Rekono logger


Expand Down
3 changes: 2 additions & 1 deletion rekono/tasks/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from executions.models import Execution
from queues.utils import cancel_and_delete_job, cancel_job
from rq.command import send_stop_job_command

from tasks.enums import Status
from tasks.models import Task

Expand Down Expand Up @@ -48,4 +49,4 @@ def cancel_task(task: Task) -> None:
task.save(update_fields=['status', 'end'])
else:
logger.warning(f'[Task] Task {task.id} can\'t be cancelled')
raise ValidationError({'id': f'Task {task.id} can not be cancelled'}) # Task is not eligible for cancellation
raise ValidationError({'id': f'Task {task.id} can\'t be cancelled'}) # Task is not eligible for cancellation
4 changes: 2 additions & 2 deletions rekono/testing/executions/test_base_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,13 +554,13 @@ def test_tool_execution(self) -> None:
self.tool_instance = self.tool_class(self.new_execution, self.intensity, self.arguments)
errors_count = 0
try:
self.tool_instance.tool_execution(['/directory-not-found'], [], []) # Directory not found
self.tool_instance.tool_execution(['/directory-not-found']) # Directory not found
except ToolExecutionException as ex:
self.tool_instance.on_error(stderr=str(ex)) # Test on_error feature
self.assertEqual(Status.ERROR, self.new_execution.status)
self.assertEqual(str(ex).strip(), self.new_execution.output_error)
errors_count += 1
self.tool_instance.tool_execution(['/'], [], []) # Valid ls execution
self.tool_instance.tool_execution(['/']) # Valid ls execution
self.assertEqual(1, errors_count)

def process_findings(self, imported_in_defectdojo: bool) -> None:
Expand Down
16 changes: 7 additions & 9 deletions rekono/tools/tools/base_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,11 @@ def get_host_from_url(self, argument: str) -> str:
host = host[:-1] # Remove last slash form URL
return host

def tool_execution(self, arguments: List[str], targets: List[BaseInput], previous_findings: List[Finding]) -> str:
def tool_execution(self, arguments: List[str]) -> str:
'''Execute the tool.
Args:
arguments (List[str]): Arguments to include in the tool command
targets (List[BaseInput]): List of targets and resources
previous_findings (List[Finding]): List of previous findings
Raises:
ToolExecutionException: Raised if tool execution finishes with an exit code distinct than zero
Expand All @@ -308,13 +306,13 @@ def tool_execution(self, arguments: List[str], targets: List[BaseInput], previou
logger.info(f'[Tool] Running: {" ".join(arguments)}')
if hasattr(self, 'run_directory'):
# Execute the tool in directory
exec = subprocess.run(arguments, capture_output=True, cwd=getattr(self, 'run_directory'))
process = subprocess.run(arguments, capture_output=True, cwd=getattr(self, 'run_directory'))
else:
exec = subprocess.run(arguments, capture_output=True) # Execute the tool
if not self.ignore_exit_code and exec.returncode > 0:
process = subprocess.run(arguments, capture_output=True) # Execute the tool
if not self.ignore_exit_code and process.returncode > 0:
# Execution error and ignore exit code is False
raise ToolExecutionException(exec.stderr.decode('utf-8'))
return exec.stdout.decode('utf-8')
raise ToolExecutionException(process.stderr.decode('utf-8'))
return process.stdout.decode('utf-8')

def create_finding(self, finding_type: Model, **fields: Any) -> Finding:
'''Create finding from fields.
Expand Down Expand Up @@ -460,7 +458,7 @@ def run(self, targets: List[BaseInput], previous_findings: List[Finding]) -> Non
output = ''
if not TESTING:
# Run tool
output = self.tool_execution(self.command_arguments, targets, previous_findings) # pragma: no cover
output = self.tool_execution(self.command_arguments) # pragma: no cover
except ToolExecutionException as ex: # pragma: no cover
logger.error(f'[Tool] {self.tool.name} execution finish with errors')
# Error during tool execution
Expand Down
17 changes: 7 additions & 10 deletions rekono/tools/tools/gitleaks.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
from typing import List

from findings.enums import Severity
from findings.models import Credential, Finding, Port, Vulnerability
from findings.models import Credential, Port, Vulnerability
from input_types.enums import InputKeyword
from input_types.models import BaseInput
from rekono.settings import REPORTS_DIR, TOOLS

from tools.exceptions import ToolExecutionException
Expand Down Expand Up @@ -42,13 +41,11 @@ def parse_output_file(self) -> None:
context=f'/.git/ : Email of the commit author {finding.get("Author")}'
)

def tool_execution(self, arguments: List[str], targets: List[BaseInput], previous_findings: List[Finding]) -> str:
def tool_execution(self, arguments: List[str]) -> str:
'''Execute the tool.
Args:
arguments (List[str]): Arguments to include in the tool command
targets (List[BaseInput]): List of targets and resources
previous_findings (List[Finding]): List of previous findings
Raises:
ToolExecutionException: Raised if tool execution finishes with an exit code distinct than zero
Expand All @@ -64,7 +61,7 @@ def tool_execution(self, arguments: List[str], targets: List[BaseInput], previou
else:
data[InputKeyword.URL.name.lower()] += '.git/' # Add .git path with last slash
self.run_directory = os.path.join(REPORTS_DIR, str(uuid.uuid4())) # Path where Git repo will be dumped
exec = subprocess.run( # Dump Git repository
process = subprocess.run( # Dump Git repository
['bash', self.script, data[InputKeyword.URL.name.lower()], self.run_directory],
capture_output=True,
cwd=self.gitdumper_directory
Expand Down Expand Up @@ -92,8 +89,8 @@ def tool_execution(self, arguments: List[str], targets: List[BaseInput], previou
)
self.execution.extra_data_path = self.run_directory # Save extra data related to GitLeaks
self.execution.save(update_fields=['extra_data_path'])
return super().tool_execution(arguments, targets, previous_findings) # Run GitLeaks
if exec.returncode > 0: # Error during gitdumper execution
raise ToolExecutionException(exec.stderr.decode('utf-8'))
return exec.stdout.decode('utf-8') # Git repository hasn't been dumped
return super().tool_execution(arguments) # Run GitLeaks
if process.returncode > 0: # Error during gitdumper execution
raise ToolExecutionException(process.stderr.decode('utf-8'))
return process.stdout.decode('utf-8') # Git repository hasn't been dumped
raise ToolExecutionException('Path argument is required')
2 changes: 1 addition & 1 deletion rekono/users/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from security.authorization.roles import Role
from security.input_validation import validate_name
from security.otp import generate, get_expiration

from users.enums import Notification

# Create your models here.
Expand Down Expand Up @@ -91,7 +92,6 @@ def enable_user(self, user: Any) -> Any:
Returns:
Any: Enabled user
'''
# user.is_active = True # Enable user
user.otp = generate() # Generate its OTP
user.otp_expiration = get_expiration() # Set OTP expiration
user.save(update_fields=['otp', 'otp_expiration'])
Expand Down

0 comments on commit e89d44a

Please sign in to comment.