Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 4 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ This guide walks you through both installation and usage.
1. [Options](#options)
1. [Severity Threshold](#severity-option)
2. [Monitor](#monitor-option)
3. [Report](#report-option)
4. [Package Vulnerabilities](#package-vulnerabilities-option)
5. [License Compliance](#license-compliance-option)
6. [Lock Restore](#lock-restore-option)
3. [Package Vulnerabilities](#package-vulnerabilities-option)
4. [License Compliance](#license-compliance-option)
5. [Lock Restore](#lock-restore-option)
2. [Repository Scan](#repository-scan)
1. [Branch Option](#branch-option)
3. [Path Scan](#path-scan)
Expand Down Expand Up @@ -282,7 +281,7 @@ The following are the options and commands available with the Cycode CLI applica
| [configure](#using-the-configure-command) | Initial command to configure your CLI client authentication. |
| [ignore](#ignoring-scan-results) | Ignores a specific value, path or rule ID. |
| [scan](#running-a-scan) | Scan the content for Secrets/IaC/SCA/SAST violations. You`ll need to specify which scan type to perform: commit-history/path/repository/etc. |
| [report](#report-command) | Generate report. You`ll need to specify which report type to perform. |
| [report](#report-command) | Generate report. You`ll need to specify which report type to perform as SBOM. |
| status | Show the CLI status and exit. |

# Scan Command
Expand All @@ -301,7 +300,6 @@ The Cycode CLI application offers several types of scans so that you can choose
| `--severity-threshold [INFO\|LOW\|MEDIUM\|HIGH\|CRITICAL]` | Show only violations at the specified level or higher. |
| `--sca-scan` | Specify the SCA scan you wish to execute (`package-vulnerabilities`/`license-compliance`). The default is both. |
| `--monitor` | 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). |
| `--report` | When specified, a violations report will be generated. A URL link to the report will be printed as an output to the command execution. |
| `--no-restore` | When specified, Cycode will not run restore command. Will scan direct dependencies ONLY! |
| `--gradle-all-sub-projects` | When specified, Cycode will run gradle restore command for all sub projects. Should run from root project directory ONLY! |
| `--help` | Show options for given command. |
Expand Down Expand Up @@ -339,28 +337,6 @@ When using this option, the scan results from this scan will appear in the knowl
> [!WARNING]
> You must be an `owner` or an `admin` in Cycode to view the knowledge graph page.

#### Report Option

> [!NOTE]
> This option is not available to IaC scans.

To push scan results tied to the [SCA policies](https://docs.cycode.com/docs/sca-policies) found in the Repository scan to Cycode, add the argument `--report` to the scan command.

`cycode scan -t sca --report repository ~/home/git/codebase`

In the same way, you can push scan results of Secrets and SAST scans to Cycode by adding the `--report` option to the scan command.

When using this option, the scan results from this scan will appear in the On-Demand Scans section of Cycode. To get to this page, click the link that appears after the printed results:

> [!WARNING]
> You must be an `owner` or an `admin` in Cycode to view this page.

![cli-report](https://raw.githubusercontent.com/cycodehq/cycode-cli/main/images/sca_report_url.png)

The report page will look something like below:

![](https://raw.githubusercontent.com/cycodehq/cycode-cli/main/images/scan_details.png)

#### Package Vulnerabilities Option

> [!NOTE]
Expand Down
4 changes: 4 additions & 0 deletions cycode/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from cycode.cli.consts import PROGRAM_NAME
from cycode.cli.main import app

app(prog_name=PROGRAM_NAME)
3 changes: 0 additions & 3 deletions cycode/cli/__main__.py

This file was deleted.

47 changes: 19 additions & 28 deletions cycode/cli/app.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import logging
from pathlib import Path
from typing import Annotated, Optional

import typer
from typer import rich_utils
from typer._completion_classes import completion_init
from typer.completion import install_callback, show_callback

from cycode import __version__
from cycode.cli.apps import ai_remediation, auth, configure, ignore, report, scan, status
from cycode.cli.cli_types import ExportTypeOption, OutputTypeOption
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
Expand All @@ -24,14 +24,10 @@
# 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[/]



For more details and advanced usage, visit: [link={_cycode_cli_docs}]{_cycode_cli_docs}[/link]
"""
_cycode_cli_epilog = f'[bold]Documentation:[/] [link={_cycode_cli_docs}]{_cycode_cli_docs}[/link]'

app = typer.Typer(
pretty_exceptions_show_locals=False,
Expand Down Expand Up @@ -64,13 +60,14 @@ def check_latest_version_on_close(ctx: typer.Context) -> None:


def export_if_needed_on_close(ctx: typer.Context) -> None:
scan_finalized = ctx.obj.get('scan_finalized')
printer = ctx.obj.get('console_printer')
if printer.is_recording:
if scan_finalized and printer.is_recording:
printer.export()


_AUTH_RICH_HELP_PANEL = 'Authentication options'
_COMPLETION_RICH_HELP_PANEL = 'Completion options'
_EXPORT_RICH_HELP_PANEL = 'Export options'


@app.callback()
Expand All @@ -90,25 +87,18 @@ def app_callback(
Optional[str],
typer.Option(hidden=True, help='Characteristic JSON object that lets servers identify the application.'),
] = None,
export_type: Annotated[
ExportTypeOption,
client_secret: Annotated[
Optional[str],
typer.Option(
'--export-type',
case_sensitive=False,
help='Specify the export type. '
'HTML and SVG will export terminal output and rely on --output option. '
'JSON always exports JSON.',
rich_help_panel=_EXPORT_RICH_HELP_PANEL,
help='Specify a Cycode client secret for this specific scan execution.',
rich_help_panel=_AUTH_RICH_HELP_PANEL,
),
] = ExportTypeOption.JSON,
export_file: Annotated[
Optional[Path],
] = None,
client_id: Annotated[
Optional[str],
typer.Option(
'--export-file',
help='Export file. Path to the file where the export will be saved. ',
dir_okay=False,
writable=True,
rich_help_panel=_EXPORT_RICH_HELP_PANEL,
help='Specify a Cycode client ID for this specific scan execution.',
rich_help_panel=_AUTH_RICH_HELP_PANEL,
),
] = None,
_: Annotated[
Expand Down Expand Up @@ -150,10 +140,11 @@ def app_callback(
if output == OutputTypeOption.JSON:
no_progress_meter = True

ctx.obj['client_id'] = client_id
ctx.obj['client_secret'] = client_secret

ctx.obj['progress_bar'] = get_progress_bar(hidden=no_progress_meter, sections=SCAN_PROGRESS_BAR_SECTIONS)

ctx.obj['export_type'] = export_type
ctx.obj['export_file'] = export_file
ctx.obj['console_printer'] = ConsolePrinter(ctx)
ctx.call_on_close(lambda: export_if_needed_on_close(ctx))

Expand Down
6 changes: 3 additions & 3 deletions cycode/cli/apps/ai_remediation/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

app = typer.Typer()

_ai_remediation_epilog = """
Note: AI remediation suggestions are generated automatically and should be reviewed before applying.
"""
_ai_remediation_epilog = (
'Note: AI remediation suggestions are generated automatically and should be reviewed before applying.'
)

app.command(
name='ai-remediation',
Expand Down
2 changes: 1 addition & 1 deletion cycode/cli/apps/ai_remediation/ai_remediation_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def ai_remediation_command(
* `cycode ai-remediation <detection_id>`: View remediation guidance
* `cycode ai-remediation <detection_id> --fix`: Apply suggested fixes
"""
client = get_scan_cycode_client()
client = get_scan_cycode_client(ctx)

try:
remediation_markdown = client.get_ai_remediation(detection_id)
Expand Down
7 changes: 1 addition & 6 deletions cycode/cli/apps/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
from cycode.cli.apps.auth.auth_command import auth_command

_auth_command_docs = 'https://github.com/cycodehq/cycode-cli/blob/main/README.md#using-the-auth-command'
_auth_command_epilog = f"""[bold]Documentation[/]



For more details and advanced usage, visit: [link={_auth_command_docs}]{_auth_command_docs}[/link]
"""
_auth_command_epilog = f'[bold]Documentation:[/] [link={_auth_command_docs}]{_auth_command_docs}[/link]'

app = typer.Typer(no_args_is_help=False)
app.command(name='auth', epilog=_auth_command_epilog, short_help='Authenticate your machine with Cycode.')(auth_command)
5 changes: 4 additions & 1 deletion cycode/cli/apps/auth/auth_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
def get_authorization_info(ctx: 'Context') -> Optional[AuthInfo]:
printer = ctx.obj.get('console_printer')

client_id, client_secret = CredentialsManager().get_credentials()
client_id, client_secret = ctx.obj.get('client_id'), ctx.obj.get('client_secret')
if not client_id or not client_secret:
client_id, client_secret = CredentialsManager().get_credentials()

if not client_id or not client_secret:
return None

Expand Down
7 changes: 1 addition & 6 deletions cycode/cli/apps/configure/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
from cycode.cli.apps.configure.configure_command import configure_command

_configure_command_docs = 'https://github.com/cycodehq/cycode-cli/blob/main/README.md#using-the-configure-command'
_configure_command_epilog = f"""[bold]Documentation[/]



For more details and advanced usage, visit: [link={_configure_command_docs}]{_configure_command_docs}[/link]
"""
_configure_command_epilog = f'[bold]Documentation:[/] [link={_configure_command_docs}]{_configure_command_docs}[/link]'


app = typer.Typer(no_args_is_help=True)
Expand Down
2 changes: 1 addition & 1 deletion cycode/cli/apps/report/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
from cycode.cli.apps.report.report_command import report_command

app = typer.Typer(name='report', no_args_is_help=True)
app.callback(short_help='Generate report. You`ll need to specify which report type to perform.')(report_command)
app.callback(short_help='Generate report. You`ll need to specify which report type to perform as SBOM.')(report_command)
app.add_typer(sbom.app)
2 changes: 1 addition & 1 deletion cycode/cli/apps/report/sbom/path/path_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def path_command(
) -> None:
add_breadcrumb('path')

client = get_report_cycode_client()
client = get_report_cycode_client(ctx)
report_parameters = ctx.obj['report_parameters']
output_format = report_parameters.output_format
output_file = ctx.obj['output_file']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def repository_url_command(
progress_bar.start()
progress_bar.set_section_length(SbomReportProgressBarSection.PREPARE_LOCAL_FILES)

client = get_report_cycode_client()
client = get_report_cycode_client(ctx)
report_parameters = ctx.obj['report_parameters']
output_file = ctx.obj['output_file']
output_format = report_parameters.output_format
Expand Down
7 changes: 1 addition & 6 deletions cycode/cli/apps/scan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,7 @@
app = typer.Typer(name='scan', no_args_is_help=True)

_scan_command_docs = 'https://github.com/cycodehq/cycode-cli/blob/main/README.md#scan-command'
_scan_command_epilog = f"""[bold]Documentation[/]



For more details and advanced usage, visit: [link={_scan_command_docs}]{_scan_command_docs}[/link]
"""
_scan_command_epilog = f'[bold]Documentation:[/] [link={_scan_command_docs}]{_scan_command_docs}[/link]'

app.callback(
short_help='Scan the content for Secrets, IaC, SCA, and SAST violations.',
Expand Down
11 changes: 4 additions & 7 deletions cycode/cli/apps/scan/code_scanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ def scan_documents(
scan_batch_thread_func, scan_type, documents_to_scan, progress_bar=progress_bar
)

aggregation_report_url = _try_get_aggregation_report_url_if_needed(scan_parameters, ctx.obj['client'], scan_type)
aggregation_report_url = _try_get_aggregation_report_url(scan_parameters, ctx.obj['client'], scan_type)
_set_aggregation_report_url(ctx, aggregation_report_url)

progress_bar.set_section_length(ScanProgressBarSection.GENERATE_REPORT, 1)
Expand Down Expand Up @@ -571,6 +571,7 @@ def print_results(
ctx: typer.Context, local_scan_results: list[LocalScanResult], errors: Optional[dict[str, 'CliError']] = None
) -> None:
printer = ctx.obj.get('console_printer')
printer.update_ctx(ctx)
printer.print_scan_results(local_scan_results, errors)


Expand Down Expand Up @@ -640,7 +641,6 @@ def parse_pre_receive_input() -> str:
def _get_default_scan_parameters(ctx: typer.Context) -> dict:
return {
'monitor': ctx.obj.get('monitor'),
'report': ctx.obj.get('report'),
'package_vulnerabilities': ctx.obj.get('package-vulnerabilities'),
'license_compliance': ctx.obj.get('license-compliance'),
'command_type': ctx.info_name.replace('-', '_'), # save backward compatibility
Expand Down Expand Up @@ -956,7 +956,7 @@ def _get_scan_result(
did_detect=True,
detections_per_file=_map_detections_per_file_and_commit_id(scan_type, scan_raw_detections),
scan_id=scan_id,
report_url=_try_get_aggregation_report_url_if_needed(scan_parameters, cycode_client, scan_type),
report_url=_try_get_aggregation_report_url(scan_parameters, cycode_client, scan_type),
)


Expand All @@ -972,12 +972,9 @@ def _set_aggregation_report_url(ctx: typer.Context, aggregation_report_url: Opti
ctx.obj['aggregation_report_url'] = aggregation_report_url


def _try_get_aggregation_report_url_if_needed(
def _try_get_aggregation_report_url(
scan_parameters: dict, cycode_client: 'ScanClient', scan_type: str
) -> Optional[str]:
if not scan_parameters.get('report', False):
return None

aggregation_id = scan_parameters.get('aggregation_id')
if aggregation_id is None:
return None
Expand Down
Loading