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
11 changes: 11 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ Release notes
Owner not found in the Dataspace are now automatically created.
https://github.com/aboutcode-org/dejacode/issues/239

- Updated the label of the following Product actions.
The labels were updated everywhere in the UI (page title, documentation,
import log, etc...) for consistency:
- Import data from Scan -> Import ScanCode scan results
- Load Packages from SBOMs -> Import SBOM
- Import Packages from manifests -> Import Package manifests
- Pull ScanCode.io Project data -> Import ScanCode.io project
Improve the rendering and layout of the Import related forms for consistency,
simplicity, and readability.
https://github.com/aboutcode-org/dejacode/issues/241

### Version 5.2.1

- Fix the models documentation navigation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<div class="progress-bar {% if has_errors %}bg-warning{% else %}bg-success{% endif %}" role="progressbar" style="width: 100%" aria-label="Scan progress" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
{% elif status == 'failure' or status == "stopped" or status == "stale" %}
<div class="progress-bar bg-danger" role="progressbar" style="width: 100%" aria-label="Scan progress" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
{% elif status == 'warning' %}
<div class="progress-bar bg-warning" role="progressbar" style="width: 100%" aria-label="Scan progress" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100"></div>
{% elif status == 'running' %}
<div class="progress-bar" role="progressbar" style="width: 40%" aria-label="Scan progress" aria-valuenow="40" aria-valuemin="0" aria-valuemax="100"></div>
{% elif status == 'not_started' or status == 'queued' %}
Expand Down
4 changes: 3 additions & 1 deletion dejacode/static/css/dejacode_bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -590,10 +590,12 @@ div.awesomplete {
[data-bs-theme=dark] .awesomplete > ul {
background: var(--bs-black);
}

#div_id_component .awesomplete {
display: inline-block !important;
}
label.requiredField {
font-weight: bolder;
}

/* -- Products comparison -- */
body.product-comparison tr.unchanged {
Expand Down
2 changes: 1 addition & 1 deletion dje/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ def pull_project_data_from_scancodeio(scancodeproject_uuid):
)

if scancode_project.type == scancode_project.ProjectType.LOAD_SBOMS:
notification_verb = "Load Packages from SBOMs"
notification_verb = "Import SBOM"
else:
notification_verb = "Import packages from ScanCode.io"

