178 lines
5.1 KiB
Python
178 lines
5.1 KiB
Python
import logging
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
from safety.codebase.render import render_initialization_result
|
|
from safety.errors import SafetyError
|
|
from safety.events.utils.emission import (
|
|
emit_codebase_detection_status,
|
|
emit_codebase_setup_completed,
|
|
)
|
|
from safety.init.main import launch_auth_if_needed
|
|
from safety.tool.main import find_local_tool_files
|
|
from safety.util import clean_project_id
|
|
from typing_extensions import Annotated
|
|
|
|
import typer
|
|
from safety.cli_util import SafetyCLISubGroup, SafetyCLICommand
|
|
from .constants import (
|
|
CMD_CODEBASE_INIT_NAME,
|
|
CMD_HELP_CODEBASE_INIT,
|
|
CMD_HELP_CODEBASE,
|
|
CMD_CODEBASE_GROUP_NAME,
|
|
CMD_HELP_CODEBASE_INIT_DISABLE_FIREWALL,
|
|
CMD_HELP_CODEBASE_INIT_LINK_TO,
|
|
CMD_HELP_CODEBASE_INIT_NAME,
|
|
CMD_HELP_CODEBASE_INIT_PATH,
|
|
)
|
|
|
|
from ..cli_util import CommandType, get_command_for
|
|
from ..error_handlers import handle_cmd_exception
|
|
from ..decorators import notify
|
|
from ..constants import CONTEXT_COMMAND_TYPE, DEFAULT_EPILOG
|
|
from safety.console import main_console as console
|
|
from .main import initialize_codebase, prepare_unverified_codebase
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
cli_apps_opts = {
|
|
"rich_markup_mode": "rich",
|
|
"cls": SafetyCLISubGroup,
|
|
"name": CMD_CODEBASE_GROUP_NAME,
|
|
}
|
|
codebase_app = typer.Typer(**cli_apps_opts)
|
|
|
|
DEFAULT_CMD = CMD_CODEBASE_INIT_NAME
|
|
|
|
|
|
@codebase_app.callback(
|
|
invoke_without_command=True,
|
|
cls=SafetyCLISubGroup,
|
|
help=CMD_HELP_CODEBASE,
|
|
epilog=DEFAULT_EPILOG,
|
|
context_settings={
|
|
"allow_extra_args": True,
|
|
"ignore_unknown_options": True,
|
|
CONTEXT_COMMAND_TYPE: CommandType.BETA,
|
|
},
|
|
)
|
|
def codebase(
|
|
ctx: typer.Context,
|
|
):
|
|
"""
|
|
Group command for Safety Codebase (project) operations. Running this command will forward to the default command.
|
|
"""
|
|
logger.info("codebase started")
|
|
|
|
# If no subcommand is invoked, forward to the default command
|
|
if not ctx.invoked_subcommand:
|
|
default_command = get_command_for(name=DEFAULT_CMD, typer_instance=codebase_app)
|
|
return ctx.forward(default_command)
|
|
|
|
|
|
@codebase_app.command(
|
|
cls=SafetyCLICommand,
|
|
help=CMD_HELP_CODEBASE_INIT,
|
|
name=CMD_CODEBASE_INIT_NAME,
|
|
epilog=DEFAULT_EPILOG,
|
|
options_metavar="[OPTIONS]",
|
|
context_settings={"allow_extra_args": True, "ignore_unknown_options": True},
|
|
)
|
|
@handle_cmd_exception
|
|
@notify
|
|
def init(
|
|
ctx: typer.Context,
|
|
name: Annotated[
|
|
Optional[str],
|
|
typer.Option(
|
|
help=CMD_HELP_CODEBASE_INIT_NAME,
|
|
callback=lambda name: clean_project_id(name) if name else None,
|
|
),
|
|
] = None,
|
|
link_to: Annotated[
|
|
Optional[str],
|
|
typer.Option(
|
|
"--link-to",
|
|
help=CMD_HELP_CODEBASE_INIT_LINK_TO,
|
|
callback=lambda name: clean_project_id(name) if name else None,
|
|
),
|
|
] = None,
|
|
skip_firewall_setup: Annotated[
|
|
bool, typer.Option(help=CMD_HELP_CODEBASE_INIT_DISABLE_FIREWALL)
|
|
] = False,
|
|
codebase_path: Annotated[
|
|
Path,
|
|
typer.Option(
|
|
"--path",
|
|
exists=True,
|
|
file_okay=False,
|
|
dir_okay=True,
|
|
writable=True,
|
|
readable=True,
|
|
resolve_path=True,
|
|
show_default=False,
|
|
help=CMD_HELP_CODEBASE_INIT_PATH,
|
|
),
|
|
] = Path("."),
|
|
):
|
|
"""
|
|
Initialize a Safety Codebase. The codebase may be entirely new to Safety Platform,
|
|
or may already exist in Safety Platform and the user is wanting to initialize it locally.
|
|
"""
|
|
logger.info("codebase init started")
|
|
|
|
if link_to and name:
|
|
raise typer.BadParameter("--link-to and --name cannot be used together")
|
|
|
|
org_slug = launch_auth_if_needed(ctx, console)
|
|
|
|
if not org_slug:
|
|
raise SafetyError(
|
|
"Organization not found, please run 'safety auth status' or 'safety auth login'"
|
|
)
|
|
|
|
should_enable_firewall = not skip_firewall_setup and ctx.obj.firewall_enabled
|
|
|
|
unverified_codebase = prepare_unverified_codebase(
|
|
codebase_path=codebase_path,
|
|
user_provided_name=name,
|
|
user_provided_link_to=link_to,
|
|
)
|
|
|
|
local_files = find_local_tool_files(codebase_path)
|
|
|
|
emit_codebase_detection_status(
|
|
event_bus=ctx.obj.event_bus,
|
|
ctx=ctx,
|
|
detected=any(local_files),
|
|
detected_files=local_files if local_files else None,
|
|
)
|
|
|
|
project_file_created, project_status = initialize_codebase(
|
|
ctx=ctx,
|
|
console=console,
|
|
codebase_path=codebase_path,
|
|
unverified_codebase=unverified_codebase,
|
|
org_slug=org_slug,
|
|
link_to=link_to,
|
|
should_enable_firewall=should_enable_firewall,
|
|
)
|
|
|
|
codebase_init_status = (
|
|
"reinitialized" if unverified_codebase.created else project_status
|
|
)
|
|
codebase_id = ctx.obj.project.id if ctx.obj.project and ctx.obj.project.id else None
|
|
|
|
render_initialization_result(
|
|
console=console,
|
|
codebase_init_status=codebase_init_status,
|
|
codebase_id=codebase_id,
|
|
)
|
|
|
|
emit_codebase_setup_completed(
|
|
event_bus=ctx.obj.event_bus,
|
|
ctx=ctx,
|
|
is_created=project_file_created,
|
|
codebase_id=codebase_id,
|
|
)
|