Skip to content

Conversation

Alex-1089
Copy link
Contributor

@Alex-1089 Alex-1089 commented Aug 19, 2025

Empty results file no longer errors out during conversion, instead generates a minimal structure

Summary by CodeRabbit

  • Bug Fixes

    • Prevent errors on empty scan results: produce header-only CSV, minimal CycloneDX SBOM, and minimal SPDX Lite document; improved handling for empty SBOM exports.
    • More robust timestamp handling in Dependency-Track checks; gracefully handle missing API responses and empty violation lists.
  • Documentation

    • Changelog updated with 1.31.3 entry and reference link.
  • Chores

    • Package version bumped to 1.31.3; base image updated to a newer Python slim variant.

@Alex-1089 Alex-1089 requested a review from eeisegn August 19, 2025 11:06
@Alex-1089 Alex-1089 self-assigned this Aug 19, 2025
Copy link

coderabbitai bot commented Aug 19, 2025

Walkthrough

Distinguishes None vs empty results across CSV, CycloneDX, SPDX Lite, and DependencyTrack paths. Empty inputs now yield header-only or minimal artifacts instead of hard errors; None continues to error. Project-violation logic adds robust timestamp parsing and guards. Package version bumped to 1.31.3.

Changes

Cohort / File(s) Summary
Release metadata
CHANGELOG.md, src/scanoss/__init__.py
Added 1.31.3 changelog entry and comparison link; bumped __version__ to 1.31.3.
CSV empty-handling
src/scanoss/csvoutput.py
parse: explicit None check -> error; empty list returns [] with warning. produce_from_json: None → failure; empty CSV data produces header-only CSV.
CycloneDX empty-handling
src/scanoss/cyclonedx.py
parse: None(None,None) error; empty dict → ({},{}) warning. produce_from_json: cdx is None(False,{}); empty cdx → generate minimal SBOM (no components) and continue.
SPDX Lite empty-handling
src/scanoss/spdxlite.py
parse: None → error; empty → {} with debug warning. produce_from_json: NoneFalse; empty → generate minimal SPDX Lite document (no packages).
DependencyTrack exporter
src/scanoss/export/dependency_track.py
_encode_sbom early-returns empty string for empty SBOM and logs notice when components is empty; otherwise JSON+base64 encoding unchanged.
DependencyTrack project violation checks
src/scanoss/inspection/dependency_track/project_violation.py
Added _safe_timestamp helper to robustly parse timestamps with warnings; guard returns False when any key timestamp is zero; run returns PolicyStatus.ERROR if fetched violations are None.
DependencyTrack service comment
src/scanoss/services/dependency_track_service.py
Clarifying comment: None denotes API failure vs empty list for no violations; no functional changes.
Docker base image
Dockerfile
Base image tag updated from python:3.10-slim to python:3.10-slim-bookworm.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Producer as CycloneDXProducer
  participant Parser as CycloneDXParser
  participant Builder as SBOMBuilder

  User->>Producer: produce_from_json(data, output_file?)
  Producer->>Parser: parse(data)
  alt data is None
    Parser-->>Producer: cdx=None, vulns=None
    Producer-->>User: (False, {}) with error logged
  else data is empty
    Parser-->>Producer: cdx={}, vulns={}
    Note over Producer,Builder: Empty results → minimal SBOM (no components)
    Producer->>Builder: build minimal SBOM
    Builder-->>Producer: SBOM object
    Producer-->>User: (True, component_dict={})
  else data has content
    Parser-->>Producer: cdx=..., vulns=...
    Producer->>Builder: build full SBOM
    Builder-->>Producer: SBOM object
    Producer-->>User: (True, component_dict)
  end
