Skip to content
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: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ jobs:
python-version: "3.12"

- name: Install python-ldap OS dependencies
run: sudo apt-get install -y libsasl2-dev libldap2-dev libssl-dev
run: |
sudo apt-get update
sudo apt-get install -y libldap2-dev libsasl2-dev

- name: Install dependencies
run: make dev envfile
Expand Down
46 changes: 13 additions & 33 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,45 +46,25 @@ envfile:
@mkdir -p $(shell dirname ${ENV_FILE}) && touch ${ENV_FILE}
@echo "SECRET_KEY=${GET_SECRET_KEY}" > ${ENV_FILE}

isort:
@echo "-> Apply isort changes to ensure proper imports ordering"
@${ACTIVATE} isort .

black:
@echo "-> Apply black code formatter"
@${ACTIVATE} black ${BLACK_ARGS} .

doc8:
@echo "-> Run doc8 validation"
@${ACTIVATE} doc8 --max-line-length 100 --ignore-path docs/_build/ \
--ignore-path docs/installation_and_sysadmin/ --quiet docs/

valid: isort black doc8 check

bandit:
@echo "-> Run source code security analyzer"
@${ACTIVATE} pip install bandit
@${ACTIVATE} bandit --recursive . \
--exclude ./bin,./data,./dist,./docs,./include,./lib,./share,./thirdparty,./var,tests \
--quiet

check: doc8 bandit
@echo "-> Run flake8 (pycodestyle, pyflakes, mccabe) validation"
@${ACTIVATE} flake8 .
@echo "-> Run isort imports ordering validation"
@${ACTIVATE} isort --check-only .
@echo "-> Run black validation"
@${ACTIVATE} black --check ${BLACK_ARGS} .
valid:
@echo "-> Run Ruff linter"
@${ACTIVATE} ruff check --fix
@echo "-> Run Ruff format"
@${ACTIVATE} ruff format

check:
@echo "-> Run Ruff linter validation (pycodestyle, bandit, isort, and more)"
@${ACTIVATE} ruff check
@echo "-> Run Ruff format validation"
@${ACTIVATE} ruff format --check
@echo "-> Running ABOUT files validation"
@${ACTIVATE} about check ./thirdparty/
@$(MAKE) check-docstrings

check-docstrings:
@echo "-> Run docstring validation"
@${ACTIVATE} pip install pydocstyle
@${ACTIVATE} pydocstyle component_catalog dejacode dejacode_toolkit dje \
license_library notification organization policy product_portfolio purldb \
reporting workflow
@$(MAKE) doc8

check-deploy:
@echo "-> Check Django deployment settings"
Expand Down Expand Up @@ -165,4 +145,4 @@ log:
createsuperuser:
${DOCKER_EXEC} web ./manage.py createsuperuser

.PHONY: virtualenv conf dev envfile check bandit isort black doc8 valid check-docstrings check-deploy clean initdb postgresdb migrate run test docs build psql bash shell log createsuperuser
.PHONY: virtualenv conf dev envfile check doc8 valid check-deploy clean initdb postgresdb migrate run test docs build psql bash shell log createsuperuser
30 changes: 16 additions & 14 deletions component_catalog/management/commands/collectpackagesdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,42 @@


class Command(DataspacedCommand):
help = ('Collects and saves md5, sha1, and size values where one of those '
'are missing in the given Dataspace on Package instances.')
help = (
"Collects and saves md5, sha1, and size values where one of those "
"are missing in the given Dataspace on Package instances."
)

def add_arguments(self, parser):
super().add_arguments(parser)
parser.add_argument(
'--save',
action='store_true',
dest='save',
"--save",
action="store_true",
dest="save",
default=False,
help='Use save() in place of update() (default) to trigger all '
'associated logic and signals. Fields such as last_modified_date '
'will be updated.',
help="Use save() in place of update() (default) to trigger all "
"associated logic and signals. Fields such as last_modified_date "
"will be updated.",
)

def handle(self, *args, **options):
super().handle(*args, **options)

packages = (
Package.objects.scope(self.dataspace)
.exclude(download_url='')
.filter(Q(md5='') | Q(sha1='') | Q(size__isnull=True))
.exclude(download_url="")
.filter(Q(md5="") | Q(sha1="") | Q(size__isnull=True))
)

self.stdout.write(f'{packages.count()} Packages in the queue.')
self.stdout.write(f"{packages.count()} Packages in the queue.")

update_count = 0
for package in packages:
self.stdout.write(f'Collecting: {package.download_url}')
self.stdout.write(f"Collecting: {package.download_url}")
update_fields = package.collect_data(save=False)
if not update_fields:
continue