Expand Down
3 changes: 1 addition & 2 deletions dje/templates/includes/form_errors_alert.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{% if form.errors %}
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="alert alert-danger" role="alert">
<p class="m-0">Please correct the error{{ form.errors|pluralize }} below.</p>
</div>
{% endif %}
18 changes: 18 additions & 0 deletions dje/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
from django.core.files.uploadedfile import TemporaryUploadedFile
from django.db import DEFAULT_DB_ALIAS
from django.db import connections
from django.test.runner import DiscoverRunner
Expand Down Expand Up @@ -124,3 +125,20 @@ def assertMaxQueries(self, num, func=None, *args, using=DEFAULT_DB_ALIAS, **kwar

with context:
func(*args, **kwargs)


def wrap_as_temp_uploaded_file(file_path):
"""Wrap an existing file as a Django TemporaryUploadedFile"""
temp_file = TemporaryUploadedFile(
name=file_path.name,
content_type="application/json",
size=file_path.stat().st_size,
charset="utf-8",
)

# Read and copy file content into the temporary file
with open(file_path, "rb") as f:
temp_file.write(f.read())

temp_file.seek(0) # Reset pointer after writing
return temp_file
2 changes: 1 addition & 1 deletion docs/reference-1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Reference 1 - Declared License Expression and License Clarity Scoring
=====================================================================

When you scan a Package from DejaCode, you can view the Scan Results in a
:guilabel:`Action` tab on the Package details user view. DejaCode presents a selection of
:guilabel:`Actions` tab on the Package details user view. DejaCode presents a selection of
scan details with an emphasis on license detection. You can also download the
complete :guilabel:`Scan Results` in .json format.

Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial-1.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ Alternatively, you can conveniently download one of the provided examples from
the following
`GitHub repository <https://github.com/aboutcode-org/dejacode/tree/main/docs/sboms/>`_.

On the Product details page, from the :guilabel:`Action` dropdown, select
:guilabel:`Load Packages from SBOMs`:
On the Product details page, from the :guilabel:`Actions` dropdown, select
:guilabel:`Import SBOM`:

* Click the :guilabel:`Choose File` button on the **SBOM file or zip archive** field.
* Select your SBOM (.cdx.json or .spdx.json) and click the :guilabel:`Open` button.
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial-2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Click the green :guilabel:`Add` button.

DejaCode presents the new Package.

- Refresh your browser page to see the :guilabel:`Action` tab.
- Refresh your browser page to see the :guilabel:`Actions` tab.
- Explore the scan results.
- Select values to apply to the new Package definition, such as one or more licenses,
a Copyright statement, and a Primary langauge.
Expand Down Expand Up @@ -109,7 +109,7 @@ Improve Package Data by Scanning
Select :guilabel:`Packages` from the main menu bar.

Identify and select a Package that needs to be improved.
Click the :guilabel:`Action` button on the Package details form.
Click the :guilabel:`Actions` button on the Package details form.

Optionally follow the progress of the Scan by selecting the :guilabel:`Scans`
option from the :guilabel:`Tools` dropdown on the main menu bar.
Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial-4-vulnerabilities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ Load Scan Results to your Product

`<https://github.com/aboutcode-org/dejacode/tree/main/docs/sboms/starship_engine_2.0_scan_results.json>`_.

2. On the Product details page, from the :guilabel:`Action` dropdown, select
:guilabel:`Import from Scan`:
2. On the Product details page, from the :guilabel:`Actions` dropdown, select
:guilabel:`Import ScanCode scan results`:

* Click the :guilabel:`Choose File` button under the **Upload file** field.
* Select the **starship_engine_2.0_scan_results.json** file and click the
Expand Down
6 changes: 3 additions & 3 deletions docs/tutorial-5-sboms.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ Load an SBOM to your Product

`<https://github.com/aboutcode-org/dejacode/raw/refs/heads/main/docs/sboms/storm-core-1.0.1.cdx.json.zip>`_.

2. On the Product details page, from the :guilabel:`Action` dropdown, select
:guilabel:`Load Packages from SBOMs`:
2. On the Product details page, from the :guilabel:`Actions` dropdown, select
:guilabel:`Import SBOM`:

* Click the Browse field beneath :guilabel:`SBOM file or zip archive`
* Select the **storm-core-1.0.cdx.json** file and leave the additional options
Expand All @@ -46,7 +46,7 @@ Load an SBOM to your Product
.. image:: images/tutorial-5-sboms/inventory-tab-1.jpg

5. You can enrich the data provided by your supplier,
From the :guilabel:`Action` dropdown, select
From the :guilabel:`Actions` dropdown, select
:guilabel:`Improve Packages from PurlDB`:

.. image:: images/tutorial-5-sboms/improve-packages-from-purldb.jpg
Expand Down
6 changes: 3 additions & 3 deletions product_portfolio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,15 @@ def perform_create(self, serializer):
@action(detail=True, methods=["post"], serializer_class=LoadSBOMsFormSerializer)
def load_sboms(self, request, *args, **kwargs):
"""
Load Packages from SBOMs.
Import SBOM.

DejaCode supports the following SBOM formats:
* CycloneDX BOM as JSON bom.json and .cdx.json,
* SPDX document as JSON .spdx.json,
* AboutCode .ABOUT files,

Multiple SBOMs: You can provide multiple SBOMs by packaging them into a zip
archive. DejaCode will handle and process them accordingly.
archive. DejaCode will process them accordingly.
"""
product = self.get_object()

Expand All @@ -374,7 +374,7 @@ def import_manifests(self, request, *args, **kwargs):
Import Packages from Manifests.

Multiple Manifests: You can provide multiple files by packaging them into a zip
archive. DejaCode will handle and process them accordingly.
archive. DejaCode will process them accordingly.
"""
product = self.get_object()

Expand Down
73 changes: 62 additions & 11 deletions product_portfolio/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
# See https://aboutcode.org for more information about AboutCode FOSS projects.
#

import json

from django import forms
from django.core.exceptions import ValidationError
from django.db import transaction
Expand Down Expand Up @@ -41,6 +43,7 @@
from dje.forms import Group
from dje.forms import JSONListField
from dje.forms import OwnerChoiceField
from dje.forms import StrictSubmit
from dje.forms import autocomplete_placeholder
from dje.mass_update import DejacodeMassUpdateForm
from dje.models import History
Expand Down Expand Up @@ -535,9 +538,12 @@ class Meta(BaseAddToProductForm.Meta):


class ImportFromScanForm(forms.Form):
upload_file = SmartFileField(extensions=["json"])
upload_file = SmartFileField(
label=_("Scan results JSON file"),
extensions=["json"],
)
create_codebase_resources = forms.BooleanField(
label=_('Create Codebase Resources (from <code>"files"</code>)'),
label=_('Create Codebase Resources (from "files" resources)'),
required=False,
initial=False,
help_text=_(
Expand Down Expand Up @@ -566,7 +572,16 @@ def __init__(self, user, *args, **kwargs):
@property
def helper(self):
helper = FormHelper()
helper.add_input(Submit("import", "Import"))
helper.attrs = {"autocomplete": "off"}
helper.layout = Layout(
Fieldset(
None,
"upload_file",
"create_codebase_resources",
"stop_on_error",
StrictSubmit("submit", _("Import"), css_class="btn-success col-2"),
),
)
return helper

def save(self, product):
Expand Down Expand Up @@ -597,7 +612,6 @@ def save(self, product):

class BaseProductImportFormView(forms.Form):
project_type = None
input_label = ""

input_file = SmartFileField(
label=_("file or zip archive"),
Expand Down Expand Up @@ -626,17 +640,21 @@ class BaseProductImportFormView(forms.Form):
),
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields["input_file"].label = _(f"{self.input_label} file or zip archive")

@property
def helper(self):
helper = FormHelper()
helper.form_method = "post"
helper.form_id = "import-manifest-form"
helper.attrs = {"autocomplete": "off"}
helper.add_input(Submit("submit", "Load Packages", css_class="btn-success"))
helper.layout = Layout(
Fieldset(
None,
"input_file",
"update_existing_packages",
"scan_all_packages",
StrictSubmit("submit", _("Import"), css_class="btn-success col-2"),
),
)
return helper

def submit(self, product, user):
Expand All @@ -659,17 +677,50 @@ def submit(self, product, user):
)


def validate_sbom_file(value):
"""Validate SBOM JSON file content."""
filename = value.name.lower()
if not filename.endswith(".json"):
return

try:
file_content = value.read().decode("utf-8")
json_data = json.loads(file_content)
except (json.JSONDecodeError, UnicodeDecodeError):
raise ValidationError(_("Invalid JSON file. Please provide a properly formatted JSON."))
finally:
value.seek(0) # Reset file pointer after reading

if headers := json_data.get("headers", []):
tool_name = headers[0].get("tool_name", "")
if "scan" in tool_name.lower():
raise ValidationError(
"Your file appears to be a ScanCode scan results. "
'You want to use the "Import ScanCode scan results" action instead.'
)


class LoadSBOMsForm(BaseProductImportFormView):
project_type = ScanCodeProject.ProjectType.LOAD_SBOMS
input_label = "SBOM"
pipeline_name = "load_sbom"

input_file = SmartFileField(
label=_("SBOM file or zip archive"),
extensions=["json", "ABOUT", "zip"],
validators=[validate_sbom_file],
required=True,
)


class ImportManifestsForm(BaseProductImportFormView):
project_type = ScanCodeProject.ProjectType.IMPORT_FROM_MANIFEST
input_label = "Manifest"
pipeline_name = "resolve_dependencies"

input_file = SmartFileField(
label=_("Manifest file or zip archive"),
required=True,
)


class StrongTextWidget(forms.Widget):
def render(self, name, value, attrs=None, renderer=None):
Expand Down
Loading