From 34819475e70ef3f803cda859aaa57cf5908666c5 Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Mon, 9 Oct 2023 21:21:42 +0200 Subject: [PATCH 1/2] CM-27690 - Configure API URL and APP URL --- cycode/cli/commands/configure/__init__.py | 0 .../commands/configure/configure_command.py | 137 +++++++++++ cycode/cli/commands/ignore/__init__.py | 0 .../ignore/ignore_command.py} | 79 +------ cycode/cli/main.py | 7 +- .../cli/user_settings/config_file_manager.py | 8 +- .../user_settings/configuration_manager.py | 4 - tests/cli/test_configure_command.py | 220 ++++++++++++++++++ .../test_user_settings_commands.py | 123 ---------- 9 files changed, 374 insertions(+), 204 deletions(-) create mode 100644 cycode/cli/commands/configure/__init__.py create mode 100644 cycode/cli/commands/configure/configure_command.py create mode 100644 cycode/cli/commands/ignore/__init__.py rename cycode/cli/{user_settings/user_settings_commands.py => commands/ignore/ignore_command.py} (56%) create mode 100644 tests/cli/test_configure_command.py delete mode 100644 tests/user_settings/test_user_settings_commands.py diff --git a/cycode/cli/commands/configure/__init__.py b/cycode/cli/commands/configure/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cycode/cli/commands/configure/configure_command.py b/cycode/cli/commands/configure/configure_command.py new file mode 100644 index 00000000..04001eaa --- /dev/null +++ b/cycode/cli/commands/configure/configure_command.py @@ -0,0 +1,137 @@ +from typing import Optional + +import click + +from cycode.cli import config, consts +from cycode.cli.user_settings.configuration_manager import ConfigurationManager +from cycode.cli.user_settings.credentials_manager import CredentialsManager +from cycode.cli.utils.string_utils import obfuscate_text + +_URLS_UPDATED_SUCCESSFULLY_MESSAGE = 'Successfully configured Cycode URLs! Saved to: {filename}' +_URLS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE = ( + 'Note that the URLs (APP and API) that already exist in environment variables ' + f'({consts.CYCODE_API_URL_ENV_VAR_NAME} and {consts.CYCODE_APP_URL_ENV_VAR_NAME}) ' + 'take precedent over these URLs; either update or remove the environment variables.' +) +_CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE = 'Successfully configured CLI credentials! Saved to: {filename}' +_CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE = ( + 'Note that the credentials that already exist in environment variables ' + f'({config.CYCODE_CLIENT_ID_ENV_VAR_NAME} and {config.CYCODE_CLIENT_SECRET_ENV_VAR_NAME}) ' + 'take precedent over these credentials; either update or remove the environment variables.' +) +_CREDENTIALS_MANAGER = CredentialsManager() +_CONFIGURATION_MANAGER = ConfigurationManager() + + +@click.command(short_help='Initial command to configure your CLI client authentication.') +def configure_command() -> None: + """Configure your CLI client authentication manually.""" + global_config_manager = _CONFIGURATION_MANAGER.global_config_file_manager + + current_api_url = global_config_manager.get_api_url() + current_app_url = global_config_manager.get_app_url() + api_url = _get_api_url_input(current_api_url) + app_url = _get_app_url_input(current_app_url) + + config_updated = False + if _should_update_value(current_api_url, api_url): + global_config_manager.update_api_base_url(api_url) + config_updated = True + if _should_update_value(current_app_url, app_url): + global_config_manager.update_app_base_url(app_url) + config_updated = True + + current_client_id, current_client_secret = _CREDENTIALS_MANAGER.get_credentials_from_file() + client_id = _get_client_id_input(current_client_id) + client_secret = _get_client_secret_input(current_client_secret) + + credentials_updated = False + if _should_update_value(current_client_id, client_id) or _should_update_value(current_client_secret, client_secret): + credentials_updated = True + _CREDENTIALS_MANAGER.update_credentials_file(client_id, client_secret) + + if config_updated: + click.echo(_get_urls_update_result_message()) + if credentials_updated: + click.echo(_get_credentials_update_result_message()) + + +def _get_client_id_input(current_client_id: Optional[str]) -> Optional[str]: + prompt_text = 'Cycode Client ID' + + prompt_suffix = ' (optional): ' + if current_client_id: + prompt_suffix = f' [{obfuscate_text(current_client_id)}]: ' + + new_client_id = click.prompt(text=prompt_text, prompt_suffix=prompt_suffix, default='', show_default=False) + return new_client_id or current_client_id + + +def _get_client_secret_input(current_client_secret: Optional[str]) -> Optional[str]: + prompt_text = 'Cycode Client Secret' + + prompt_suffix = ' (optional): ' + if current_client_secret: + prompt_suffix = f' [{obfuscate_text(current_client_secret)}]: ' + + new_client_secret = click.prompt(text=prompt_text, prompt_suffix=prompt_suffix, default='', show_default=False) + return new_client_secret or current_client_secret + + +def _get_app_url_input(current_app_url: Optional[str]) -> str: + prompt_text = 'Cycode APP URL' + + default = consts.DEFAULT_CYCODE_APP_URL + if current_app_url: + default = current_app_url + + return click.prompt(text=prompt_text, default=default, type=click.STRING) + + +def _get_api_url_input(current_api_url: Optional[str]) -> str: + prompt_text = 'Cycode API URL' + + default = consts.DEFAULT_CYCODE_API_URL + if current_api_url: + default = current_api_url + + return click.prompt(text=prompt_text, default=default, type=click.STRING) + + +def _get_credentials_update_result_message() -> str: + success_message = _CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE.format(filename=_CREDENTIALS_MANAGER.get_filename()) + if _are_credentials_exist_in_environment_variables(): + return f'{success_message}. {_CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE}' + + return success_message + + +def _are_credentials_exist_in_environment_variables() -> bool: + client_id, client_secret = _CREDENTIALS_MANAGER.get_credentials_from_environment_variables() + return any([client_id, client_secret]) + + +def _get_urls_update_result_message() -> str: + success_message = _URLS_UPDATED_SUCCESSFULLY_MESSAGE.format( + filename=_CONFIGURATION_MANAGER.global_config_file_manager.get_filename() + ) + if _are_urls_exist_in_environment_variables(): + return f'{success_message}. {_URLS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE}' + + return success_message + + +def _are_urls_exist_in_environment_variables() -> bool: + api_url = _CONFIGURATION_MANAGER.get_api_url_from_environment_variables() + app_url = _CONFIGURATION_MANAGER.get_app_url_from_environment_variables() + return any([api_url, app_url]) + + +def _should_update_value( + old_value: Optional[str], + new_value: Optional[str], +) -> bool: + if not new_value: + return False + + return old_value != new_value diff --git a/cycode/cli/commands/ignore/__init__.py b/cycode/cli/commands/ignore/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cycode/cli/user_settings/user_settings_commands.py b/cycode/cli/commands/ignore/ignore_command.py similarity index 56% rename from cycode/cli/user_settings/user_settings_commands.py rename to cycode/cli/commands/ignore/ignore_command.py index 9629de1e..66515447 100644 --- a/cycode/cli/user_settings/user_settings_commands.py +++ b/cycode/cli/commands/ignore/ignore_command.py @@ -1,41 +1,21 @@ -import os.path +import os import re -from typing import Optional import click from cycode.cli import consts from cycode.cli.config import config, configuration_manager -from cycode.cli.user_settings.credentials_manager import CredentialsManager from cycode.cli.utils.path_utils import get_absolute_path -from cycode.cli.utils.string_utils import hash_string_to_sha256, obfuscate_text +from cycode.cli.utils.string_utils import hash_string_to_sha256 from cycode.cyclient import logger -CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE = 'Successfully configured CLI credentials!' -CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE = ( - 'Note that the credentials that already exist in environment' - ' variables (CYCODE_CLIENT_ID and CYCODE_CLIENT_SECRET) take' - ' precedent over these credentials; either update or remove ' - 'the environment variables.' -) -credentials_manager = CredentialsManager() - -@click.command( - short_help='Initial command to authenticate your CLI client with Cycode using a client ID and client secret.' -) -def set_credentials() -> None: - """Authenticates your CLI client with Cycode manually by using a client ID and client secret.""" - click.echo(f'Update credentials in file ({credentials_manager.get_filename()})') - current_client_id, current_client_secret = credentials_manager.get_credentials_from_file() - client_id = _get_client_id_input(current_client_id) - client_secret = _get_client_secret_input(current_client_secret) +def _is_path_to_ignore_exists(path: str) -> bool: + return os.path.exists(path) - if not _should_update_credentials(current_client_id, current_client_secret, client_id, client_secret): - return - credentials_manager.update_credentials_file(client_id, client_secret) - click.echo(_get_credentials_update_result_message()) +def _is_package_pattern_valid(package: str) -> bool: + return re.search('^[^@]+@[^@]+$', package) is not None @click.command(short_help='Ignores a specific value, path or rule ID.') @@ -83,7 +63,7 @@ def set_credentials() -> None: required=False, help='Add an ignore rule to the global CLI config.', ) -def add_exclusions( +def ignore_command( by_value: str, by_sha: str, by_path: str, by_rule: str, by_package: str, scan_type: str, is_global: bool ) -> None: """Ignores a specific value, path or rule ID.""" @@ -126,48 +106,3 @@ def add_exclusions( }, ) configuration_manager.add_exclusion(configuration_scope, scan_type, exclusion_type, exclusion_value) - - -def _get_client_id_input(current_client_id: str) -> str: - new_client_id = click.prompt( - f'cycode client id [{_obfuscate_credential(current_client_id)}]', default='', show_default=False - ) - - return new_client_id if new_client_id else current_client_id - - -def _get_client_secret_input(current_client_secret: str) -> str: - new_client_secret = click.prompt( - f'cycode client secret [{_obfuscate_credential(current_client_secret)}]', default='', show_default=False - ) - return new_client_secret if new_client_secret else current_client_secret - - -def _get_credentials_update_result_message() -> str: - if not _are_credentials_exist_in_environment_variables(): - return CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE - - return CREDENTIALS_UPDATED_SUCCESSFULLY_MESSAGE + ' ' + CREDENTIALS_ARE_SET_IN_ENVIRONMENT_VARIABLES_MESSAGE - - -def _are_credentials_exist_in_environment_variables() -> bool: - client_id, client_secret = credentials_manager.get_credentials_from_environment_variables() - return client_id is not None or client_secret is not None - - -def _should_update_credentials( - current_client_id: str, current_client_secret: str, new_client_id: str, new_client_secret: str -) -> bool: - return current_client_id != new_client_id or current_client_secret != new_client_secret - - -def _obfuscate_credential(credential: Optional[str]) -> str: - return '' if not credential else obfuscate_text(credential) - - -def _is_path_to_ignore_exists(path: str) -> bool: - return os.path.exists(path) - - -def _is_package_pattern_valid(package: str) -> bool: - return re.search('^[^@]+@[^@]+$', package) is not None diff --git a/cycode/cli/main.py b/cycode/cli/main.py index efa2b200..082cca3a 100644 --- a/cycode/cli/main.py +++ b/cycode/cli/main.py @@ -8,6 +8,8 @@ from cycode import __version__ from cycode.cli import code_scanner from cycode.cli.auth.auth_command import authenticate +from cycode.cli.commands.configure.configure_command import configure_command +from cycode.cli.commands.ignore.ignore_command import ignore_command from cycode.cli.commands.report.report_command import report_command from cycode.cli.config import config from cycode.cli.consts import ( @@ -19,7 +21,6 @@ ) from cycode.cli.models import Severity from cycode.cli.user_settings.configuration_manager import ConfigurationManager -from cycode.cli.user_settings.user_settings_commands import add_exclusions, set_credentials from cycode.cli.utils import scan_utils from cycode.cli.utils.get_api_client import get_scan_cycode_client from cycode.cli.utils.progress_bar import SCAN_PROGRESS_BAR_SECTIONS, get_progress_bar @@ -183,8 +184,8 @@ def version(context: click.Context) -> None: commands={ 'scan': code_scan, 'report': report_command, - 'configure': set_credentials, - 'ignore': add_exclusions, + 'configure': configure_command, + 'ignore': ignore_command, 'auth': authenticate, 'version': version, }, diff --git a/cycode/cli/user_settings/config_file_manager.py b/cycode/cli/user_settings/config_file_manager.py index acec4d17..e4e5e6b1 100644 --- a/cycode/cli/user_settings/config_file_manager.py +++ b/cycode/cli/user_settings/config_file_manager.py @@ -52,8 +52,12 @@ def get_exclude_detections_in_deleted_lines(self, command_scan_type: str) -> Opt command_scan_type, self.EXCLUDE_DETECTIONS_IN_DELETED_LINES ) - def update_base_url(self, base_url: str) -> None: - update_data = {self.ENVIRONMENT_SECTION_NAME: {self.API_URL_FIELD_NAME: base_url}} + def update_api_base_url(self, api_url: str) -> None: + update_data = {self.ENVIRONMENT_SECTION_NAME: {self.API_URL_FIELD_NAME: api_url}} + self.write_content_to_file(update_data) + + def update_app_base_url(self, app_url: str) -> None: + update_data = {self.ENVIRONMENT_SECTION_NAME: {self.APP_URL_FIELD_NAME: app_url}} self.write_content_to_file(update_data) def get_installation_id(self) -> Optional[str]: diff --git a/cycode/cli/user_settings/configuration_manager.py b/cycode/cli/user_settings/configuration_manager.py index 65da08fc..4ceec970 100644 --- a/cycode/cli/user_settings/configuration_manager.py +++ b/cycode/cli/user_settings/configuration_manager.py @@ -76,10 +76,6 @@ def _merge_exclusions(self, local_exclusions: Dict, global_exclusions: Dict) -> keys = set(list(local_exclusions.keys()) + list(global_exclusions.keys())) return {key: local_exclusions.get(key, []) + global_exclusions.get(key, []) for key in keys} - def update_base_url(self, base_url: str, scope: str = 'local') -> None: - config_file_manager = self.get_config_file_manager(scope) - config_file_manager.update_base_url(base_url) - def get_or_create_installation_id(self) -> str: config_file_manager = self.get_config_file_manager() diff --git a/tests/cli/test_configure_command.py b/tests/cli/test_configure_command.py new file mode 100644 index 00000000..4c42971b --- /dev/null +++ b/tests/cli/test_configure_command.py @@ -0,0 +1,220 @@ +from typing import TYPE_CHECKING + +from click.testing import CliRunner + +from cycode.cli.commands.configure.configure_command import configure_command + +if TYPE_CHECKING: + from pytest_mock import MockerFixture + + +def test_configure_command_no_exist_values_in_file(mocker: 'MockerFixture') -> None: + # Arrange + app_url_user_input = 'new app url' + api_url_user_input = 'new api url' + client_id_user_input = 'new client id' + client_secret_user_input = 'new client secret' + + mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', + return_value=(None, None), + ) + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_api_url', + return_value=None, + ) + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_app_url', + return_value=None, + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch( + 'click.prompt', + side_effect=[api_url_user_input, app_url_user_input, client_id_user_input, client_secret_user_input], + ) + + mocked_update_credentials = mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' + ) + mocked_update_api_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_api_base_url' + ) + mocked_update_app_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_app_base_url' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + mocked_update_credentials.assert_called_once_with(client_id_user_input, client_secret_user_input) + mocked_update_api_base_url.assert_called_once_with(api_url_user_input) + mocked_update_app_base_url.assert_called_once_with(app_url_user_input) + + +def test_configure_command_update_current_configs_in_files(mocker: 'MockerFixture') -> None: + # Arrange + app_url_user_input = 'new app url' + api_url_user_input = 'new api url' + client_id_user_input = 'new client id' + client_secret_user_input = 'new client secret' + + mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', + return_value=('client id file', 'client secret file'), + ) + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_api_url', + return_value='api url file', + ) + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_app_url', + return_value='app url file', + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch( + 'click.prompt', + side_effect=[api_url_user_input, app_url_user_input, client_id_user_input, client_secret_user_input], + ) + + mocked_update_credentials = mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' + ) + mocked_update_api_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_api_base_url' + ) + mocked_update_app_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_app_base_url' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + mocked_update_credentials.assert_called_once_with(client_id_user_input, client_secret_user_input) + mocked_update_api_base_url.assert_called_once_with(api_url_user_input) + mocked_update_app_base_url.assert_called_once_with(app_url_user_input) + + +def test_set_credentials_update_only_client_id(mocker: 'MockerFixture') -> None: + # Arrange + client_id_user_input = 'new client id' + current_client_id = 'client secret file' + mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', + return_value=('client id file', 'client secret file'), + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch('click.prompt', side_effect=['', '', client_id_user_input, '']) + mocked_update_credentials = mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + mocked_update_credentials.assert_called_once_with(client_id_user_input, current_client_id) + + +def test_configure_command_update_only_client_secret(mocker: 'MockerFixture') -> None: + # Arrange + client_secret_user_input = 'new client secret' + current_client_id = 'client secret file' + + mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', + return_value=(current_client_id, 'client secret file'), + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch('click.prompt', side_effect=['', '', '', client_secret_user_input]) + mocked_update_credentials = mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + mocked_update_credentials.assert_called_once_with(current_client_id, client_secret_user_input) + + +def test_configure_command_update_only_api_url(mocker: 'MockerFixture') -> None: + # Arrange + api_url_user_input = 'new api url' + current_api_url = 'api url' + + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_api_url', + return_value=current_api_url, + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch('click.prompt', side_effect=[api_url_user_input, '', '', '']) + mocked_update_api_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_api_base_url' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + mocked_update_api_base_url.assert_called_once_with(api_url_user_input) + + +def test_configure_command_should_not_update_credentials_file(mocker: 'MockerFixture') -> None: + # Arrange + client_id_user_input = '' + client_secret_user_input = '' + + mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', + return_value=('client id file', 'client secret file'), + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch('click.prompt', side_effect=['', '', client_id_user_input, client_secret_user_input]) + mocked_update_credentials = mocker.patch( + 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + assert not mocked_update_credentials.called + + +def test_configure_command_should_not_update_config_file(mocker: 'MockerFixture') -> None: + # Arrange + app_url_user_input = '' + api_url_user_input = '' + + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_api_url', + return_value='api url file', + ) + mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.get_app_url', + return_value='app url file', + ) + + # side effect - multiple return values, each item in the list represents return of a call + mocker.patch('click.prompt', side_effect=[api_url_user_input, app_url_user_input, '', '']) + mocked_update_api_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_api_base_url' + ) + mocked_update_app_base_url = mocker.patch( + 'cycode.cli.user_settings.config_file_manager.ConfigFileManager.update_app_base_url' + ) + + # Act + CliRunner().invoke(configure_command) + + # Assert + assert not mocked_update_api_base_url.called + assert not mocked_update_app_base_url.called diff --git a/tests/user_settings/test_user_settings_commands.py b/tests/user_settings/test_user_settings_commands.py deleted file mode 100644 index 6ef0cf2e..00000000 --- a/tests/user_settings/test_user_settings_commands.py +++ /dev/null @@ -1,123 +0,0 @@ -from typing import TYPE_CHECKING - -from click.testing import CliRunner - -from cycode.cli.user_settings.user_settings_commands import set_credentials - -if TYPE_CHECKING: - from pytest_mock import MockerFixture - - -def test_set_credentials_no_exist_credentials_in_file(mocker: 'MockerFixture') -> None: - # Arrange - client_id_user_input = 'new client id' - client_secret_user_input = 'new client secret' - mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', - return_value=(None, None), - ) - - # side effect - multiple return values, each item in the list represent return of a call - mocker.patch('click.prompt', side_effect=[client_id_user_input, client_secret_user_input]) - mocked_update_credentials = mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' - ) - click = CliRunner() - - # Act - click.invoke(set_credentials) - - # Assert - mocked_update_credentials.assert_called_once_with(client_id_user_input, client_secret_user_input) - - -def test_set_credentials_update_current_credentials_in_file(mocker: 'MockerFixture') -> None: - # Arrange - client_id_user_input = 'new client id' - client_secret_user_input = 'new client secret' - mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', - return_value=('client id file', 'client secret file'), - ) - - # side effect - multiple return values, each item in the list represents return of a call - mocker.patch('click.prompt', side_effect=[client_id_user_input, client_secret_user_input]) - mocked_update_credentials = mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' - ) - click = CliRunner() - - # Act - click.invoke(set_credentials) - - # Assert - mocked_update_credentials.assert_called_once_with(client_id_user_input, client_secret_user_input) - - -def test_set_credentials_update_only_client_id(mocker: 'MockerFixture') -> None: - # Arrange - client_id_user_input = 'new client id' - current_client_id = 'client secret file' - mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', - return_value=('client id file', 'client secret file'), - ) - - # side effect - multiple return values, each item in the list represent return of a call - mocker.patch('click.prompt', side_effect=[client_id_user_input, '']) - mocked_update_credentials = mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' - ) - click = CliRunner() - - # Act - click.invoke(set_credentials) - - # Assert - mocked_update_credentials.assert_called_once_with(client_id_user_input, current_client_id) - - -def test_set_credentials_update_only_client_secret(mocker: 'MockerFixture') -> None: - # Arrange - client_secret_user_input = 'new client secret' - current_client_id = 'client secret file' - mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', - return_value=(current_client_id, 'client secret file'), - ) - - # side effect - multiple return values, each item in the list represent return of a call - mocker.patch('click.prompt', side_effect=['', client_secret_user_input]) - mocked_update_credentials = mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' - ) - click = CliRunner() - - # Act - click.invoke(set_credentials) - - # Assert - mocked_update_credentials.assert_called_once_with(current_client_id, client_secret_user_input) - - -def test_set_credentials_should_not_update_file(mocker: 'MockerFixture') -> None: - # Arrange - client_id_user_input = '' - client_secret_user_input = '' - mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.get_credentials_from_file', - return_value=('client id file', 'client secret file'), - ) - - # side effect - multiple return values, each item in the list represent return of a call - mocker.patch('click.prompt', side_effect=[client_id_user_input, client_secret_user_input]) - mocked_update_credentials = mocker.patch( - 'cycode.cli.user_settings.credentials_manager.CredentialsManager.update_credentials_file' - ) - click = CliRunner() - - # Act - click.invoke(set_credentials) - - # Assert - assert not mocked_update_credentials.called From b3ef450dcead8c80f097935653e6fc86f66c5bce Mon Sep 17 00:00:00 2001 From: Ilya Siamionau Date: Tue, 10 Oct 2023 11:06:41 +0200 Subject: [PATCH 2/2] use empty brackets instead of "optional" --- cycode/cli/commands/configure/configure_command.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cycode/cli/commands/configure/configure_command.py b/cycode/cli/commands/configure/configure_command.py index 04001eaa..5f9bad0e 100644 --- a/cycode/cli/commands/configure/configure_command.py +++ b/cycode/cli/commands/configure/configure_command.py @@ -59,7 +59,7 @@ def configure_command() -> None: def _get_client_id_input(current_client_id: Optional[str]) -> Optional[str]: prompt_text = 'Cycode Client ID' - prompt_suffix = ' (optional): ' + prompt_suffix = ' []: ' if current_client_id: prompt_suffix = f' [{obfuscate_text(current_client_id)}]: ' @@ -70,7 +70,7 @@ def _get_client_id_input(current_client_id: Optional[str]) -> Optional[str]: def _get_client_secret_input(current_client_secret: Optional[str]) -> Optional[str]: prompt_text = 'Cycode Client Secret' - prompt_suffix = ' (optional): ' + prompt_suffix = ' []: ' if current_client_secret: prompt_suffix = f' [{obfuscate_text(current_client_secret)}]: '