Skip to content

Commit 0366b40

Browse files
authored
CM-29953 - Scanning many paths in one CLI run (#183)
1 parent 16bc696 commit 0366b40

File tree

7 files changed

+50
-33
lines changed

7 files changed

+50
-33
lines changed

cycode/cli/commands/report/sbom/path/path_command.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from cycode.cli import consts
66
from cycode.cli.commands.report.sbom.common import create_sbom_report, send_report_feedback
77
from cycode.cli.exceptions.handle_report_sbom_errors import handle_report_exception
8-
from cycode.cli.files_collector.path_documents import get_relevant_document
8+
from cycode.cli.files_collector.path_documents import get_relevant_documents
99
from cycode.cli.files_collector.sca.sca_code_scanner import perform_pre_scan_documents_actions
1010
from cycode.cli.files_collector.zip_documents import zip_documents
1111
from cycode.cli.utils.get_api_client import get_report_cycode_client
@@ -28,8 +28,8 @@ def path_command(context: click.Context, path: str) -> None:
2828
report_execution_id = -1
2929

3030
try:
31-
documents = get_relevant_document(
32-
progress_bar, SbomReportProgressBarSection.PREPARE_LOCAL_FILES, consts.SCA_SCAN_TYPE, path
31+
documents = get_relevant_documents(
32+
progress_bar, SbomReportProgressBarSection.PREPARE_LOCAL_FILES, consts.SCA_SCAN_TYPE, (path,)
3333
)
3434
# TODO(MarshalX): combine perform_pre_scan_documents_actions with get_relevant_document.
3535
# unhardcode usage of context in perform_pre_scan_documents_actions

cycode/cli/commands/scan/code_scanner.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from cycode.cli.exceptions.handle_scan_errors import handle_scan_exception
1717
from cycode.cli.files_collector.excluder import exclude_irrelevant_documents_to_scan
1818
from cycode.cli.files_collector.models.in_memory_zip import InMemoryZip
19-
from cycode.cli.files_collector.path_documents import get_relevant_document
19+
from cycode.cli.files_collector.path_documents import get_relevant_documents
2020
from cycode.cli.files_collector.repository_documents import (
2121
get_commit_range_modified_documents,
2222
get_diff_file_path,
@@ -68,7 +68,7 @@ def scan_sca_commit_range(context: click.Context, path: str, commit_range: str)
6868
scan_type = context.obj['scan_type']
6969
progress_bar = context.obj['progress_bar']
7070

71-
scan_parameters = get_scan_parameters(context, path)
71+
scan_parameters = get_scan_parameters(context, (path,))
7272
from_commit_rev, to_commit_rev = parse_commit_range(commit_range, path)
7373
from_commit_documents, to_commit_documents = get_commit_range_modified_documents(
7474
progress_bar, ScanProgressBarSection.PREPARE_LOCAL_FILES, path, from_commit_rev, to_commit_rev
@@ -82,13 +82,13 @@ def scan_sca_commit_range(context: click.Context, path: str, commit_range: str)
8282
scan_commit_range_documents(context, from_commit_documents, to_commit_documents, scan_parameters=scan_parameters)
8383

8484

85-
def scan_disk_files(context: click.Context, path: str) -> None:
86-
scan_parameters = get_scan_parameters(context, path)
85+
def scan_disk_files(context: click.Context, paths: Tuple[str]) -> None:
86+
scan_parameters = get_scan_parameters(context, paths)
8787
scan_type = context.obj['scan_type']
8888
progress_bar = context.obj['progress_bar']
8989

9090
try:
91-
documents = get_relevant_document(progress_bar, ScanProgressBarSection.PREPARE_LOCAL_FILES, scan_type, path)
91+
documents = get_relevant_documents(progress_bar, ScanProgressBarSection.PREPARE_LOCAL_FILES, scan_type, paths)
9292
perform_pre_scan_documents_actions(context, scan_type, documents)
9393
scan_documents(context, documents, scan_parameters=scan_parameters)
9494
except Exception as e:
@@ -535,22 +535,31 @@ def get_default_scan_parameters(context: click.Context) -> dict:
535535
}
536536

537537

538-
def get_scan_parameters(context: click.Context, path: str) -> dict:
538+
def get_scan_parameters(context: click.Context, paths: Tuple[str]) -> dict:
539539
scan_parameters = get_default_scan_parameters(context)
540-
remote_url = try_get_git_remote_url(path)
540+
541+
if len(paths) != 1:
542+
# ignore remote url if multiple paths are provided
543+
return scan_parameters
544+
545+
remote_url = try_get_git_remote_url(paths[0])
541546
if remote_url:
542-
# TODO(MarshalX): remove hardcode
547+
# TODO(MarshalX): remove hardcode in context
543548
context.obj['remote_url'] = remote_url
544-
scan_parameters.update(remote_url)
549+
scan_parameters.update(
550+
{
551+
'remote_url': remote_url,
552+
}
553+
)
554+
545555
return scan_parameters
546556

547557

548-
def try_get_git_remote_url(path: str) -> Optional[dict]:
558+
def try_get_git_remote_url(path: str) -> Optional[str]:
549559
try:
550-
git_remote_url = Repo(path).remotes[0].config_reader.get('url')
551-
return {
552-
'remote_url': git_remote_url,
553-
}
560+
remote_url = Repo(path).remotes[0].config_reader.get('url')
561+
logger.debug(f'Found Git remote URL "{remote_url}" in path "{path}"')
562+
return remote_url
554563
except Exception as e:
555564
logger.debug('Failed to get git remote URL. %s', {'exception_message': str(e)})
556565
return None
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
from typing import Tuple
2+
13
import click
24

35
from cycode.cli.commands.scan.code_scanner import scan_disk_files
46
from cycode.cyclient import logger
57

68

79
@click.command(short_help='Scan the files in the path provided in the command.')
8-
@click.argument('path', nargs=1, type=click.Path(exists=True, resolve_path=True), required=True)
10+
@click.argument('paths', nargs=-1, type=click.Path(exists=True, resolve_path=True), required=True)
911
@click.pass_context
10-
def path_command(context: click.Context, path: str) -> None:
12+
def path_command(context: click.Context, paths: Tuple[str]) -> None:
1113
progress_bar = context.obj['progress_bar']
1214
progress_bar.start()
1315

14-
logger.debug('Starting path scan process, %s', {'path': path})
15-
scan_disk_files(context, path)
16+
logger.debug('Starting path scan process, %s', {'paths': paths})
17+
scan_disk_files(context, paths)

cycode/cli/commands/scan/repository/repisotiry_command.py renamed to cycode/cli/commands/scan/repository/repository_command.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
required=False,
2626
)
2727
@click.pass_context
28-
def repisotiry_command(context: click.Context, path: str, branch: str) -> None:
28+
def repository_command(context: click.Context, path: str, branch: str) -> None:
2929
try:
3030
logger.debug('Starting repository scan process, %s', {'path': path, 'branch': branch})
3131

@@ -54,7 +54,7 @@ def repisotiry_command(context: click.Context, path: str, branch: str) -> None:
5454

5555
logger.debug('Found all relevant files for scanning %s', {'path': path, 'branch': branch})
5656
scan_documents(
57-
context, documents_to_scan, is_git_diff=False, scan_parameters=get_scan_parameters(context, path)
57+
context, documents_to_scan, is_git_diff=False, scan_parameters=get_scan_parameters(context, (path,))
5858
)
5959
except Exception as e:
6060
handle_scan_exception(context, e)

cycode/cli/commands/scan/scan_ci/scan_ci_command.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
from cycode.cli.commands.scan.code_scanner import scan_commit_range
66
from cycode.cli.commands.scan.scan_ci.ci_integrations import get_commit_range
77

8+
# This command is not finished yet. It is not used in the codebase.
9+
810

911
@click.command(
1012
short_help='Execute scan in a CI environment which relies on the '

cycode/cli/commands/scan/scan_command.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from cycode.cli.commands.scan.path.path_command import path_command
88
from cycode.cli.commands.scan.pre_commit.pre_commit_command import pre_commit_command
99
from cycode.cli.commands.scan.pre_receive.pre_receive_command import pre_receive_command
10-
from cycode.cli.commands.scan.repository.repisotiry_command import repisotiry_command
10+
from cycode.cli.commands.scan.repository.repository_command import repository_command
1111
from cycode.cli.config import config
1212
from cycode.cli.consts import (
1313
ISSUE_DETECTED_STATUS_CODE,
@@ -21,14 +21,14 @@
2121

2222
@click.group(
2323
commands={
24-
'repository': repisotiry_command,
24+
'repository': repository_command,
2525
'commit_history': commit_history_command,
2626
'path': path_command,
2727
'pre_commit': pre_commit_command,
2828
'pre_receive': pre_receive_command,
2929
},
3030
short_help='Scan the content for Secrets/IaC/SCA/SAST violations. '
31-
'You`ll need to specify which scan type to perform: ci/commit_history/path/repository/etc.',
31+
'You`ll need to specify which scan type to perform: commit_history/path/repository/etc.',
3232
)
3333
@click.option(
3434
'--scan-type',

cycode/cli/files_collector/path_documents.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import os
2-
from typing import TYPE_CHECKING, Iterable, List
2+
from typing import TYPE_CHECKING, Iterable, List, Tuple
33

44
import pathspec
55

@@ -48,9 +48,13 @@ def _get_relevant_files_in_path(path: str, exclude_patterns: Iterable[str]) -> L
4848

4949

5050
def _get_relevant_files(
51-
progress_bar: 'BaseProgressBar', progress_bar_section: 'ProgressBarSection', scan_type: str, path: str
51+
progress_bar: 'BaseProgressBar', progress_bar_section: 'ProgressBarSection', scan_type: str, paths: Tuple[str]
5252
) -> List[str]:
53-
all_files_to_scan = _get_relevant_files_in_path(path=path, exclude_patterns=['**/.git/**', '**/.cycode/**'])
53+
all_files_to_scan = []
54+
for path in paths:
55+
all_files_to_scan.extend(
56+
_get_relevant_files_in_path(path=path, exclude_patterns=['**/.git/**', '**/.cycode/**'])
57+
)
5458

5559
# we are double the progress bar section length because we are going to process the files twice
5660
# first time to get the file list with respect of excluded patterns (excluding takes seconds to execute)
@@ -70,7 +74,7 @@ def _get_relevant_files(
7074
progress_bar.set_section_length(progress_bar_section, progress_bar_section_len)
7175

7276
logger.debug(
73-
'Found all relevant files for scanning %s', {'path': path, 'file_to_scan_count': len(relevant_files_to_scan)}
77+
'Found all relevant files for scanning %s', {'paths': paths, 'file_to_scan_count': len(relevant_files_to_scan)}
7478
)
7579

7680
return relevant_files_to_scan
@@ -89,15 +93,15 @@ def _handle_tfplan_file(file: str, content: str, is_git_diff: bool) -> Document:
8993
return Document(document_name, tf_content, is_git_diff)
9094

9195

92-
def get_relevant_document(
96+
def get_relevant_documents(
9397
progress_bar: 'BaseProgressBar',
9498
progress_bar_section: 'ProgressBarSection',
9599
scan_type: str,
96-
path: str,
100+
paths: Tuple[str],
97101
*,
98102
is_git_diff: bool = False,
99103
) -> List[Document]:
100-
relevant_files = _get_relevant_files(progress_bar, progress_bar_section, scan_type, path)
104+
relevant_files = _get_relevant_files(progress_bar, progress_bar_section, scan_type, paths)
101105

102106
documents: List[Document] = []
103107
for file in relevant_files:

0 commit comments

Comments
 (0)