Loading
sequenceDiagram
  autonumber
  participant Exp as DependencyTrackExporter
  participant Enc as _encode_sbom

  Exp->>Enc: encode(sbom_content)
  alt sbom_content is None or {}
    Enc-->>Exp: "" (warning: empty SBOM)
  else components == []
    Note right of Enc: Notice: SBOM contains no components (empty results)
    Enc-->>Exp: base64(JSON(SBOM))
  else
    Enc-->>Exp: base64(JSON(SBOM))
  end
Loading
sequenceDiagram
  autonumber
  participant PV as ProjectViolation
  participant DT as DependencyTrack API

  PV->>DT: get_project_violations(project)
  DT-->>PV: violations or None
  alt response is None
    PV-->>PV: return PolicyStatus.ERROR
  else
    PV->>PV: _safe_timestamp(import/analysis/occurrence)
    alt any timestamp == 0
      PV-->>PV: Not updated (incomplete processing) → return False
    else
      PV-->>PV: Updated if analysis>=import AND occurrence>=import
    end
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

bug

Suggested reviewers

  • agustingroh
  • eeisegn

Poem

A nibble of nothing, a basket of null—
I thump out warnings, but never a lull.
Empty files get headers, SBOMs get a shell,
Timestamps checked, timestamps well.
Version bumped, rabbit hops—release looks swell. 🐇✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/alex/SP-3078_empty-results-handling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

SCANOSS SCAN Completed 🚀

  • Detected components: 1
  • Undeclared components: 0
  • Declared components: 1
  • Detected files: 84
  • Detected files undeclared: 0
  • Detected files declared: 84
  • Licenses detected: 1
  • Licenses detected with copyleft: 0
  • Policies: ✅ 1 pass (1 total)

View more details on SCANOSS Action Summary

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
CHANGELOG.md (1)

645-646: Fix duplicate/broken link reference for 1.31.3

You’re redefining the 1.31.2 link and pointing it to the 1.31.3 compare URL. This triggers markdownlint MD053 and breaks the link set.

Apply this diff:

-[1.31.2]: https://github.com/scanoss/scanoss.py/compare/v1.31.2...v1.31.3
+[1.31.3]: https://github.com/scanoss/scanoss.py/compare/v1.31.2...v1.31.3
🧹 Nitpick comments (10)
src/scanoss/services/dependency_track_service.py (1)

100-101: Clarifying comment is helpful — no functional change

Returning the API response as-is with None vs empty list clearly documented. Consider aligning PE8 type-hint spacing in this function signature in a follow-up (e.g., def get_project_violations(self, project_id: str):).

src/scanoss/csvoutput.py (5)

53-59: None vs empty handling is correct; fix f-string lint

The explicit None vs len(data) == 0 handling is spot on. Line 59 uses an f-string without placeholders, triggering F541.

Apply this diff:

-        self.print_debug(f'Processing raw results into CSV format...')
+        self.print_debug('Processing raw results into CSV format...')

25-30: Sort imports to fix isort/flake8 (I001)

Reorder stdlib imports alphabetically.

-import json
-import os.path
-import sys
-import csv
+import csv
+import json
+import os.path
+import sys

214-214: Open CSV output with newline='' to avoid extra blank lines on Windows

Python’s csv writer recommends newline='' when opening files.

-        if output_file:
-            file = open(output_file, 'w')
+        if output_file:
+            file = open(output_file, 'w', newline='')

76-83: Break long log lines to satisfy E501

Some warnings likely exceed 120 chars. Wrap the calls for readability and to satisfy the linter.

-                        self.print_stderr(f'Warning: No Dependencies found for {f}: {file_details}')
+                        self.print_stderr(
+                            f'Warning: No Dependencies found for {f}: {file_details}'
+                        )
@@
-                        self.print_stderr(f'Warning: Purl block missing for {f}: {file_details}')
+                        self.print_stderr(
+                            f'Warning: Purl block missing for {f}: {file_details}'
+                        )
@@
-                        self.print_stderr(f'Warning: No PURL found for {f}: {file_details}')
+                        self.print_stderr(
+                            f'Warning: No PURL found for {f}: {file_details}'
+                        )

