Skip to content
Closed
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: 1 addition & 10 deletions scanpipe/management/commands/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,7 @@

from scanpipe.management.commands import ProjectCommand
from scanpipe.pipes import output

SUPPORTED_FORMATS = [
"json",
"csv",
"xlsx",
"attribution",
"spdx",
"cyclonedx",
"ort-package-list",
]
from scanpipe.pipes.output import SUPPORTED_FORMATS


class Command(ProjectCommand):
Expand Down
3 changes: 2 additions & 1 deletion scanpipe/management/commands/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

from scanpipe.management.commands import extract_tag_from_input_file
from scanpipe.pipes.fetch import SCHEME_TO_FETCHER_MAPPING
from scanpipe.pipes.output import PRINT_SUPPORTED_FORMATS


class Command(BaseCommand):
Expand Down Expand Up @@ -59,7 +60,7 @@ def add_arguments(self, parser):
parser.add_argument(
"--format",
default="json",
choices=["json", "spdx", "cyclonedx", "attribution", "ort-package-list"],
choices=PRINT_SUPPORTED_FORMATS,
help="Specifies the output serialization format for the results.",
)

Expand Down
21 changes: 21 additions & 0 deletions scanpipe/pipes/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,27 @@

scanpipe_app = apps.get_app_config("scanpipe")

# All formats supported by the `output` management command.
SUPPORTED_FORMATS = [
"json",
"csv",
"xlsx",
"attribution",
"spdx",
"cyclonedx",
"ort-package-list",
]

# Subset of formats compatible with stdout streaming (--print mode).
# Excludes binary formats (xlsx) and multi-file formats (csv).
PRINT_SUPPORTED_FORMATS = [
"json",
"spdx",
"cyclonedx",
"attribution",
"ort-package-list",
]


def safe_filename(filename):
"""Convert the provided `filename` to a safe filename."""
Expand Down
50 changes: 50 additions & 0 deletions scanpipe/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
from scanpipe.models import WebhookSubscription
from scanpipe.pipes import flag
from scanpipe.pipes import purldb
from scanpipe.pipes.output import PRINT_SUPPORTED_FORMATS
from scanpipe.pipes.output import SUPPORTED_FORMATS as PIPE_SUPPORTED_FORMATS
from scanpipe.tests import filter_warnings
from scanpipe.tests import make_dependency
from scanpipe.tests import make_mock_response
Expand Down Expand Up @@ -756,6 +758,29 @@ def test_scanpipe_management_command_output(self):
self.assertIn('"bomFormat": "CycloneDX"', out_value)
self.assertIn('"specVersion": "1.5",', out_value)

def test_supported_formats_sync(self):
"""
Ensure SUPPORTED_FORMATS in management/commands/output.py always matches
the canonical list in pipes/output.py, and that PRINT_SUPPORTED_FORMATS
is a strict subset of SUPPORTED_FORMATS (never includes csv or xlsx).
"""
from scanpipe.management.commands.output import SUPPORTED_FORMATS as CMD_FORMATS

self.assertEqual(
set(PIPE_SUPPORTED_FORMATS),
set(CMD_FORMATS),
"SUPPORTED_FORMATS in management/commands/output.py is out of sync "
"with pipes/output.py. Update one of them.",
)
# PRINT_SUPPORTED_FORMATS must be a subset of SUPPORTED_FORMATS
self.assertTrue(
set(PRINT_SUPPORTED_FORMATS).issubset(set(PIPE_SUPPORTED_FORMATS)),
"PRINT_SUPPORTED_FORMATS contains formats not in SUPPORTED_FORMATS.",
)
# csv and xlsx must never be in PRINT_SUPPORTED_FORMATS (--print incompatible)
self.assertNotIn("csv", PRINT_SUPPORTED_FORMATS)
self.assertNotIn("xlsx", PRINT_SUPPORTED_FORMATS)

def test_scanpipe_management_command_delete_project(self):
project = make_project(name="my_project")
work_path = project.work_path
Expand Down Expand Up @@ -984,6 +1009,31 @@ def test_scanpipe_management_command_run(self):
json_data = json.loads(out.getvalue())
self.assertEqual(3, len(json_data["files"]))

# Test --format spdx
out = StringIO()
with redirect_stdout(out):
call_command("run", "do_nothing", input_location, "--format", "spdx")
out_value = out.getvalue()
self.assertIn('"spdxVersion":', out_value)

# Test --format cyclonedx
out = StringIO()
with redirect_stdout(out):
call_command("run", "do_nothing", input_location, "--format", "cyclonedx")
out_value = out.getvalue()
self.assertIn('"bomFormat": "CycloneDX"', out_value)

# Test --format ort-package-list
# do_nothing pipeline doesn't find packages, so it generates an empty list, but it shouldn't crash
out = StringIO()
with redirect_stdout(out):
call_command("run", "do_nothing", input_location, "--format", "ort-package-list")

# Test incompatible streaming formats are rejected by argparse choices
expected = "Error: argument --format: invalid choice: 'csv'"
with self.assertRaisesMessage(CommandError, expected):
call_command("run", "do_nothing", input_location, "--format", "csv")

# Multiple pipeline and selected_groups are supported
out = StringIO()
with redirect_stdout(out):
Expand Down