|
22 | 22 | from dataclasses import dataclass |
23 | 23 | from pathlib import Path |
24 | 24 | from typing import IO |
25 | | -from unittest.mock import patch |
| 25 | +from unittest.mock import MagicMock, patch |
26 | 26 |
|
27 | 27 | import pytest |
28 | 28 | import yaml |
|
51 | 51 | from cognite.extractorutils.configtools.loaders import ( |
52 | 52 | ConfigResolver, |
53 | 53 | compile_patterns, |
| 54 | + load_yaml_dict, |
54 | 55 | ) |
55 | 56 | from cognite.extractorutils.configtools.validators import matches_pattern, matches_patterns |
56 | 57 | from cognite.extractorutils.exceptions import InvalidConfigError |
@@ -750,3 +751,95 @@ def test_configresolver_fallback_encoding(tmp_path: Path, caplog: pytest.LogCapt |
750 | 751 | assert config.logger.file.path is not None |
751 | 752 | assert "café" in config.logger.file.path |
752 | 753 | assert any("Falling back to system default encoding." in r.message for r in caplog.records) |
| 754 | + |
| 755 | + |
| 756 | +@pytest.mark.parametrize("auth_method", ["default", "client-secret"]) |
| 757 | +def test_keyvault_config_env_var_expansion(monkeypatch: pytest.MonkeyPatch, auth_method: str) -> None: |
| 758 | + monkeypatch.setenv("MY_KEYVAULT_NAME", "test-keyvault-from-env") |
| 759 | + |
| 760 | + if auth_method == "default": |
| 761 | + yaml_config = """ |
| 762 | + azure-keyvault: |
| 763 | + keyvault-name: ${MY_KEYVAULT_NAME} |
| 764 | + authentication-method: default |
| 765 | +
|
| 766 | + database: |
| 767 | + password: !keyvault db-password |
| 768 | + """ |
| 769 | + else: |
| 770 | + monkeypatch.setenv("KV_CLIENT_ID", "client-id-123") |
| 771 | + monkeypatch.setenv("KV_TENANT_ID", "tenant-id-456") |
| 772 | + monkeypatch.setenv("KV_SECRET", "secret-789") |
| 773 | + yaml_config = """ |
| 774 | + azure-keyvault: |
| 775 | + keyvault-name: ${MY_KEYVAULT_NAME} |
| 776 | + authentication-method: client-secret |
| 777 | + client-id: ${KV_CLIENT_ID} |
| 778 | + tenant-id: ${KV_TENANT_ID} |
| 779 | + secret: ${KV_SECRET} |
| 780 | +
|
| 781 | + database: |
| 782 | + password: !keyvault db-password |
| 783 | + """ |
| 784 | + |
| 785 | + with ( |
| 786 | + patch("cognite.extractorutils.configtools.loaders.DefaultAzureCredential") as mock_default_cred, |
| 787 | + patch("cognite.extractorutils.configtools.loaders.ClientSecretCredential") as mock_client_cred, |
| 788 | + patch("cognite.extractorutils.configtools.loaders.SecretClient") as mock_secret_client, |
| 789 | + ): |
| 790 | + mock_client_instance = MagicMock() |
| 791 | + mock_client_instance.get_secret.return_value = MagicMock(value="secret-from-keyvault") |
| 792 | + mock_secret_client.return_value = mock_client_instance |
| 793 | + mock_default_cred.return_value = MagicMock() |
| 794 | + mock_client_cred.return_value = MagicMock() |
| 795 | + |
| 796 | + config = load_yaml_dict(yaml_config) |
| 797 | + |
| 798 | + mock_secret_client.assert_called_once() |
| 799 | + call_kwargs = mock_secret_client.call_args[1] |
| 800 | + assert call_kwargs["vault_url"] == "https://test-keyvault-from-env.vault.azure.net" |
| 801 | + |
| 802 | + assert config["database"]["password"] == "secret-from-keyvault" |
| 803 | + |
| 804 | + if auth_method == "default": |
| 805 | + mock_default_cred.assert_called_once() |
| 806 | + mock_client_cred.assert_not_called() |
| 807 | + |
| 808 | + if auth_method == "client-secret": |
| 809 | + mock_client_cred.assert_called_once_with( |
| 810 | + tenant_id="tenant-id-456", |
| 811 | + client_id="client-id-123", |
| 812 | + client_secret="secret-789", |
| 813 | + ) |
| 814 | + mock_default_cred.assert_not_called() |
| 815 | + |
| 816 | + |
| 817 | +def test_keyvault_tag_without_config_raises_error() -> None: |
| 818 | + yaml_config = """ |
| 819 | + database: |
| 820 | + password: !keyvault db-password |
| 821 | + """ |
| 822 | + |
| 823 | + with pytest.raises(InvalidConfigError) as e: |
| 824 | + load_yaml_dict(yaml_config) |
| 825 | + assert ( |
| 826 | + e.value.message |
| 827 | + == "Attempted to load values from Azure key vault with no key vault configured. Include an `azure-keyvault` section in your config to use the !keyvault tag." |
| 828 | + ) |
| 829 | + |
| 830 | + |
| 831 | +def test_keyvault_client_secret_missing_raises_error() -> None: |
| 832 | + yaml_config = """ |
| 833 | + azure-keyvault: |
| 834 | + keyvault-name: test-keyvault-from-env |
| 835 | + authentication-method: client-secret |
| 836 | + client-id: client-id-123 |
| 837 | + tenant-id: tenant-id-456 |
| 838 | +
|
| 839 | + database: |
| 840 | + password: !keyvault db-password |
| 841 | + """ |
| 842 | + |
| 843 | + with pytest.raises(InvalidConfigError) as e: |
| 844 | + load_yaml_dict(yaml_config) |
| 845 | + assert e.value.message == "Missing client secret parameters. client-id, tenant-id and client-secret are mandatory" |
0 commit comments