From 8de4aa792973de4520c13f1d5e633db6f24c9ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verine=20Bonnech=C3=A8re?= Date: Wed, 8 Jan 2025 12:41:14 +0100 Subject: [PATCH 1/2] fix: make API urls from GitGuardian work with GGShield --- ....bonnechere_handle_product_doc_api_urls.md | 3 ++ ggshield/core/config/config.py | 9 ++++ tests/unit/cmd/auth/test_login.py | 49 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 changelog.d/20250108_124709_severine.bonnechere_handle_product_doc_api_urls.md diff --git a/changelog.d/20250108_124709_severine.bonnechere_handle_product_doc_api_urls.md b/changelog.d/20250108_124709_severine.bonnechere_handle_product_doc_api_urls.md new file mode 100644 index 0000000000..f07b12cf05 --- /dev/null +++ b/changelog.d/20250108_124709_severine.bonnechere_handle_product_doc_api_urls.md @@ -0,0 +1,3 @@ +### Fixed + +- `--instance` param now handles input https://api.eu1.gitguardian.com/v1 or https://api.gitguardian.com/v1. diff --git a/ggshield/core/config/config.py b/ggshield/core/config/config.py index 67e200b6f9..f651f71376 100644 --- a/ggshield/core/config/config.py +++ b/ggshield/core/config/config.py @@ -86,6 +86,7 @@ def get_instance_name_and_source(self) -> Tuple[str, ConfigSource]: The instance name (defaulting to URL) of the selected instance priority order is: - set from the command line (by setting cmdline_instance_name) + - in case the user set the api url instead of dashboard url, we replace it - GITGUARDIAN_INSTANCE env var - GITGUARDIAN_API_URL env var - in local user config (in user_config.dashboard_url) @@ -93,6 +94,14 @@ def get_instance_name_and_source(self) -> Tuple[str, ConfigSource]: - the default instance """ if self._cmdline_instance_name: + if ( + "api" in self._cmdline_instance_name + and "gitguardian" in self._cmdline_instance_name + ): + return ( + api_to_dashboard_url(self._cmdline_instance_name), + ConfigSource.CMD_OPTION, + ) return self._cmdline_instance_name, ConfigSource.CMD_OPTION try: diff --git a/tests/unit/cmd/auth/test_login.py b/tests/unit/cmd/auth/test_login.py index be18d7bfc8..9de22ccce0 100644 --- a/tests/unit/cmd/auth/test_login.py +++ b/tests/unit/cmd/auth/test_login.py @@ -147,6 +147,36 @@ def test_auth_login_token_default_instance(self, monkeypatch, cli_fs_runner): assert "ggshield config set instance" not in result.output self._request_mock.assert_all_requests_happened() + @pytest.mark.parametrize( + ("cmd_line_instance", "expected_instance"), + [ + ("https://api.gitguardian.com/v1", "https://dashboard.gitguardian.com"), + ( + "https://api.eu1.gitguardian.com/v1", + "https://dashboard.eu1.gitguardian.com", + ), + ], + ) + def test_api_instance_url( + self, cmd_line_instance, expected_instance, cli_fs_runner + ): + """ + GIVEN a valid API token and an instance URL matching GitGuardian API urls + WHEN running the login command + THEN it succeeds + """ + token = "mysupertoken" + cmd = ["auth", "login", "--method=token", f"--instance={cmd_line_instance}"] + self._request_mock.add_GET(TOKEN_ENDPOINT, VALID_TOKEN_RESPONSE) + result = cli_fs_runner.invoke(cli, cmd, color=False, input=token + "\n") + config = Config() + config_instance_urls = [ + instance_config.url for instance_config in config.auth_config.instances + ] + assert_invoke_ok(result) + assert expected_instance in config_instance_urls + self._request_mock.assert_all_requests_happened() + @pytest.mark.parametrize( ("instance", "suggests"), ( @@ -966,3 +996,22 @@ def test_invalid_instance_url(self, instance_url, cli_fs_runner, monkeypatch): exit_code, output = self.run_cmd(cli_fs_runner) assert exit_code == ExitCode.USAGE_ERROR, output self._webbrowser_open_mock.assert_not_called() + + @pytest.mark.parametrize( + "instance_url", + [ + "https://api.gitguardian.com/v1", + "https://api.eu1.gitguardian.com/v1", + ], + ) + def test_api_instance_url(self, instance_url, cli_fs_runner, monkeypatch): + """ + GIVEN an instance URL matching GitGuardian API urls + WHEN running the login command + THEN it succeeds + """ + monkeypatch.setenv("GITGUARDIAN_INSTANCE", instance_url) + self.prepare_mocks(monkeypatch) + exit_code, output = self.run_cmd(cli_fs_runner) + assert exit_code == ExitCode.SUCCESS, output + self._webbrowser_open_mock.assert_called() From cc27bb4cbf9e3e399e5d936a86b51b6d5f2e4709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verine=20Bonnech=C3=A8re?= Date: Fri, 10 Jan 2025 18:45:47 +0100 Subject: [PATCH 2/2] chore: stricter regex on api url. Handle on-prem --- ggshield/core/config/config.py | 9 +++++---- tests/unit/cmd/auth/test_login.py | 10 ++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/ggshield/core/config/config.py b/ggshield/core/config/config.py index f651f71376..a6a4206455 100644 --- a/ggshield/core/config/config.py +++ b/ggshield/core/config/config.py @@ -1,5 +1,6 @@ import logging import os +import re from enum import Enum from pathlib import Path from typing import Any, Optional, Set, Tuple @@ -94,10 +95,10 @@ def get_instance_name_and_source(self) -> Tuple[str, ConfigSource]: - the default instance """ if self._cmdline_instance_name: - if ( - "api" in self._cmdline_instance_name - and "gitguardian" in self._cmdline_instance_name - ): + if re.match( + r"^https:\/\/api(\.[a-z0-9]+)?\.gitguardian\.com", + self._cmdline_instance_name, + ) or re.match(r"/exposed/?$", self._cmdline_instance_name): return ( api_to_dashboard_url(self._cmdline_instance_name), ConfigSource.CMD_OPTION, diff --git a/tests/unit/cmd/auth/test_login.py b/tests/unit/cmd/auth/test_login.py index 9de22ccce0..58ac249faa 100644 --- a/tests/unit/cmd/auth/test_login.py +++ b/tests/unit/cmd/auth/test_login.py @@ -151,10 +151,19 @@ def test_auth_login_token_default_instance(self, monkeypatch, cli_fs_runner): ("cmd_line_instance", "expected_instance"), [ ("https://api.gitguardian.com/v1", "https://dashboard.gitguardian.com"), + ("https://api.gitguardian.com", "https://dashboard.gitguardian.com"), ( "https://api.eu1.gitguardian.com/v1", "https://dashboard.eu1.gitguardian.com", ), + ( + "https://gitguardian.mycorp.local/exposed/", + "https://gitguardian.mycorp.local", + ), + ( + "https://gitguardian.mycorp.local/exposed", + "https://gitguardian.mycorp.local", + ), ], ) def test_api_instance_url( @@ -1002,6 +1011,7 @@ def test_invalid_instance_url(self, instance_url, cli_fs_runner, monkeypatch): [ "https://api.gitguardian.com/v1", "https://api.eu1.gitguardian.com/v1", + "https://gitguardian.mycorp.local/exposed/", ], ) def test_api_instance_url(self, instance_url, cli_fs_runner, monkeypatch):