"""Tests for github_cli SecretsManagerClient.""" from unittest.mock import MagicMock, patch import pytest from github_client.secrets_manager import SecretsManagerClient @patch('boto3.client') def test_get_github_token_returns_secret_string(mock_boto_client: MagicMock) -> None: """get_github_token returns the SecretString value from the response. :param mock_boto_client: :return: """ mock_sm = MagicMock() mock_boto_client.return_value = mock_sm mock_sm.get_secret_value.return_value = {'SecretString': 'ghp_mytoken'} client = SecretsManagerClient() token = client.get_github_token('my/secret/name') assert token == 'ghp_mytoken' @patch('boto3.client') def test_get_github_token_uses_correct_secret_id(mock_boto_client: MagicMock) -> None: """get_github_token calls get_secret_value with the expected SecretId. :param mock_boto_client: :return: """ mock_sm = MagicMock() mock_boto_client.return_value = mock_sm mock_sm.get_secret_value.return_value = {'SecretString': 'ghp_mytoken'} client = SecretsManagerClient() client.get_github_token('prod/github/token') mock_sm.get_secret_value.assert_called_once_with(SecretId='prod/github/token') @patch('boto3.client') def test_get_github_token_returns_decoded_secret_binary( mock_boto_client: MagicMock, ) -> None: """get_github_token decodes SecretBinary when SecretString is absent. :param mock_boto_client: :return: """ mock_sm = MagicMock() mock_boto_client.return_value = mock_sm mock_sm.get_secret_value.return_value = {'SecretBinary': b'ghp_binarytoken'} client = SecretsManagerClient() token = client.get_github_token('my/binary/secret') assert token == 'ghp_binarytoken' @patch('boto3.client') def test_get_github_token_raises_when_neither_key_present( mock_boto_client: MagicMock, ) -> None: """get_github_token raises ValueError when the response has no secret data. :param mock_boto_client: :return: """ mock_sm = MagicMock() mock_boto_client.return_value = mock_sm mock_sm.get_secret_value.return_value = {} client = SecretsManagerClient() with pytest.raises(ValueError, match='neither SecretString nor SecretBinary'): client.get_github_token('empty/secret') @patch('boto3.client') def test_get_github_token_propagates_boto3_error(mock_boto_client: MagicMock) -> None: """get_github_token propagates exceptions raised by boto3. :param mock_boto_client: :return: """ mock_sm = MagicMock() mock_boto_client.return_value = mock_sm mock_sm.get_secret_value.side_effect = Exception('ResourceNotFoundException') client = SecretsManagerClient() with pytest.raises(Exception, match='ResourceNotFoundException'): client.get_github_token('nonexistent/secret')