Skip to content

Commit

Permalink
Merge pull request #979 from GitGuardian/agateau/use-ui-verbose
Browse files Browse the repository at this point in the history
Rework verbose mode
  • Loading branch information
agateau-gg authored Oct 25, 2024
2 parents bc77a6a + db00d97 commit 77fa6a9
Show file tree
Hide file tree
Showing 49 changed files with 359 additions and 461 deletions.
3 changes: 3 additions & 0 deletions changelog.d/20241014_131933_aurelien.gateau_use_ui_verbose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- Adding the `--debug` argument now automatically turns on verbose mode.
43 changes: 22 additions & 21 deletions ggshield/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from ggshield.core.config import Config
from ggshield.core.env_utils import load_dot_env
from ggshield.core.errors import ExitCode
from ggshield.core.ui import log_utils
from ggshield.core.ui import ensure_level, log_utils
from ggshield.core.ui.rich import RichGGShieldUI
from ggshield.utils.click import RealPath
from ggshield.utils.os import getenv_bool
Expand Down Expand Up @@ -57,19 +57,6 @@ def exit_code(ctx: click.Context, exit_code: int, **kwargs: Any) -> int:
return exit_code


def config_path_callback(
ctx: click.Context, param: click.Parameter, value: Optional[Path]
) -> Optional[Path]:
# The --config option is marked as "is_eager" to ensure it's called before all the
# others. This makes it the right place to create the configuration object.
if not ctx.obj:
ctx.obj = ContextObj()
ctx.obj.cache = Cache()

ctx.obj.config = Config(value)
return value


