cycode 0.2.5.dev6__tar.gz → 0.2.5.dev7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/PKG-INFO +7 -7
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/README.md +6 -6
- cycode-0.2.5.dev7/cycode/__init__.py +1 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/main.py +4 -4
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/printers/base_printer.py +3 -1
- cycode-0.2.5.dev7/cycode/cli/printers/base_table_printer.py +43 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/printers/console_printer.py +10 -6
- cycode-0.2.5.dev6/cycode/cli/printers/table_printer.py → cycode-0.2.5.dev7/cycode/cli/printers/sca_table_printer.py +4 -32
- cycode-0.2.5.dev7/cycode/cli/printers/table.py +61 -0
- cycode-0.2.5.dev7/cycode/cli/printers/table_models.py +20 -0
- cycode-0.2.5.dev7/cycode/cli/printers/table_printer.py +116 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/printers/text_printer.py +3 -10
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/string_utils.py +4 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/pyproject.toml +1 -1
- cycode-0.2.5.dev6/cycode/__init__.py +0 -1
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/auth/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/auth/auth_command.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/auth/auth_manager.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/ci_integrations.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/code_scanner.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/config.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/config.yaml +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/consts.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/exceptions/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/exceptions/custom_exceptions.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/base_restore_maven_dependencies.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/restore_gradle_dependencies.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/restore_maven_dependencies.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/sca_code_scanner.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/models.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/printers/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/printers/json_printer.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/base_file_manager.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/config_file_manager.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/configuration_manager.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/credentials_manager.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/user_settings/user_settings_commands.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/path_utils.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/scan_utils.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/shell_executor.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/task_timer.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/utils/yaml_utils.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/zip_file.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/auth_client.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/config.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/config.yaml +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/config_dev.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/cycode_client.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/cycode_client_base.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/cycode_dev_based_client.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/cycode_token_based_client.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/models.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/scan_client.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/scan_config/__init__.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/scan_config/scan_config_base.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/scan_config/scan_config_creator.py +0 -0
- {cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cyclient/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cycode
|
|
3
|
-
Version: 0.2.5.
|
|
3
|
+
Version: 0.2.5.dev7
|
|
4
4
|
Summary: Perform secrets/iac scans for your sources using Cycode's engine
|
|
5
5
|
Home-page: https://github.com/cycodehq-public/cycode-cli
|
|
6
6
|
License: MIT
|
|
@@ -248,12 +248,12 @@ repos:
|
|
|
248
248
|
|
|
249
249
|
The following are the options and commands available with the Cycode CLI application:
|
|
250
250
|
|
|
251
|
-
| Option
|
|
252
|
-
|
|
253
|
-
| `--output [text\|json]` | Specify the output (`text`/`json`). The default is `text` |
|
|
254
|
-
| `-v`, `--verbose`
|
|
255
|
-
| `--version`
|
|
256
|
-
| `--help`
|
|
251
|
+
| Option | Description |
|
|
252
|
+
|--------------------------------|-------------------------------------------------------------------|
|
|
253
|
+
| `--output [text\|json\|table]` | Specify the output (`text`/`json`/`table`). The default is `text` |
|
|
254
|
+
| `-v`, `--verbose` | Show detailed logs |
|
|
255
|
+
| `--version` | Show the version and exit. |
|
|
256
|
+
| `--help` | Show options for given command. |
|
|
257
257
|
|
|
258
258
|
| Command | Description |
|
|
259
259
|
|-------------------------------------|-------------|
|
|
@@ -211,12 +211,12 @@ repos:
|
|
|
211
211
|
|
|
212
212
|
The following are the options and commands available with the Cycode CLI application:
|
|
213
213
|
|
|
214
|
-
| Option
|
|
215
|
-
|
|
216
|
-
| `--output [text\|json]` | Specify the output (`text`/`json`). The default is `text` |
|
|
217
|
-
| `-v`, `--verbose`
|
|
218
|
-
| `--version`
|
|
219
|
-
| `--help`
|
|
214
|
+
| Option | Description |
|
|
215
|
+
|--------------------------------|-------------------------------------------------------------------|
|
|
216
|
+
| `--output [text\|json\|table]` | Specify the output (`text`/`json`/`table`). The default is `text` |
|
|
217
|
+
| `-v`, `--verbose` | Show detailed logs |
|
|
218
|
+
| `--version` | Show the version and exit. |
|
|
219
|
+
| `--help` | Show options for given command. |
|
|
220
220
|
|
|
221
221
|
| Command | Description |
|
|
222
222
|
|-------------------------------------|-------------|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.2.5.dev7' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
|
|
@@ -65,10 +65,10 @@ NO_ISSUES_STATUS_CODE = 0
|
|
|
65
65
|
@click.option('--output', default=None,
|
|
66
66
|
help="""
|
|
67
67
|
\b
|
|
68
|
-
Specify the results output (text/json),
|
|
68
|
+
Specify the results output (text/json/table),
|
|
69
69
|
the default is text
|
|
70
70
|
""",
|
|
71
|
-
type=click.Choice(['text', 'json']))
|
|
71
|
+
type=click.Choice(['text', 'json', 'table']))
|
|
72
72
|
@click.option('--severity-threshold',
|
|
73
73
|
default=None,
|
|
74
74
|
help='Show only violations at the specified level or higher (supported for SCA scan type only).',
|
|
@@ -142,8 +142,8 @@ def finalize(context: click.Context, *args, **kwargs):
|
|
|
142
142
|
@click.option(
|
|
143
143
|
'--output',
|
|
144
144
|
default='text',
|
|
145
|
-
help='Specify the output (text/json), the default is text',
|
|
146
|
-
type=click.Choice(['text', 'json'])
|
|
145
|
+
help='Specify the output (text/json/table), the default is text',
|
|
146
|
+
type=click.Choice(['text', 'json', 'table'])
|
|
147
147
|
)
|
|
148
148
|
@click.option(
|
|
149
149
|
'--user-agent',
|
|
@@ -7,7 +7,9 @@ from cycode.cli.models import DocumentDetections, CliResult, CliError
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class BasePrinter(ABC):
|
|
10
|
-
|
|
10
|
+
RED_COLOR_NAME = 'red'
|
|
11
|
+
WHITE_COLOR_NAME = 'white'
|
|
12
|
+
GREEN_COLOR_NAME = 'green'
|
|
11
13
|
|
|
12
14
|
def __init__(self, context: click.Context):
|
|
13
15
|
self.context = context
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
from typing import List
|
|
3
|
+
|
|
4
|
+
import click
|
|
5
|
+
|
|
6
|
+
from cycode.cli.printers.text_printer import TextPrinter
|
|
7
|
+
from cycode.cli.models import DocumentDetections, CliError, CliResult
|
|
8
|
+
from cycode.cli.printers.base_printer import BasePrinter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseTablePrinter(BasePrinter, abc.ABC):
|
|
12
|
+
def __init__(self, context: click.Context):
|
|
13
|
+
super().__init__(context)
|
|
14
|
+
self.context = context
|
|
15
|
+
self.scan_id: str = context.obj.get('scan_id')
|
|
16
|
+
self.scan_type: str = context.obj.get('scan_type')
|
|
17
|
+
self.show_secret: bool = context.obj.get('show_secret', False)
|
|
18
|
+
|
|
19
|
+
def print_result(self, result: CliResult) -> None:
|
|
20
|
+
TextPrinter(self.context).print_result(result)
|
|
21
|
+
|
|
22
|
+
def print_error(self, error: CliError) -> None:
|
|
23
|
+
TextPrinter(self.context).print_error(error)
|
|
24
|
+
|
|
25
|
+
def print_scan_results(self, results: List[DocumentDetections]):
|
|
26
|
+
click.secho(f'Scan Results: (scan_id: {self.scan_id})')
|
|
27
|
+
|
|
28
|
+
if not results:
|
|
29
|
+
click.secho('Good job! No issues were found!!! 👏👏👏', fg=self.GREEN_COLOR_NAME)
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
self._print_results(results)
|
|
33
|
+
|
|
34
|
+
report_url = self.context.obj.get('report_url')
|
|
35
|
+
if report_url:
|
|
36
|
+
click.secho(f'Report URL: {report_url}')
|
|
37
|
+
|
|
38
|
+
def _is_git_repository(self) -> bool:
|
|
39
|
+
return self.context.obj.get('remote_url') is not None
|
|
40
|
+
|
|
41
|
+
@abc.abstractmethod
|
|
42
|
+
def _print_results(self, results: List[DocumentDetections]) -> None:
|
|
43
|
+
raise NotImplementedError
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import click
|
|
2
2
|
from typing import List, TYPE_CHECKING
|
|
3
3
|
|
|
4
|
-
from cycode.cli.consts import SCA_SCAN_TYPE
|
|
5
4
|
from cycode.cli.exceptions.custom_exceptions import CycodeError
|
|
6
5
|
from cycode.cli.models import DocumentDetections, CliResult, CliError
|
|
7
6
|
from cycode.cli.printers.table_printer import TablePrinter
|
|
7
|
+
from cycode.cli.printers.sca_table_printer import SCATablePrinter
|
|
8
8
|
from cycode.cli.printers.json_printer import JsonPrinter
|
|
9
9
|
from cycode.cli.printers.text_printer import TextPrinter
|
|
10
10
|
|
|
@@ -16,11 +16,15 @@ class ConsolePrinter:
|
|
|
16
16
|
_AVAILABLE_PRINTERS = {
|
|
17
17
|
'text': TextPrinter,
|
|
18
18
|
'json': JsonPrinter,
|
|
19
|
-
'
|
|
19
|
+
'table': TablePrinter,
|
|
20
|
+
# overrides
|
|
21
|
+
'table_sca': SCATablePrinter,
|
|
22
|
+
'text_sca': SCATablePrinter,
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
def __init__(self, context: click.Context):
|
|
23
26
|
self.context = context
|
|
27
|
+
self.scan_type = self.context.obj.get('scan_type')
|
|
24
28
|
self.output_type = self.context.obj.get('output')
|
|
25
29
|
|
|
26
30
|
self._printer_class = self._AVAILABLE_PRINTERS.get(self.output_type)
|
|
@@ -32,11 +36,11 @@ class ConsolePrinter:
|
|
|
32
36
|
printer.print_scan_results(detections_results_list)
|
|
33
37
|
|
|
34
38
|
def _get_scan_printer(self) -> 'BasePrinter':
|
|
35
|
-
scan_type = self.context.obj.get('scan_type')
|
|
36
|
-
|
|
37
39
|
printer_class = self._printer_class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
+
|
|
41
|
+
composite_printer = self._AVAILABLE_PRINTERS.get(f'{self.output_type}_{self.scan_type}')
|
|
42
|
+
if composite_printer:
|
|
43
|
+
printer_class = composite_printer
|
|
40
44
|
|
|
41
45
|
return printer_class(self.context)
|
|
42
46
|
|
|
@@ -5,8 +5,8 @@ import click
|
|
|
5
5
|
from texttable import Texttable
|
|
6
6
|
|
|
7
7
|
from cycode.cli.consts import LICENSE_COMPLIANCE_POLICY_ID, PACKAGE_VULNERABILITY_POLICY_ID
|
|
8
|
-
from cycode.cli.models import DocumentDetections, Detection
|
|
9
|
-
from cycode.cli.printers.
|
|
8
|
+
from cycode.cli.models import DocumentDetections, Detection
|
|
9
|
+
from cycode.cli.printers.base_table_printer import BaseTablePrinter
|
|
10
10
|
|
|
11
11
|
SEVERITY_COLUMN = 'Severity'
|
|
12
12
|
LICENSE_COLUMN = 'License'
|
|
@@ -23,36 +23,11 @@ PREVIEW_DETECTIONS_COMMON_HEADERS = [
|
|
|
23
23
|
]
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
class
|
|
27
|
-
|
|
28
|
-
WHITE_COLOR_NAME = 'white'
|
|
29
|
-
GREEN_COLOR_NAME = 'green'
|
|
30
|
-
|
|
31
|
-
def __init__(self, context: click.Context):
|
|
32
|
-
super().__init__(context)
|
|
33
|
-
self.scan_id = context.obj.get('scan_id')
|
|
34
|
-
|
|
35
|
-
def print_result(self, result: CliResult) -> None:
|
|
36
|
-
raise NotImplemented
|
|
37
|
-
|
|
38
|
-
def print_error(self, error: CliError) -> None:
|
|
39
|
-
raise NotImplemented
|
|
40
|
-
|
|
41
|
-
def print_scan_results(self, results: List[DocumentDetections]):
|
|
42
|
-
click.secho(f"Scan Results: (scan_id: {self.scan_id})")
|
|
43
|
-
|
|
44
|
-
if not results:
|
|
45
|
-
click.secho("Good job! No issues were found!!! 👏👏👏", fg=self.GREEN_COLOR_NAME)
|
|
46
|
-
return
|
|
47
|
-
|
|
26
|
+
class SCATablePrinter(BaseTablePrinter):
|
|
27
|
+
def _print_results(self, results: List[DocumentDetections]) -> None:
|
|
48
28
|
detections_per_detection_type_id = self._extract_detections_per_detection_type_id(results)
|
|
49
|
-
|
|
50
29
|
self._print_detection_per_detection_type_id(detections_per_detection_type_id)
|
|
51
30
|
|
|
52
|
-
report_url = self.context.obj.get('report_url')
|
|
53
|
-
if report_url:
|
|
54
|
-
click.secho(f'Report URL: {report_url}')
|
|
55
|
-
|
|
56
31
|
@staticmethod
|
|
57
32
|
def _extract_detections_per_detection_type_id(results: List[DocumentDetections]) -> Dict[str, List[Detection]]:
|
|
58
33
|
detections_per_detection_type_id = defaultdict(list)
|
|
@@ -146,9 +121,6 @@ class TablePrinter(BasePrinter):
|
|
|
146
121
|
|
|
147
122
|
return row
|
|
148
123
|
|
|
149
|
-
def _is_git_repository(self) -> bool:
|
|
150
|
-
return self.context.obj.get("remote_url") is not None
|
|
151
|
-
|
|
152
124
|
def _get_upgrade_package_vulnerability(self, detection: Detection) -> List[str]:
|
|
153
125
|
alert = detection.detection_details.get('alert')
|
|
154
126
|
row = [
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from typing import List, Dict, Optional, TYPE_CHECKING
|
|
2
|
+
from texttable import Texttable
|
|
3
|
+
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from cycode.cli.printers.table_models import ColumnInfo, ColumnWidths
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Table:
|
|
9
|
+
"""Helper class to manage columns and their values in the right order and only if the column should be presented."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, column_infos: Optional[List['ColumnInfo']] = None):
|
|
12
|
+
self._column_widths = None
|
|
13
|
+
|
|
14
|
+
self._columns: Dict['ColumnInfo', List[str]] = dict()
|
|
15
|
+
if column_infos:
|
|
16
|
+
self._columns: Dict['ColumnInfo', List[str]] = {columns: list() for columns in column_infos}
|
|
17
|
+
|
|
18
|
+
def add(self, column: 'ColumnInfo') -> None:
|
|
19
|
+
self._columns[column] = list()
|
|
20
|
+
|
|
21
|
+
def set(self, column: 'ColumnInfo', value: str) -> None:
|
|
22
|
+
# we push values only for existing columns what were added before
|
|
23
|
+
if column in self._columns:
|
|
24
|
+
self._columns[column].append(value)
|
|
25
|
+
|
|
26
|
+
def _get_ordered_columns(self) -> List['ColumnInfo']:
|
|
27
|
+
# we are sorting columns by index to make sure that columns will be printed in the right order
|
|
28
|
+
return sorted(self._columns, key=lambda column_info: column_info.index)
|
|
29
|
+
|
|
30
|
+
def get_columns_info(self) -> List['ColumnInfo']:
|
|
31
|
+
return self._get_ordered_columns()
|
|
32
|
+
|
|
33
|
+
def get_headers(self) -> List[str]:
|
|
34
|
+
return [header.name for header in self._get_ordered_columns()]
|
|
35
|
+
|
|
36
|
+
def get_rows(self) -> List[str]:
|
|
37
|
+
column_values = [self._columns[column_info] for column_info in self._get_ordered_columns()]
|
|
38
|
+
return list(zip(*column_values))
|
|
39
|
+
|
|
40
|
+
def set_cols_width(self, column_widths: 'ColumnWidths') -> None:
|
|
41
|
+
header_width_size = []
|
|
42
|
+
for header in self.get_columns_info():
|
|
43
|
+
width_multiplier = 1
|
|
44
|
+
if header in column_widths:
|
|
45
|
+
width_multiplier = column_widths[header]
|
|
46
|
+
|
|
47
|
+
header_width_size.append(len(header.name) * width_multiplier)
|
|
48
|
+
|
|
49
|
+
self._column_widths = header_width_size
|
|
50
|
+
|
|
51
|
+
def get_table(self, max_width: int = 80) -> Texttable:
|
|
52
|
+
table = Texttable(max_width)
|
|
53
|
+
table.header(self.get_headers())
|
|
54
|
+
|
|
55
|
+
for row in self.get_rows():
|
|
56
|
+
table.add_row(row)
|
|
57
|
+
|
|
58
|
+
if self._column_widths:
|
|
59
|
+
table.set_cols_width(self._column_widths)
|
|
60
|
+
|
|
61
|
+
return table
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from typing import NamedTuple, Dict
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ColumnInfoBuilder:
|
|
5
|
+
_index = 0
|
|
6
|
+
|
|
7
|
+
@staticmethod
|
|
8
|
+
def build(name: str) -> 'ColumnInfo':
|
|
9
|
+
column_info = ColumnInfo(name, ColumnInfoBuilder._index)
|
|
10
|
+
ColumnInfoBuilder._index += 1
|
|
11
|
+
return column_info
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ColumnInfo(NamedTuple):
|
|
15
|
+
name: str
|
|
16
|
+
index: int # Represents the order of the columns, starting from the left
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
ColumnWidths = Dict[ColumnInfo, int]
|
|
20
|
+
ColumnWidthsConfig = Dict[str, ColumnWidths]
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
import click
|
|
4
|
+
|
|
5
|
+
from cycode.cli.printers.base_table_printer import BaseTablePrinter
|
|
6
|
+
from cycode.cli.printers.table_models import ColumnInfoBuilder, ColumnWidthsConfig
|
|
7
|
+
from cycode.cli.printers.table import Table
|
|
8
|
+
from cycode.cli.utils.string_utils import obfuscate_text, get_position_in_line
|
|
9
|
+
from cycode.cli.consts import SECRET_SCAN_TYPE, INFRA_CONFIGURATION_SCAN_TYPE, SAST_SCAN_TYPE
|
|
10
|
+
from cycode.cli.models import DocumentDetections, Detection, Document
|
|
11
|
+
|
|
12
|
+
# Creation must have strict order. Represents the order of the columns in the table (from left to right)
|
|
13
|
+
ISSUE_TYPE_COLUMN = ColumnInfoBuilder.build(name='Issue Type')
|
|
14
|
+
RULE_ID_COLUMN = ColumnInfoBuilder.build(name='Rule ID')
|
|
15
|
+
FILE_PATH_COLUMN = ColumnInfoBuilder.build(name='File Path')
|
|
16
|
+
SECRET_SHA_COLUMN = ColumnInfoBuilder.build(name='Secret SHA')
|
|
17
|
+
COMMIT_SHA_COLUMN = ColumnInfoBuilder.build(name='Commit SHA')
|
|
18
|
+
LINE_NUMBER_COLUMN = ColumnInfoBuilder.build(name='Line Number')
|
|
19
|
+
COLUMN_NUMBER_COLUMN = ColumnInfoBuilder.build(name='Column Number')
|
|
20
|
+
VIOLATION_LENGTH_COLUMN = ColumnInfoBuilder.build(name='Violation Length')
|
|
21
|
+
VIOLATION_COLUMN = ColumnInfoBuilder.build(name='Violation')
|
|
22
|
+
|
|
23
|
+
COLUMN_WIDTHS_CONFIG: ColumnWidthsConfig = {
|
|
24
|
+
SECRET_SCAN_TYPE: {
|
|
25
|
+
ISSUE_TYPE_COLUMN: 2,
|
|
26
|
+
RULE_ID_COLUMN: 2,
|
|
27
|
+
FILE_PATH_COLUMN: 2,
|
|
28
|
+
SECRET_SHA_COLUMN: 2,
|
|
29
|
+
VIOLATION_COLUMN: 2,
|
|
30
|
+
},
|
|
31
|
+
INFRA_CONFIGURATION_SCAN_TYPE: {
|
|
32
|
+
ISSUE_TYPE_COLUMN: 4,
|
|
33
|
+
RULE_ID_COLUMN: 3,
|
|
34
|
+
FILE_PATH_COLUMN: 3,
|
|
35
|
+
},
|
|
36
|
+
SAST_SCAN_TYPE: {
|
|
37
|
+
ISSUE_TYPE_COLUMN: 7,
|
|
38
|
+
RULE_ID_COLUMN: 2,
|
|
39
|
+
FILE_PATH_COLUMN: 3,
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class TablePrinter(BaseTablePrinter):
|
|
45
|
+
def _print_results(self, results: List[DocumentDetections]) -> None:
|
|
46
|
+
table = self._get_table()
|
|
47
|
+
if self.scan_type in COLUMN_WIDTHS_CONFIG:
|
|
48
|
+
table.set_cols_width(COLUMN_WIDTHS_CONFIG[self.scan_type])
|
|
49
|
+
|
|
50
|
+
for result in results:
|
|
51
|
+
for detection in result.detections:
|
|
52
|
+
self._enrich_table_with_values(table, detection, result.document)
|
|
53
|
+
|
|
54
|
+
click.echo(table.get_table().draw())
|
|
55
|
+
|
|
56
|
+
def _get_table(self) -> Table:
|
|
57
|
+
table = Table()
|
|
58
|
+
|
|
59
|
+
table.add(ISSUE_TYPE_COLUMN)
|
|
60
|
+
table.add(RULE_ID_COLUMN)
|
|
61
|
+
table.add(FILE_PATH_COLUMN)
|
|
62
|
+
table.add(LINE_NUMBER_COLUMN)
|
|
63
|
+
table.add(COLUMN_NUMBER_COLUMN)
|
|
64
|
+
|
|
65
|
+
if self._is_git_repository():
|
|
66
|
+
table.add(COMMIT_SHA_COLUMN)
|
|
67
|
+
|
|
68
|
+
if self.scan_type == SECRET_SCAN_TYPE:
|
|
69
|
+
table.add(SECRET_SHA_COLUMN)
|
|
70
|
+
table.add(VIOLATION_LENGTH_COLUMN)
|
|
71
|
+
table.add(VIOLATION_COLUMN)
|
|
72
|
+
|
|
73
|
+
return table
|
|
74
|
+
|
|
75
|
+
def _enrich_table_with_values(self, table: Table, detection: Detection, document: Document) -> None:
|
|
76
|
+
self._enrich_table_with_detection_summary_values(table, detection, document)
|
|
77
|
+
self._enrich_table_with_detection_code_segment_values(table, detection, document)
|
|
78
|
+
|
|
79
|
+
def _enrich_table_with_detection_summary_values(
|
|
80
|
+
self, table: Table, detection: Detection, document: Document
|
|
81
|
+
) -> None:
|
|
82
|
+
issue_type = detection.message
|
|
83
|
+
if self.scan_type == SECRET_SCAN_TYPE:
|
|
84
|
+
issue_type = detection.type
|
|
85
|
+
|
|
86
|
+
table.set(ISSUE_TYPE_COLUMN, issue_type)
|
|
87
|
+
table.set(RULE_ID_COLUMN, detection.detection_rule_id)
|
|
88
|
+
table.set(FILE_PATH_COLUMN, click.format_filename(document.path))
|
|
89
|
+
table.set(SECRET_SHA_COLUMN, detection.detection_details.get('sha512', ''))
|
|
90
|
+
table.set(COMMIT_SHA_COLUMN, detection.detection_details.get('commit_id', ''))
|
|
91
|
+
|
|
92
|
+
def _enrich_table_with_detection_code_segment_values(
|
|
93
|
+
self, table: Table, detection: Detection, document: Document
|
|
94
|
+
) -> None:
|
|
95
|
+
detection_details = detection.detection_details
|
|
96
|
+
|
|
97
|
+
detection_line = detection_details.get('line_in_file', -1)
|
|
98
|
+
if self.scan_type == SECRET_SCAN_TYPE:
|
|
99
|
+
detection_line = detection_details.get('line', -1)
|
|
100
|
+
|
|
101
|
+
detection_column = get_position_in_line(document.content, detection_details.get('start_position', -1))
|
|
102
|
+
violation_length = detection_details.get('length', -1)
|
|
103
|
+
|
|
104
|
+
violation = ''
|
|
105
|
+
file_content_lines = document.content.splitlines()
|
|
106
|
+
if detection_line < len(file_content_lines):
|
|
107
|
+
line = file_content_lines[detection_line]
|
|
108
|
+
violation = line[detection_column: detection_column + violation_length]
|
|
109
|
+
|
|
110
|
+
if not self.show_secret:
|
|
111
|
+
violation = obfuscate_text(violation)
|
|
112
|
+
|
|
113
|
+
table.set(LINE_NUMBER_COLUMN, str(detection_line))
|
|
114
|
+
table.set(COLUMN_NUMBER_COLUMN, str(detection_column))
|
|
115
|
+
table.set(VIOLATION_LENGTH_COLUMN, f'{violation_length} chars')
|
|
116
|
+
table.set(VIOLATION_COLUMN, violation)
|
|
@@ -7,14 +7,10 @@ from cycode.cli.printers.base_printer import BasePrinter
|
|
|
7
7
|
from cycode.cli.models import DocumentDetections, Detection, Document, CliResult, CliError
|
|
8
8
|
from cycode.cli.config import config
|
|
9
9
|
from cycode.cli.consts import SECRET_SCAN_TYPE, COMMIT_RANGE_BASED_COMMAND_SCAN_TYPES
|
|
10
|
-
from cycode.cli.utils.string_utils import obfuscate_text
|
|
10
|
+
from cycode.cli.utils.string_utils import obfuscate_text, get_position_in_line
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class TextPrinter(BasePrinter):
|
|
14
|
-
RED_COLOR_NAME = 'red'
|
|
15
|
-
WHITE_COLOR_NAME = 'white'
|
|
16
|
-
GREEN_COLOR_NAME = 'green'
|
|
17
|
-
|
|
18
14
|
def __init__(self, context: click.Context):
|
|
19
15
|
super().__init__(context)
|
|
20
16
|
self.scan_id: str = context.obj.get('scan_id')
|
|
@@ -132,9 +128,6 @@ class TextPrinter(BasePrinter):
|
|
|
132
128
|
|
|
133
129
|
return self.WHITE_COLOR_NAME
|
|
134
130
|
|
|
135
|
-
def _get_position_in_line(self, text: str, position: int) -> int:
|
|
136
|
-
return position - text.rfind('\n', 0, position) - 1
|
|
137
|
-
|
|
138
131
|
def _get_line_number_style(self, line_number: int):
|
|
139
132
|
return f'{click.style(str(line_number), fg=self.WHITE_COLOR_NAME, bold=False)} ' \
|
|
140
133
|
f'{click.style("|", fg=self.RED_COLOR_NAME, bold=False)}'
|
|
@@ -158,7 +151,7 @@ class TextPrinter(BasePrinter):
|
|
|
158
151
|
file_content = document.content
|
|
159
152
|
file_lines = file_content.splitlines()
|
|
160
153
|
start_line = self._get_code_segment_start_line(detection_line, code_segment_size)
|
|
161
|
-
detection_position_in_line =
|
|
154
|
+
detection_position_in_line = get_position_in_line(file_content, detection_position)
|
|
162
155
|
|
|
163
156
|
click.echo()
|
|
164
157
|
for i in range(code_segment_size):
|
|
@@ -182,7 +175,7 @@ class TextPrinter(BasePrinter):
|
|
|
182
175
|
git_diff_content = document.content
|
|
183
176
|
git_diff_lines = git_diff_content.splitlines()
|
|
184
177
|
detection_line = git_diff_lines[detection_line_number]
|
|
185
|
-
detection_position_in_line =
|
|
178
|
+
detection_position_in_line = get_position_in_line(git_diff_content, detection_position)
|
|
186
179
|
|
|
187
180
|
click.echo()
|
|
188
181
|
self._print_detection_line(document, detection_line, detection_line_number_in_original_file,
|
|
@@ -43,3 +43,7 @@ def generate_random_string(string_len: int):
|
|
|
43
43
|
# letters, digits, and symbols
|
|
44
44
|
characters = string.ascii_letters + string.digits + string.punctuation
|
|
45
45
|
return ''.join(random.choice(characters) for _ in range(string_len))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_position_in_line(text: str, position: int) -> int:
|
|
49
|
+
return position - text.rfind('\n', 0, position) - 1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "cycode"
|
|
3
|
-
version = "0.2.5.
|
|
3
|
+
version = "0.2.5.dev7" # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
|
|
4
4
|
description = "Perform secrets/iac scans for your sources using Cycode's engine"
|
|
5
5
|
keywords=["secret-scan", "cycode", "devops", "token", "secret", "security", "cycode", "code"]
|
|
6
6
|
authors = ["Cycode <support@cycode.com>"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.2.5.dev6' # DON'T TOUCH. Placeholder. Will be filled automatically on poetry build from Git Tag
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/base_restore_maven_dependencies.py
RENAMED
|
File without changes
|
{cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/restore_gradle_dependencies.py
RENAMED
|
File without changes
|
{cycode-0.2.5.dev6 → cycode-0.2.5.dev7}/cycode/cli/helpers/maven/restore_maven_dependencies.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|