if options['save']:
if options["save"]:
package.save()
else:
Package.objects.filter(pk=package.pk).update(
Expand All @@ -56,5 +58,5 @@ def handle(self, *args, **options):
self.stdout.write(f"{', '.join(update_fields)} updated")
update_count += 1

msg = f'{update_count} Package(s) updated.'
msg = f"{update_count} Package(s) updated."
self.stdout.write(self.style.SUCCESS(msg))
16 changes: 5 additions & 11 deletions component_catalog/tests/test_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ def test_edit_component_assigned_package_replacement(self):

# Making sure we have unicode char in the name
package1 = Package.objects.create(
filename="\u02A0package1.zip", dataspace=self.component1.dataspace
filename="\u02a0package1.zip", dataspace=self.component1.dataspace
)
assigned_package1 = ComponentAssignedPackage.objects.create(
component=self.component1, package=package1, dataspace=self.component1.dataspace
Expand Down Expand Up @@ -414,7 +414,7 @@ def test_edit_component_assigned_package_replacement(self):

# Replacing the existing file by a another one
package2 = Package.objects.create(
filename="\u02A0package2.zip", dataspace=self.component1.dataspace
filename="\u02a0package2.zip", dataspace=self.component1.dataspace
)
params["componentassignedpackage_set-0-package"] = package2.id
self.client.post(url, params)
Expand Down Expand Up @@ -1124,9 +1124,7 @@ def test_component_changelist_set_policy_action_proper(self):
<td>license1</td>
<td>license1 AND license2</td>
<td><input type="checkbox" name="checked_id_{}" class="enabler"></td>
</tr>""".format(
self.component1.get_admin_url(), self.component1.id
)
</tr>""".format(self.component1.get_admin_url(), self.component1.id)
self.assertContains(response, expected, html=True)

self.assertIsNone(self.component1.usage_policy)
Expand Down Expand Up @@ -1333,9 +1331,7 @@ def test_component_admin_form_license_expression_change_impact_on_relation(self)
</a> in changelist
</strong>
</li>
""".format(
subcomponent_relation.id
)
""".format(subcomponent_relation.id)
self.assertContains(response, expected, html=True)

def test_component_admin_form_subcomponent_inline_clean_license_expression(self):
Expand Down Expand Up @@ -1710,9 +1706,7 @@ def test_package_changelist_set_policy_action_proper(self):
<td>license1</td>
<td>license1 AND license2</td>
<td><input type="checkbox" name="checked_id_{}" class="enabler"></td>
</tr>""".format(
p1.get_admin_url(), p1.filename, p1.id
)
</tr>""".format(p1.get_admin_url(), p1.filename, p1.id)
self.assertContains(response, expected, html=True)

self.assertIsNone(p1.usage_policy)
Expand Down
8 changes: 3 additions & 5 deletions component_catalog/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4133,9 +4133,7 @@ def test_component_catalog_list_view_request_links(self):
expected = """
<a href="{}#activity" class="r-link">
<span class="badge text-bg-request">R</span>
</a>""".format(
self.component1.get_absolute_url()
)
</a>""".format(self.component1.get_absolute_url())
self.assertContains(response, expected, html=True)

def test_component_list_multi_send_about_files_view(self):
Expand Down Expand Up @@ -4578,7 +4576,7 @@ def test_related_label_has_correct_target(self):
reverse("grp_related_lookup"), self.c1.pk
)
response = self.client.get(url)
expected = [{"label": "{0}".format(self.c1), "safe": False, "value": str(self.c1.pk)}]
expected = [{"label": str(self.c1), "safe": False, "value": str(self.c1.pk)}]
self.assertEqual(expected, json.loads(response.content))

def test_reference_dataspace_users_access_another_dataspaces_through_grappelli_lookup(self):
Expand All @@ -4591,7 +4589,7 @@ def test_reference_dataspace_users_access_another_dataspaces_through_grappelli_l
response = self.client.get(url)
expected = [
{
"label": "{0}".format(self.other_component),
"label": str(self.other_component),
"safe": False,
"value": str(self.other_component.pk),
}
Expand Down
2 changes: 1 addition & 1 deletion component_catalog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2337,7 +2337,7 @@ def scan_detected_package_fields(self, key_files_packages):
for label, scan_field in ScanCodeIO.SCAN_PACKAGE_FIELD:
if value := self.detected_package_data.get(scan_field):
if isinstance(value, list):
value = format_html("<br>".join(([escape(entry) for entry in value])))
value = format_html("<br>".join([escape(entry) for entry in value]))
else:
value = escape(value)
detected_package_fields.append((label, value))
Expand Down
7 changes: 3 additions & 4 deletions dejacode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
from pathlib import Path

import environ
import ldap
from django_auth_ldap.config import GroupOfNamesType
from django_auth_ldap.config import LDAPSearch

# The home directory of the dejacode user that owns the installation.
PROJECT_DIR = environ.Path(__file__) - 1
Expand Down Expand Up @@ -685,10 +688,6 @@ def get_fake_redis_connection(config, use_strict_redis):

# LDAP Configuration

import ldap
from django_auth_ldap.config import GroupOfNamesType
from django_auth_ldap.config import LDAPSearch

# This authentication backend enables users to authenticate against an
# LDAP server.
# To enable LDAP Authentication, first, set the following in your .env
Expand Down
4 changes: 2 additions & 2 deletions dejacode_toolkit/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

def sha1(content):
"""Return the sha1 hash of the given content."""
return hashlib.sha1(content).hexdigest() # nosec
return hashlib.sha1(content, usedforsecurity=False).hexdigest()


def sha256(content):
Expand All @@ -26,4 +26,4 @@ def sha512(content):

def md5(content):
"""Return the md5 hash of the given content."""
return hashlib.md5(content).hexdigest() # nosec
return hashlib.md5(content, usedforsecurity=False).hexdigest()
6 changes: 3 additions & 3 deletions dje/client_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ def add_client_data(request, **kwargs):
Set values on the request, to be available in the JavaScript client data object.
On the client side, the values are accessible through ``NEXB.client_data``.
"""
if not hasattr(request, 'client_data'):
if not hasattr(request, "client_data"):
request.client_data = {}
request.client_data.update(kwargs)


def client_data_context_processor(request):
client_data = getattr(request, 'client_data', {})
return {'client_data': client_data}
client_data = getattr(request, "client_data", {})
return {"client_data": client_data}
54 changes: 32 additions & 22 deletions dje/management/commands/checkdata.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# DejaCode is a trademark of nexB Inc.
Expand All @@ -17,45 +16,56 @@


class Command(BaseCommand):
help = 'Checks the given Dataspace for potential data problems.'
help = "Checks the given Dataspace for potential data problems."
requires_system_checks = []

def add_arguments(self, parser):
parser.add_argument('dataspace', nargs='?', help='Name of the Dataspace.')
parser.add_argument('--tag', '-t', action='append', dest='tags',
help='Run only checks labeled with given tag.')
parser.add_argument('--list-tags', action='store_true', dest='list_tags',
help='List available tags.')
parser.add_argument('--all-dataspaces', action='store_true', dest='all_dataspaces',
help='Run the checks on all Dataspaces.')
parser.add_argument("dataspace", nargs="?", help="Name of the Dataspace.")
parser.add_argument(
"--tag",
"-t",
action="append",
dest="tags",
help="Run only checks labeled with given tag.",
)
parser.add_argument(
"--list-tags", action="store_true", dest="list_tags", help="List available tags."
)
parser.add_argument(
"--all-dataspaces",
action="store_true",
dest="all_dataspaces",
help="Run the checks on all Dataspaces.",
)

def handle(self, *args, **options):
if options['list_tags']:
self.stdout.write('\n'.join(sorted(registry.tags_available())))
if options["list_tags"]:
self.stdout.write("\n".join(sorted(registry.tags_available())))
return

dataspace = options.get('dataspace')
tags = options.get('tags')
dataspace = options.get("dataspace")
tags = options.get("tags")

if not dataspace and not options['all_dataspaces']:
raise CommandError('Enter a Dataspace.')
if not dataspace and not options["all_dataspaces"]:
raise CommandError("Enter a Dataspace.")

special_tags = ['reporting'], ['expression']
if options['all_dataspaces'] and tags not in special_tags:
raise CommandError('--all-dataspaces only usable with `--tag reporting` or '
'`--tag expression`')
special_tags = ["reporting"], ["expression"]
if options["all_dataspaces"] and tags not in special_tags:
raise CommandError(
"--all-dataspaces only usable with `--tag reporting` or " "`--tag expression`"
)

app_configs = {}

if dataspace:
try:
dataspace = Dataspace.objects.get(name=dataspace)
except Dataspace.DoesNotExist:
raise CommandError(f'The Dataspace {dataspace} does not exit.')
raise CommandError(f"The Dataspace {dataspace} does not exit.")

# Using `app_configs` as a workaround to provide the dataspace to
# the check commands.
app_configs = {'dataspace': dataspace}
app_configs = {"dataspace": dataspace}

if tags:
try:
Expand All @@ -65,7 +75,7 @@ def handle(self, *args, **options):
else:
raise CommandError(f'No data check for the "{invalid_tag}" tag.')
else:
tags = ['data', 'reporting', 'expression'] # default tags
tags = ["data", "reporting", "expression"] # default tags

self.check(
app_configs=app_configs,
Expand Down
5 changes: 1 addition & 4 deletions dje/management/commands/checkmigrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ def add_arguments(self, parser):
parser.add_argument(
"--database",
default=DEFAULT_DB_ALIAS,
help=(
'Nominates a database to synchronize. Defaults to the "default" '
"database."
),
help='Nominates a database to synchronize. Defaults to the "default" ' "database.",
)

def handle(self, *args, **options):
Expand Down
3 changes: 1 addition & 2 deletions dje/management/commands/checks.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# DejaCode is a trademark of nexB Inc.
Expand Down Expand Up @@ -441,7 +440,7 @@ def check_for_fields_value_inconsistencies(app_configs, **kwargs):
group_list = list(group)

for field_name in fields_to_check:
if type(tuple()) == type(field_name):
if isinstance(field_name, tuple):
field_name, method = field_name
inconsistencies = {str(getattr(instance, method)()) for instance in group_list}
else:
Expand Down
Loading