forked from cycodehq/cycode-cli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
198 lines (170 loc) · 7.07 KB
/
Copy pathmain.py
File metadata and controls
198 lines (170 loc) · 7.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import logging
import click
import sys
from typing import List, Optional
from cycode import __version__
from cycode.cli.models import Severity
from cycode.cli.config import config
from cycode.cli import code_scanner
from cycode.cli.user_settings.credentials_manager import CredentialsManager
from cycode.cli.user_settings.configuration_manager import ConfigurationManager
from cycode.cli.user_settings.user_settings_commands import set_credentials, add_exclusions
from cycode.cli.auth.auth_command import authenticate
from cycode.cli.utils import scan_utils
from cycode.cyclient import logger
from cycode.cyclient.cycode_client_base import CycodeClientBase
from cycode.cyclient.models import UserAgentOptionScheme
from cycode.cyclient.scan_config.scan_config_creator import create_scan_client
CONTEXT = dict()
ISSUE_DETECTED_STATUS_CODE = 1
NO_ISSUES_STATUS_CODE = 0
@click.group(
commands={
"repository": code_scanner.scan_repository,
"commit_history": code_scanner.scan_repository_commit_history,
"path": code_scanner.scan_path,
"pre_commit": code_scanner.pre_commit_scan,
"pre_receive": code_scanner.pre_receive_scan
},
)
@click.option('--scan-type', '-t', default="secret",
help="""
\b
Specify the scan you wish to execute (secret/iac/sca),
the default is secret
""",
type=click.Choice(config['scans']['supported_scans']))
@click.option('--secret',
default=None,
help='Specify a Cycode client secret for this specific scan execution',
type=str,
required=False)
@click.option('--client-id',
default=None,
help='Specify a Cycode client ID for this specific scan execution',
type=str,
required=False)
@click.option('--show-secret',
is_flag=True,
default=False,
help='Show secrets in plain text',
type=bool,
required=False)
@click.option('--soft-fail',
is_flag=True,
default=False,
help='Run scan without failing, always return a non-error status code',
type=bool,
required=False)
@click.option('--output', default=None,
help="""
\b
Specify the results output (text/json/table),
the default is text
""",
type=click.Choice(['text', 'json', 'table']))
@click.option('--severity-threshold',
default=None,
help='Show only violations at the specified level or higher (supported for SCA scan type only).',
type=click.Choice([e.name for e in Severity]),
required=False)
@click.option('--sca-scan',
default=None,
help="Specify the sca scan you wish to execute (package-vulnerabilities/license-compliance), the default is both",
multiple=True,
type=click.Choice(config['scans']['supported_sca_scans']))
@click.option('--monitor',
is_flag=True,
default=False,
help="When specified, the scan results will be recorded in the knowledge graph. Please note that when working in 'monitor' mode, the knowledge graph will not be updated as a result of SCM events (Push, Repo creation).(supported for SCA scan type only).",
type=bool,
required=False)
@click.option('--report',
is_flag=True,
default=False,
help="When specified, a violations report will be generated. A URL link to the report will be printed as an output to the command execution",
type=bool,
required=False)
@click.pass_context
def code_scan(context: click.Context, scan_type, client_id, secret, show_secret, soft_fail, output, severity_threshold,
sca_scan: List[str], monitor, report):
""" Scan content for secrets/IaC/sca/SAST violations, You need to specify which scan type: ci/commit_history/path/repository/etc """
if show_secret:
context.obj["show_secret"] = show_secret
else:
context.obj["show_secret"] = config["result_printer"]["default"]["show_secret"]
if soft_fail:
context.obj["soft_fail"] = soft_fail
else:
context.obj["soft_fail"] = config["soft_fail"]
context.obj["scan_type"] = scan_type
if output is not None:
# save backward compatability with old style command
context.obj["output"] = output
context.obj["client"] = get_cycode_client(client_id, secret)
context.obj["severity_threshold"] = severity_threshold
context.obj["monitor"] = monitor
context.obj["report"] = report
_sca_scan_to_context(context, sca_scan)
return 1
@code_scan.result_callback()
@click.pass_context
def finalize(context: click.Context, *args, **kwargs):
if context.obj["soft_fail"]:
sys.exit(0)
sys.exit(ISSUE_DETECTED_STATUS_CODE if _should_fail_scan(context) else NO_ISSUES_STATUS_CODE)
@click.group(
commands={
"scan": code_scan,
"configure": set_credentials,
"ignore": add_exclusions,
"auth": authenticate
},
context_settings=CONTEXT
)
@click.option(
"--verbose", "-v", is_flag=True, default=False, help="Show detailed logs",
)
@click.option(
'--output',
default='text',
help='Specify the output (text/json/table), the default is text',
type=click.Choice(['text', 'json', 'table'])
)
@click.option(
'--user-agent',
default=None,
help='Characteristic JSON object that lets servers identify the application',
type=str,
)
@click.version_option(__version__, prog_name="cycode")
@click.pass_context
def main_cli(context: click.Context, verbose: bool, output: str, user_agent: Optional[str]):
context.ensure_object(dict)
configuration_manager = ConfigurationManager()
verbose = verbose or configuration_manager.get_verbose_flag()
context.obj['verbose'] = verbose
log_level = logging.DEBUG if verbose else logging.INFO
logger.setLevel(log_level)
context.obj['output'] = output
if user_agent:
user_agent_option = UserAgentOptionScheme().loads(user_agent)
CycodeClientBase.enrich_user_agent(user_agent_option.user_agent_suffix)
def get_cycode_client(client_id, client_secret):
if not client_id or not client_secret:
client_id, client_secret = _get_configured_credentials()
if not client_id:
raise click.ClickException("Cycode client id needed.")
if not client_secret:
raise click.ClickException("Cycode client secret is needed.")
return create_scan_client(client_id, client_secret)
def _get_configured_credentials():
credentials_manager = CredentialsManager()
return credentials_manager.get_credentials()
def _should_fail_scan(context: click.Context):
return scan_utils.is_scan_failed(context)
def _sca_scan_to_context(context: click.Context, sca_scan_user_selected: List[str]):
for sca_scan_option_selected in sca_scan_user_selected:
context.obj[sca_scan_option_selected] = True
if __name__ == '__main__':
main_cli()