@click.group(
context_settings={"help_option_names": ["-h", "--help"]},
commands={
Expand All @@ -91,24 +78,38 @@ def config_path_callback(
type=RealPath(exists=True, resolve_path=True, file_okay=True, dir_okay=False),
is_eager=True,
help="Set a custom config file. Ignores local and global config files.",
callback=config_path_callback,
)
@add_common_options()
@click.version_option(version=__version__)
@click.pass_context
def cli(
ctx: click.Context,
*,
allow_self_signed: Optional[bool],
config_path: Optional[Path],
**kwargs: Any,
) -> None:
load_dot_env()
# Create ContextObj, load config
ctx.obj = ctx_obj = ContextObj()
ctx_obj.cache = Cache()
ctx_obj.config = Config(config_path)
user_config = ctx_obj.config.user_config

# If the config wants a higher UI level, set it now
if user_config.debug and ui.get_level() < ui.Level.DEBUG:
setup_debug_mode()
elif user_config.verbose and ui.get_level() < ui.Level.VERBOSE:
ensure_level(ui.Level.VERBOSE)

config = ContextObj.get(ctx).config
# Update allow_self_signed in the config
# TODO: this should be reworked: if a command which writes the config is called with
# --allow-self-signed, the config will contain `allow_self_signed: true`.
if allow_self_signed:
user_config.allow_self_signed = allow_self_signed

_set_color(ctx)
load_dot_env()

if config.user_config.debug:
# if `debug` is set in the configuration file, then setup debug mode now.
setup_debug_mode()
_set_color(ctx)


def _set_color(ctx: click.Context):
Expand Down
4 changes: 1 addition & 3 deletions ggshield/cmd/hmsl/check_secret_manager/hashicorp_vault.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
json_option,
text_json_format_option,
)
from ggshield.cmd.utils.context_obj import ContextObj
from ggshield.core import ui
from ggshield.core.errors import UnexpectedError
from ggshield.core.text_utils import pluralize
Expand Down Expand Up @@ -156,8 +155,7 @@ def check_hashicorp_vault_cmd(
f"Could not fetch {len(result.not_fetched_paths)} paths. "
"Make sure your token has access to all the secrets in your vault."
)
config = ContextObj.get(ctx).config
if config.user_config.verbose:
if ui.is_verbose():
ui.display_error("> The following paths could not be fetched:")
for path in result.not_fetched_paths:
ui.display_error(f"- {path}")
Expand Down
6 changes: 3 additions & 3 deletions ggshield/cmd/iac/scan/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ def iac_scan_all(
root = get_project_root_dir(directory)
relative_paths = [str(x.resolve().relative_to(root)) for x in paths]

if config.user_config.verbose:
ui.display_info("> Scanned files")
if ui.is_verbose():
ui.display_verbose("> Scanned files")
for filepath in relative_paths:
ui.display_info(f"- {click.format_filename(filepath)}")
ui.display_verbose(f"- {click.format_filename(filepath)}")

client = ctx_obj.client

Expand Down
21 changes: 7 additions & 14 deletions ggshield/cmd/iac/scan/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
from ggshield.cmd.utils.common_decorators import display_beta_warning, exception_wrapper
from ggshield.cmd.utils.common_options import directory_argument
from ggshield.cmd.utils.context_obj import ContextObj
from ggshield.core import ui
from ggshield.core.git_hooks.ci.get_scan_ci_parameters import (
NotAMergeRequestError,
get_scan_ci_parameters,
Expand Down Expand Up @@ -54,14 +55,9 @@ def scan_ci_cmd(
# we will work with branch names and deep commits, so we run a git fetch to ensure the
# branch names and commit sha are locally available
git(["fetch"], cwd=directory)
params = get_scan_ci_parameters(
ci_mode, wd=directory, verbose=config.user_config.verbose
)
params = get_scan_ci_parameters(ci_mode, wd=directory)
if params is None:
click.echo(
"No commit found in merge request, skipping scan.",
err=True,
)
ui.display_info("No commit found in merge request, skipping scan.")
return 0

current_commit, reference_commit = params
Expand All @@ -78,13 +74,10 @@ def scan_ci_cmd(
augment_unignored_issues(config.user_config, result)
return display_iac_scan_diff_result(ctx, directory, result)
except NotAMergeRequestError:
click.echo(
(
"WARNING: scan ci expects to be run in a merge-request pipeline.\n"
"No target branch could be identified, will perform a scan all instead.\n"
"This is a fallback behaviour, that will be removed in a future version."
),
err=True,
ui.display_warning(
"scan ci expects to be run in a merge-request pipeline.\n"
"No target branch could be identified, will perform a scan all instead.\n"
"This is a fallback behaviour, that will be removed in a future version."
)
result = iac_scan_all(
ctx, directory, scan_mode=ScanMode.CI_ALL, ci_mode=ci_mode
Expand Down
17 changes: 9 additions & 8 deletions ggshield/cmd/iac/scan/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,31 +115,32 @@ def iac_scan_diff(

check_directory_not_ignored(directory, exclusion_regexes)

verbose = config.user_config.verbose if config and config.user_config else False
verbose = ui.is_verbose()

if verbose:
if previous_ref is None:
ui.display_info("> No file to scan in reference.")
ui.display_verbose("> No file to scan in reference.")
else:
ui.display_info(f"> Scanned files in reference {previous_ref}")
ui.display_verbose(f"> Scanned files in reference {previous_ref}")
filepaths = filter_iac_filepaths(
directory, get_git_filepaths(directory, previous_ref)
)
for filepath in filepaths:
ui.display_info(f"- {click.format_filename(filepath)}")
ui.display_info("")
ui.display_verbose(f"- {click.format_filename(filepath)}")
ui.display_verbose("")

if current_ref is None:
current_ref = INDEX_REF if include_staged else "HEAD"
if verbose:
if include_staged:
ui.display_info("> Scanned files in current state (staged)")
ui.display_verbose("> Scanned files in current state (staged)")
else:
ui.display_info("> Scanned files in current state")
ui.display_verbose("> Scanned files in current state")
filepaths = filter_iac_filepaths(
directory, get_git_filepaths(directory=directory, ref=current_ref)
)
for filepath in filepaths:
ui.display_info(f"- {click.format_filename(filepath)}")
ui.display_verbose(f"- {click.format_filename(filepath)}")

modified_iac_files = []

Expand Down
2 changes: 1 addition & 1 deletion ggshield/cmd/iac/scan/iac_scan_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def create_output_handler(ctx: click.Context) -> IaCOutputHandler:
output_handler_cls = IaCJSONOutputHandler
else:
output_handler_cls = IaCTextOutputHandler
return output_handler_cls(verbose=ctx_obj.config.user_config.verbose)
return output_handler_cls(verbose=ui.is_verbose())


def handle_scan_error(client: GGClient, detail: Detail) -> None:
Expand Down
23 changes: 7 additions & 16 deletions ggshield/cmd/sca/scan/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
)
from ggshield.cmd.utils.common_decorators import exception_wrapper
from ggshield.cmd.utils.common_options import directory_argument
from ggshield.cmd.utils.context_obj import ContextObj
from ggshield.core import ui
from ggshield.core.git_hooks.ci.get_scan_ci_parameters import (
NotAMergeRequestError,
get_scan_ci_parameters,
Expand Down Expand Up @@ -63,22 +63,16 @@ def scan_ci_cmd(
ignore_not_fixable,
)

config = ContextObj.get(ctx).config
ci_mode = SupportedCI.from_ci_env()
output_handler = create_output_handler(ctx)

try:
# we will work with branch names and deep commits, so we run a git fetch to ensure the
# branch names and commit sha are locally available
git(["fetch"], cwd=directory)
params = get_scan_ci_parameters(
ci_mode, wd=directory, verbose=config.user_config.verbose
)
params = get_scan_ci_parameters(ci_mode, wd=directory)
if params is None:
click.echo(
"No commit found in merge request, skipping scan.",
err=True,
)
ui.display_info("No commit found in merge request, skipping scan.")
return 0

current_commit, reference_commit = params
Expand All @@ -94,13 +88,10 @@ def scan_ci_cmd(
scan = SCAScanDiffVulnerabilityCollection(id=str(directory), result=result)
return output_handler.process_scan_diff_result(scan)
except NotAMergeRequestError:
click.echo(
(
"WARNING: scan ci expects to be run in a merge-request pipeline.\n"
"No target branch could be identified, will perform a scan all instead.\n"
"This is a fallback behaviour, that will be removed in a future version."
),
err=True,
ui.display_warning(
"scan ci expects to be run in a merge-request pipeline.\n"
"No target branch could be identified, will perform a scan all instead.\n"
"This is a fallback behaviour, that will be removed in a future version."
)
result = sca_scan_all(ctx, directory=directory, scan_mode=ScanMode.CI_ALL)
scan = SCAScanAllVulnerabilityCollection(id=str(directory), result=result)
Expand Down
30 changes: 8 additions & 22 deletions ggshield/cmd/sca/scan/sca_scan_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,7 @@ def sca_scan_all(
check_directory_not_ignored(directory, exclusion_regexes)

sca_filepaths, sca_filter_status_code = get_sca_scan_all_filepaths(
directory=directory,
exclusion_regexes=exclusion_regexes,
verbose=config.user_config.verbose,
client=client,
directory=directory, exclusion_regexes=exclusion_regexes, client=client
)

if len(sca_filepaths) == 0:
Expand Down Expand Up @@ -109,10 +106,7 @@ def sca_scan_all(


def get_sca_scan_all_filepaths(
directory: Path,
exclusion_regexes: Set[Pattern[str]],
verbose: bool,
client: GGClient,
directory: Path, exclusion_regexes: Set[Pattern[str]], client: GGClient
) -> Tuple[List[str], int]:
"""
Retrieve SCA related files of a directory.
Expand Down Expand Up @@ -140,10 +134,10 @@ def get_sca_scan_all_filepaths(
# Only sca_files field is useful in the case of a full_scan,
# all the potential files already exist in `all_filepaths`
sca_files = response.sca_files
if verbose:
ui.display_info("> Scanned files:")
if ui.is_verbose():
ui.display_verbose("> Scanned files:")
for filename in sca_files:
ui.display_info(f"- {click.format_filename(filename)}")
ui.display_verbose(f"- {click.format_filename(filename)}")

return sca_files, response.status_code

Expand All @@ -159,7 +153,7 @@ def create_output_handler(ctx: click.Context) -> SCAOutputHandler:
output_handler_cls = SCATextOutputHandler
config = ctx_obj.config
return output_handler_cls(
verbose=config.user_config.verbose, exit_zero=config.user_config.exit_zero
verbose=ui.is_verbose(), exit_zero=config.user_config.exit_zero
)


Expand Down Expand Up @@ -204,19 +198,11 @@ def sca_scan_diff(
previous_files = []
else:
previous_files = sca_files_from_git_repo(
directory,
previous_ref,
client,
exclusion_regexes=exclusion_regexes,
verbose=config.user_config.verbose,
directory, previous_ref, client, exclusion_regexes=exclusion_regexes
)

current_files = sca_files_from_git_repo(
directory,
current_ref,
client,
exclusion_regexes=exclusion_regexes,
verbose=config.user_config.verbose,
directory, current_ref, client, exclusion_regexes=exclusion_regexes
)

if len(previous_files) == 0 and len(current_files) == 0:
Expand Down
6 changes: 2 additions & 4 deletions ggshield/cmd/secret/scan/archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,15 @@ def archive_cmd(

ctx_obj = ContextObj.get(ctx)
config = ctx_obj.config
verbose = config.user_config.verbose
files, binary_paths = create_files_from_paths(
paths=[temp_path],
exclusion_regexes=ctx_obj.exclusion_regexes,
list_files_mode=ListFilesMode.ALL,
)
if verbose:
print_file_list(files, binary_paths)
print_file_list(files, binary_paths)
ui.display_heading("Starting scan")

with ui.create_scanner_ui(len(files), verbose=verbose) as scanner_ui:
with ui.create_scanner_ui(len(files)) as scanner_ui:
scan_context = ScanContext(
scan_mode=ScanMode.ARCHIVE,
command_path=ctx.command_path,
Expand Down
8 changes: 3 additions & 5 deletions ggshield/cmd/secret/scan/changes.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ def changes_cmd(ctx: click.Context, **kwargs: Any) -> int:
default_branch = get_default_branch()
commit_list = get_list_commit_SHA(f"{default_branch}..HEAD")

if config.user_config.verbose:
ui.display_info(
f"Scan staged changes and {len(commit_list)} new {pluralize('commit', len(commit_list))}"
)
ui.display_verbose(
f"Scan staged changes and {len(commit_list)} new {pluralize('commit', len(commit_list))}"
)

scan_context = ScanContext(
scan_mode=ScanMode.CHANGE,
Expand All @@ -54,5 +53,4 @@ def changes_cmd(ctx: click.Context, **kwargs: Any) -> int:
exclusion_regexes=ctx_obj.exclusion_regexes,
secret_config=config.user_config.secret,
scan_context=scan_context,
verbose=config.user_config.verbose,
)
6 changes: 3 additions & 3 deletions ggshield/cmd/secret/scan/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
)
from ggshield.cmd.utils.common_decorators import exception_wrapper
from ggshield.cmd.utils.context_obj import ContextObj
from ggshield.core import ui
from ggshield.core.cache import ReadOnlyCache
from ggshield.core.git_hooks.ci import collect_commit_range_from_ci_env
from ggshield.core.scan import ScanContext, ScanMode
Expand All @@ -32,11 +33,10 @@ def ci_cmd(ctx: click.Context, **kwargs: Any) -> int:
if not (os.getenv("CI") or os.getenv("JENKINS_HOME") or os.getenv("BUILD_BUILDID")):
raise UsageError("`secret scan ci` should only be used in a CI environment.")

commit_list, ci_mode = collect_commit_range_from_ci_env(config.user_config.verbose)
commit_list, ci_mode = collect_commit_range_from_ci_env()
mode_header = f"{ScanMode.CI.value}/{ci_mode.value}"

if config.user_config.verbose:
click.echo(f"Commits to scan: {len(commit_list)}", err=True)
ui.display_verbose(f"Commits to scan: {len(commit_list)}")

scan_context = ScanContext(
scan_mode=mode_header,
Expand Down
1 change: 0 additions & 1 deletion ggshield/cmd/secret/scan/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ def docker_name_cmd(
cache=ctx_obj.cache,
secret_config=config.user_config.secret,
scan_context=scan_context,
verbose=config.user_config.verbose,
)

return output_handler.process_scan(scan)
Loading

0 comments on commit 77fa6a9

Please sign in to comment.