Also applies to: 120-128


47-162: Function is too large/branchy; consider extraction for maintainability (PLR0912/PLR0915)

The parse method mixes traversal, normalization, and row construction with many branches. Consider extracting helpers (e.g., _rows_from_dependency_entry(...), _rows_from_file_entry(...)) to reduce complexity and improve testability. No need to block this PR; can be a follow-up.

Do you want me to sketch a refactor patch that splits parse into helpers?

src/scanoss/cyclonedx.py (2)

60-66: Good separation of None vs empty input; consider a defensive type check.

The new handling correctly treats None as an error and empty dict as a minimal/empty output path. To avoid a potential TypeError if a non-mapping is passed (e.g., list), consider guarding with isinstance(data, dict) before len(data).

-        if len(data) == 0:
+        if not isinstance(data, dict):
+            self.print_stderr('ERROR: Invalid JSON type provided. Expected an object/dict.')
+            return None, None
+        if len(data) == 0:

195-197: Nice minimal-SBOM path for empty results. Add a unit test to lock behavior.

Recommend adding a test asserting that {} input yields True and a minimal, valid CycloneDX document with empty components/vulnerabilities.

Would you like me to scaffold a pytest covering this scenario (including stdout/file emission)?

src/scanoss/inspection/dependency_track/project_violation.py (2)

256-260: Comment and logic mismatch: update the comment to reflect OR condition.

The code returns False if any timestamp is zero, but the comment says “all timestamps are zero”.

-        # If all timestamps are zero, this indicates no processing has occurred
+        # If any timestamp is zero, this indicates processing is incomplete

385-391: Header style inconsistency for None-results branch in Markdown generator.

You return “h3.” (Jira style) here, while the non-None path uses “### ” (Markdown). Since this function serves both _markdown and _jira_markdown, consider using a consistent header or deriving it from the table_generator/format_type to avoid mixed renderings.

