-
Notifications
You must be signed in to change notification settings - Fork 62
Expand file tree
/
Copy pathapp.py
More file actions
173 lines (148 loc) · 6.33 KB
/
app.py
File metadata and controls
173 lines (148 loc) · 6.33 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
import logging
import sys
from typing import Annotated, Optional
import typer
from typer import rich_utils
from typer._completion_classes import completion_init
from typer._completion_shared import Shells
from typer.completion import install_callback, show_callback
from cycode import __version__
from cycode.cli.apps import ai_guardrails, ai_remediation, auth, configure, ignore, report, report_import, scan, status
if sys.version_info >= (3, 10):
from cycode.cli.apps import mcp
from cycode.cli.cli_types import OutputTypeOption
from cycode.cli.consts import CLI_CONTEXT_SETTINGS
from cycode.cli.printers import ConsolePrinter
from cycode.cli.user_settings.configuration_manager import ConfigurationManager
from cycode.cli.utils.progress_bar import SCAN_PROGRESS_BAR_SECTIONS, get_progress_bar
from cycode.cli.utils.version_checker import version_checker
from cycode.cyclient.cycode_client_base import CycodeClientBase
from cycode.cyclient.models import UserAgentOptionScheme
from cycode.logger import set_logging_level
# By default, it uses dim style which is hard to read with the combination of color from RICH_HELP
rich_utils.STYLE_ERRORS_SUGGESTION = 'bold'
# By default, it uses blue color which is too dark for some terminals
rich_utils.RICH_HELP = "Try [cyan]'{command_path} {help_option}'[/] for help."
completion_init() # DO NOT TOUCH; this is required for the completion to work properly
_cycode_cli_docs = 'https://github.com/cycodehq/cycode-cli/blob/main/README.md'
_cycode_cli_epilog = f'[bold]Documentation:[/] [link={_cycode_cli_docs}]{_cycode_cli_docs}[/link]'
app = typer.Typer(
pretty_exceptions_show_locals=False,
pretty_exceptions_short=True,
context_settings=CLI_CONTEXT_SETTINGS,
epilog=_cycode_cli_epilog,
rich_markup_mode='rich',
no_args_is_help=True,
add_completion=False, # we add it manually to control the rich help panel
)
app.add_typer(ai_guardrails.app)
app.add_typer(ai_remediation.app)
app.add_typer(auth.app)
app.add_typer(configure.app)
app.add_typer(ignore.app)
app.add_typer(report.app)
app.add_typer(report_import.app)
app.add_typer(scan.app)
app.add_typer(status.app)
if sys.version_info >= (3, 10):
app.add_typer(mcp.app)
def check_latest_version_on_close(ctx: typer.Context) -> None:
output = ctx.obj.get('output')
# don't print anything if the output is JSON
if output == OutputTypeOption.JSON:
return
# we always want to check the latest version for "version" and "status" commands
should_use_cache = ctx.invoked_subcommand not in {'version', 'status'}
version_checker.check_and_notify_update(current_version=__version__, use_cache=should_use_cache)
def export_if_needed_on_close(ctx: typer.Context) -> None:
scan_finalized = ctx.obj.get('scan_finalized')
printer = ctx.obj.get('console_printer')
if scan_finalized and printer.is_recording:
printer.export()
_AUTH_RICH_HELP_PANEL = 'Authentication options'
_COMPLETION_RICH_HELP_PANEL = 'Completion options'
@app.callback()
def app_callback(
ctx: typer.Context,
verbose: Annotated[bool, typer.Option('--verbose', '-v', help='Show detailed logs.')] = False,
no_progress_meter: Annotated[
bool, typer.Option('--no-progress-meter', help='Do not show the progress meter.')
] = False,
no_update_notifier: Annotated[
bool, typer.Option('--no-update-notifier', help='Do not check CLI for updates.')
] = False,
output: Annotated[
OutputTypeOption, typer.Option('--output', '-o', case_sensitive=False, help='Specify the output type.')
] = OutputTypeOption.RICH,
user_agent: Annotated[
Optional[str],
typer.Option(hidden=True, help='Characteristic JSON object that lets servers identify the application.'),
] = None,
client_secret: Annotated[
Optional[str],
typer.Option(
help='Specify a Cycode client secret for this specific scan execution.',
rich_help_panel=_AUTH_RICH_HELP_PANEL,
),
] = None,
client_id: Annotated[
Optional[str],
typer.Option(
help='Specify a Cycode client ID for this specific scan execution.',
rich_help_panel=_AUTH_RICH_HELP_PANEL,
),
] = None,
id_token: Annotated[
Optional[str],
typer.Option(
help='Specify a Cycode OIDC ID token for this specific scan execution.',
rich_help_panel=_AUTH_RICH_HELP_PANEL,
),
] = None,
_: Annotated[
Optional[bool],
typer.Option(
'--install-completion',
callback=install_callback,
is_eager=True,
expose_value=False,
help='Install completion for the current shell.',
rich_help_panel=_COMPLETION_RICH_HELP_PANEL,
),
] = False,
__: Annotated[
Shells, # the choice is required for Homebrew to be able to install the completion
typer.Option(
'--show-completion',
callback=show_callback,
is_eager=True,
expose_value=False,
show_default=False,
help='Show completion for the specified shell, to copy it or customize the installation.',
rich_help_panel=_COMPLETION_RICH_HELP_PANEL,
),
] = None,
) -> None:
"""[bold cyan]Cycode CLI - Command Line Interface for Cycode.[/]"""
ctx.ensure_object(dict)
configuration_manager = ConfigurationManager()
verbose = verbose or configuration_manager.get_verbose_flag()
ctx.obj['verbose'] = verbose
if verbose:
set_logging_level(logging.DEBUG)
ctx.obj['output'] = output
if output == OutputTypeOption.JSON:
no_progress_meter = True
ctx.obj['client_id'] = client_id
ctx.obj['client_secret'] = client_secret
ctx.obj['id_token'] = id_token
ctx.obj['progress_bar'] = get_progress_bar(hidden=no_progress_meter, sections=SCAN_PROGRESS_BAR_SECTIONS)
ctx.obj['console_printer'] = ConsolePrinter(ctx)
ctx.call_on_close(lambda: export_if_needed_on_close(ctx))
if user_agent:
user_agent_option = UserAgentOptionScheme().loads(user_agent)
CycodeClientBase.enrich_user_agent(user_agent_option.user_agent_suffix)
ctx.obj['plugin_app_name'] = user_agent_option.app_name
ctx.obj['plugin_app_version'] = user_agent_option.app_version
if not no_update_notifier:
ctx.call_on_close(lambda: check_latest_version_on_close(ctx))