-            return {
-                "details": "h3. Dependency Track Project Violations\n\nNo policy violations found.\n",
+            return {
+                "details": "### Dependency Track Project Violations\n\nNo policy violations found.\n",
                 "summary": "0 policy violations were found.\n",
             }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between fdc02af and f1ebbed.

📒 Files selected for processing (7)
  • CHANGELOG.md (2 hunks)
  • src/scanoss/csvoutput.py (2 hunks)
  • src/scanoss/cyclonedx.py (2 hunks)
  • src/scanoss/export/dependency_track.py (1 hunks)
  • src/scanoss/inspection/dependency_track/project_violation.py (2 hunks)
  • src/scanoss/services/dependency_track_service.py (1 hunks)
  • src/scanoss/spdxlite.py (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (5)
src/scanoss/spdxlite.py (2)
src/scanoss/cli.py (1)
  • print_stderr (86-90)
src/scanoss/scanossbase.py (2)
  • print_stderr (45-49)
  • print_debug (58-63)
src/scanoss/export/dependency_track.py (3)
src/scanoss/spdxlite.py (1)
  • print_stderr (55-59)
src/scanoss/cli.py (1)
  • print_stderr (86-90)
src/scanoss/scanossbase.py (1)
  • print_msg (51-56)
src/scanoss/cyclonedx.py (1)
src/scanoss/scanossbase.py (2)
  • print_stderr (45-49)
  • print_msg (51-56)
src/scanoss/csvoutput.py (1)
src/scanoss/scanossbase.py (2)
  • print_stderr (45-49)
  • print_msg (51-56)
src/scanoss/inspection/dependency_track/project_violation.py (4)
src/scanoss/spdxlite.py (1)
  • print_stderr (55-59)
src/scanoss/cli.py (1)
  • print_stderr (86-90)
src/scanoss/scanossbase.py (1)
  • print_msg (51-56)
src/scanoss/inspection/policy_check.py (2)
  • PolicyStatus (33-44)
  • _get_formatter (182-197)
🪛 LanguageTool
CHANGELOG.md

[grammar] ~12-~12: There might be a mistake here.
Context: ...ing changes... ## [1.31.3] - 2025-08-19 ### Fixed - Added handling for empty results...

(QB_NEW_EN)


[grammar] ~13-~13: There might be a mistake here.
Context: ...s... ## [1.31.3] - 2025-08-19 ### Fixed - Added handling for empty results files ...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
CHANGELOG.md

645-645: Link and image reference definitions should be needed
Duplicate link or image reference definition: "1.31.2"

(MD053, link-image-reference-definitions)

🪛 GitHub Actions: Lint
src/scanoss/csvoutput.py

[error] 25-30: I001 Import block is unsorted or unformatted.


[error] 47-47: PLR0912 Too many branches (25 > 12)


[error] 47-47: PLR0915 Too many statements (65 > 50)


[error] 59-59: F541 f-string without any placeholders


[error] 98-98: E501 Line too long (123 > 120)

src/scanoss/inspection/dependency_track/project_violation.py

[error] 246-246: E501 Line too long (130 > 120)


[error] 248-248: E501 Line too long (132 > 120)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (7)
CHANGELOG.md (1)

12-15: Release note looks good and matches PR intent

Entry clearly communicates the fix for empty results handling.

src/scanoss/csvoutput.py (1)

188-194: Good: header-only CSV on empty input

This produces a usable CSV with headers and zero rows when results are empty, matching the PR objective.

src/scanoss/spdxlite.py (2)

74-80: Correct None vs empty handling

Returning None for missing data and an empty dict for empty results is consistent with downstream behavior.


282-288: Minimal SPDX on empty input — aligns with PR goal

Proceeding to build a minimal SPDX Lite document when raw_data is empty achieves the “no error on empty” goal.

src/scanoss/cyclonedx.py (1)

192-196: No downstream None checks on CycloneDX output—safe to return {}
All callers of produce_from_json only inspect the Boolean success flag or ignore the second return value. None perform is None or == None checks on the JSON output, so switching from None to {} poses no risk.

src/scanoss/inspection/dependency_track/project_violation.py (2)

234-245: Robust timestamp normalization is a solid improvement.

Local helper cleanly handles string/numeric timestamps and logs on invalid values. This should reduce runtime errors from API variances.


451-454: Graceful handling of None from service layer is spot on.

Differentiating None (API error) from [] (no violations) aligns well with the rest of the PR’s semantics.

Comment on lines 120 to +126
if not sbom_content:
self.print_stderr('Warning: Empty SBOM content')
self.print_stderr('Warning: Empty SBOM content provided')
return ''
# Check if SBOM has no components (empty scan results)
components = sbom_content.get('components', [])
if len(components) == 0:
self.print_msg('Notice: SBOM contains no components (empty scan results)')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Don’t upload an empty BOM to Dependency Track

When sbom_content is falsy, _encode_sbom returns an empty string. The caller (upload_sbom_contents) will still build a payload and attempt the upload, which is likely to be rejected by the API.

Add a guard in upload_sbom_contents to skip the upload if encoding produced an empty string.

@@
-            self.print_debug('Encoding SBOM to base64')
-            payload = _build_payload(self._encode_sbom(sbom_content), project_id, project_name, project_version)
+            self.print_debug('Encoding SBOM to base64')
+            encoded_bom = self._encode_sbom(sbom_content)
+            if not encoded_bom:
+                self.print_msg('Empty SBOM content detected. Skipping upload to Dependency Track.')
+                return False
+            payload = _build_payload(encoded_bom, project_id, project_name, project_version)

🏁 Script executed:

#!/bin/bash
# Locate the upload_sbom_contents method and inspect its implementation
rg -nP "def upload_sbom_contents" -C10 src/scanoss/export/dependency_track.py

# Confirm where and how _encode_sbom is invoked within that method
rg -nP "_encode_sbom" -C10 src/scanoss/export/dependency_track.py

Length of output: 3311


Add guard to skip upload when SBOM encoding yields an empty string

To prevent attempting to send an empty BOM payload (which the API will reject), update upload_sbom_contents in src/scanoss/export/dependency_track.py as follows:

• File: src/scanoss/export/dependency_track.py
• Method: upload_sbom_contents (around line 186)

@@ -186,7 +186,12 @@
             self.print_debug('Encoding SBOM to base64')
-            payload = _build_payload(self._encode_sbom(sbom_content), project_id, project_name, project_version)
+            # Skip sending if SBOM content is empty or invalid
+            encoded_bom = self._encode_sbom(sbom_content)
+            if not encoded_bom:
+                self.print_msg('Empty SBOM content detected. Skipping upload to Dependency Track.')
+                return False
+            payload = _build_payload(encoded_bom, project_id, project_name, project_version)
 
             url = f'{self.url}/api/v1/bom'
             headers = {'Content-Type': 'application/json', 'X-Api-Key': self.apikey}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if not sbom_content:
self.print_stderr('Warning: Empty SBOM content')
self.print_stderr('Warning: Empty SBOM content provided')
return ''
# Check if SBOM has no components (empty scan results)
components = sbom_content.get('components', [])
if len(components) == 0:
self.print_msg('Notice: SBOM contains no components (empty scan results)')
self.print_debug('Encoding SBOM to base64')
# Skip sending if SBOM content is empty or invalid
encoded_bom = self._encode_sbom(sbom_content)
if not encoded_bom:
self.print_msg('Empty SBOM content detected. Skipping upload to Dependency Track.')
return False
payload = _build_payload(encoded_bom, project_id, project_name, project_version)
url = f'{self.url}/api/v1/bom'
headers = {'Content-Type': 'application/json', 'X-Api-Key': self.apikey}
🤖 Prompt for AI Agents
In src/scanoss/export/dependency_track.py around lines 120-126 (and adjust in
upload_sbom_contents near line ~186), add a guard that prevents attempting to
upload when SBOM encoding results in an empty string: after encoding/serializing
the SBOM (the variable that becomes the payload), check if the encoded_payload
is falsy or empty and if so log/print a warning/notice and return early without
calling the upload API; ensure the function returns an empty string or
appropriate sentinel consistent with existing returns and does not proceed to
send the empty BOM to the API.

Copy link

SCANOSS SCAN Completed 🚀

  • Detected components: 1
  • Undeclared components: 0
  • Declared components: 1
  • Detected files: 83
  • Detected files undeclared: 0
  • Detected files declared: 83
  • Licenses detected: 1
  • Licenses detected with copyleft: 0
  • Policies: ✅ 1 pass (1 total)

View more details on SCANOSS Action Summary

Copy link

SCANOSS SCAN Completed 🚀

  • Detected components: 1
  • Undeclared components: 0
  • Declared components: 1
  • Detected files: 83
  • Detected files undeclared: 0
  • Detected files declared: 83
  • Licenses detected: 1
  • Licenses detected with copyleft: 0
  • Policies: ✅ 1 pass (1 total)

View more details on SCANOSS Action Summary

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
src/scanoss/inspection/dependency_track/project_violation.py (4)

216-221: Docstring contradicts implementation (AND vs OR) — update wording

The implementation requires both timestamps to be >= last import, but the docstring says "either". Align the docstring with the logic.

-        occurrence metrics. A project is considered updated when either the
-        vulnerability analysis or the metrics' last occurrence timestamp is greater
-        than or equal to the last BOM import timestamp.
+        occurrence metrics. A project is considered updated when both the
+        vulnerability analysis and the metrics' last occurrence timestamp are
+        greater than or equal to the last BOM import timestamp.

260-263: Comment says “all” but condition checks “any” — fix the comment

The guard returns False if any of the timestamps are zero. Adjust the comment to avoid confusion.

-        # If all timestamps are zero, this indicates no processing has occurred
+        # If any timestamp is zero, this indicates processing has not fully occurred

269-273: _wait_processing_by_project_id docstring return clause is inaccurate on timeout

On timeout, the function returns the latest dt_project, not None. Update the docstring to match behavior.

-        """
-                Wait for project processing to complete in Dependency Track.
-
-                Returns:
-                    Return the project or None if processing fails or times out
-        """
+        """
+                Wait for project processing to complete in Dependency Track.
+
+                Returns:
+                    The project if available. Returns None if retrieval fails; on timeout, returns the latest project payload.
+        """

455-465: Add a type guard for unexpected payloads to avoid runtime errors

If the service ever returns a non-list payload (e.g., an error dict), sorting will fail. A quick type check will harden this path.

         dt_project_violations = self.dep_track_service.get_project_violations(self.project_id)
         # Handle case where service returns None (API error) vs empty list (no violations)
         if dt_project_violations is None:
             self.print_stderr('Error: Failed to retrieve project violations from Dependency Track')
             return PolicyStatus.ERROR.value
+        if not isinstance(dt_project_violations, list):
+            self.print_stderr(f'Error: Unexpected violations payload type: {type(dt_project_violations).__name__}')
+            return PolicyStatus.ERROR.value
         # Sort violations by priority and format output
         formatter = self._get_formatter()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f38f5af and f3b5282.

📒 Files selected for processing (1)
  • src/scanoss/inspection/dependency_track/project_violation.py (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/scanoss/inspection/dependency_track/project_violation.py (4)
src/scanoss/spdxlite.py (1)
  • print_stderr (55-59)
src/scanoss/cli.py (1)
  • print_stderr (86-90)
src/scanoss/scanossbase.py (1)
  • print_msg (51-56)
src/scanoss/inspection/policy_check.py (2)
  • PolicyStatus (33-44)
  • _get_formatter (182-197)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
src/scanoss/inspection/dependency_track/project_violation.py (2)

245-248: E501-long lines resolved for _safe_timestamp calls — LGTM

Splitting the long calls across lines fixes the linter errors without changing behavior. Good call.

Also applies to: 250-253


455-459: Graceful handling of None responses from the service — LGTM

Differentiating None (error) from an empty list (no violations) prevents hard failures and aligns with the PR goal.

Copy link

SCANOSS SCAN Completed 🚀

  • Detected components: 1
  • Undeclared components: 0
  • Declared components: 1
  • Detected files: 83
  • Detected files undeclared: 0
  • Detected files declared: 83
  • Licenses detected: 1
  • Licenses detected with copyleft: 0
  • Policies: ✅ 1 pass (1 total)

View more details on SCANOSS Action Summary

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
Dockerfile (4)

1-1: Multi-arch correctness: avoid using BUILDPLATFORM for runtime stages

Using BUILDPLATFORM for the shared base means all downstream stages (including runtime) inherit the build machine’s architecture. This can silently produce wrong-arch images when cross-building (e.g., building linux/arm64 on amd64 builders). Prefer BUILDPLATFORM only for builder stages and TARGETPLATFORM for runtime stages.

If you build multi-arch images with buildx, consider splitting the base:

-FROM --platform=$BUILDPLATFORM python:3.10-slim-bookworm AS base
+FROM --platform=$BUILDPLATFORM python:3.10-slim-bookworm AS build-base
+FROM --platform=$TARGETPLATFORM python:3.10-slim-bookworm AS run-base

And update stage usage:

-FROM base AS builder
+FROM build-base AS builder
-FROM base AS no_entry_point
+FROM run-base AS no_entry_point

This keeps native execution for builds while ensuring the final image matches the target arch. Please confirm your CI uses BuildKit/buildx and that cross-arch builds still produce correct-arch outputs with the current Dockerfile.

Also applies to: 9-9, 49-49


64-65: Pin Syft to a version (and optionally verify checksum) to improve supply-chain hygiene

Piping a moving install script from main to sh is brittle and can drift. Pin to a released version; optionally verify checksums.

Apply a minimal pin:

-RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin
+ARG SYFT_VERSION=v0.104.0
+RUN curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \
+  | sh -s -- -b /usr/local/bin ${SYFT_VERSION}

Or fetch a release tarball by arch (better for reproducibility):

# Example alternative (add after setting run-base)
ARG SYFT_VERSION=v0.104.0
RUN set -eux; \
    arch="$(dpkg --print-architecture)"; \
    curl -sSfL -o /tmp/syft.tgz \
      "https://github.com/anchore/syft/releases/download/${SYFT_VERSION}/syft_${SYFT_VERSION#v}_linux_${arch}.tar.gz"; \
    tar -xzf /tmp/syft.tgz -C /usr/local/bin syft; \
    rm /tmp/syft.tgz
# Optionally add sha256 verification for the tarball

33-41: Replace remote ADD with curl + pinned version (and optional checksum)

ADD with a remote URL reduces control over integrity and caching. Prefer an explicit curl with a pinned tag (and optionally a checksum) for reproducible builds.

-ADD https://github.com/nexB/typecode_libmagic_from_sources/archive/refs/tags/v5.39.210212.tar.gz /install/
-RUN tar -xvzf /install/v5.39.210212.tar.gz -C /install \
+ARG TYPECODE_SRC_VER=v5.39.210212
+RUN curl -sSfL -o /install/typecode.tar.gz \
+      "https://github.com/nexB/typecode_libmagic_from_sources/archive/refs/tags/${TYPECODE_SRC_VER}.tar.gz" \
+    && tar -xvzf /install/typecode.tar.gz -C /install \
     && cd /install/typecode_libmagic_from_sources* \
     && ./build.sh \
     && python3 setup.py sdist bdist_wheel \
     && ls /install/typecode_libmagic_from_sources*/dist/*.whl \
     && pip3 install --no-cache-dir `ls /install/typecode_libmagic_from_sources*/dist/*.whl`

If you can publish and reference official checksums for the tarball, add a sha256 verification step before extracting.


45-46: Avoid hardcoding the Python minor version in site-packages path

This will break if/when the base Python version changes. Compute the site-packages path dynamically.

-RUN rm -rf /opt/venv/lib/python3.10/site-packages/licensedcode/data/rules /opt/venv/lib/python3.10/site-packages/licensedcode/data/cache
-RUN mkdir  /opt/venv/lib/python3.10/site-packages/licensedcode/data/rules /opt/venv/lib/python3.10/site-packages/licensedcode/data/cache
+RUN py_site="$(python -c 'import site; print(site.getsitepackages()[0])')" \
+ && rm -rf "$py_site/licensedcode/data/rules" "$py_site/licensedcode/data/cache" \
+ && mkdir -p "$py_site/licensedcode/data/rules" "$py_site/licensedcode/data/cache"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f3b5282 and 25b8835.

📒 Files selected for processing (2)
  • Dockerfile (1 hunks)
  • src/scanoss/csvoutput.py (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/scanoss/csvoutput.py
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (2)
Dockerfile (2)

1-1: Bookworm base upgrade looks good

Switching to python:3.10-slim-bookworm aligns with Debian 12 and the later use of libicu72; this should reduce CVEs relative to bullseye and is consistent with the rest of the file.


58-61: libicu72 matches bookworm—good catch

Installing libicu72 is correct for Debian bookworm and aligns with the base image change.

@Alex-1089 Alex-1089 merged commit 3900859 into main Aug 19, 2025
6 checks passed
@Alex-1089 Alex-1089 deleted the feat/alex/SP-3078_empty-results-handling branch August 19, 2025 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants