dlt-utils 0.1.2__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dlt_utils
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Shared utilities for dlt data pipelines with multi-company support
5
5
  Author: Jay van den Bos
6
6
  License: MIT
@@ -18,6 +18,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Requires-Python: >=3.13
19
19
  Description-Content-Type: text/markdown
20
20
  Requires-Dist: dlt>=1.19.1
21
+ Requires-Dist: azure-identity>=1.15.0
22
+ Requires-Dist: azure-keyvault-secrets>=4.8.0
21
23
  Provides-Extra: dev
22
24
  Requires-Dist: pytest>=7.0; extra == "dev"
23
25
  Requires-Dist: pytest-cov; extra == "dev"
@@ -27,6 +27,7 @@ from .args import (
27
27
  create_base_parser,
28
28
  CommonArgs,
29
29
  )
30
+ from .azure_keyvault import AzureKeyVault
30
31
  from .logging import configure_logging
31
32
  from .pipeline import (
32
33
  filter_resources,
@@ -37,7 +38,7 @@ from .pipeline import (
37
38
  )
38
39
 
39
40
 
40
- __version__ = "0.1.2"
41
+ __version__ = "0.2.0"
41
42
 
42
43
  __all__ = [
43
44
  # Incremental
@@ -53,6 +54,8 @@ __all__ = [
53
54
  "add_common_args",
54
55
  "CommonArgs",
55
56
  "create_base_parser",
57
+ # azure_keyvault
58
+ "AzureKeyVault",
56
59
  # logging
57
60
  "configure_logging",
58
61
  # pipeline
@@ -0,0 +1,93 @@
1
+ """
2
+ Azure Key Vault utilities voor secret management.
3
+
4
+ Dit module biedt een AzureKeyVault class voor het ophalen, opslaan en beheren van
5
+ secrets in Azure Key Vault. Authenticatie gebeurt via Service Principal credentials
6
+ (client_id, client_secret, tenant_id).
7
+
8
+ Gebruik:
9
+ - Secrets ophalen voor database credentials, API keys, etc.
10
+ - Secrets opslaan/updaten vanuit pipelines
11
+ - Tags updaten voor secrets
12
+
13
+ Vereiste environment variables:
14
+ - KEYVAULT_BASE_URL: URL van de Key Vault (bijv. https://myvault.vault.azure.net/)
15
+ - KEYVAULT_SECRET_NAME: Naam van de secret
16
+ - AZURE_TENANT_ID: Azure AD tenant ID
17
+ - AZURE_CLIENT_ID: Service Principal client ID
18
+ - AZURE_CLIENT_SECRET: Service Principal client secret
19
+ """
20
+ from azure.identity import ClientSecretCredential
21
+ from azure.keyvault.secrets import SecretClient
22
+ import json
23
+ import os
24
+
25
+
26
+ class AzureKeyVault:
27
+ def __init__(self):
28
+ """
29
+ Base class for Azure
30
+ """
31
+ super(AzureKeyVault, self).__init__()
32
+
33
+ # Azure Key Vault configuration
34
+ self.KEYVAULT_BASE_URL = os.getenv('KEYVAULT_BASE_URL')
35
+ self.KEYVAULT_SECRET_NAME = os.getenv('KEYVAULT_SECRET_NAME')
36
+
37
+ # Initialize Azure credential and Key Vault client
38
+ self.credential = ClientSecretCredential(
39
+ tenant_id=os.getenv('AZURE_TENANT_ID'),
40
+ client_id=os.getenv('AZURE_CLIENT_ID'),
41
+ client_secret=os.getenv('AZURE_CLIENT_SECRET')
42
+ )
43
+ self.secret_client = SecretClient(
44
+ vault_url=self.KEYVAULT_BASE_URL,
45
+ credential=self.credential
46
+ )
47
+
48
+ def get_secret(self) -> object:
49
+ """
50
+ Get secret from Azure Key Vault.
51
+
52
+ Returns
53
+ -------
54
+ object
55
+ Object with value, properties, etc. of the secret
56
+ """
57
+ secret = self.secret_client.get_secret(self.KEYVAULT_SECRET_NAME)
58
+
59
+ return secret
60
+
61
+ def update_secret_tags(self, tags: dict):
62
+ """
63
+ Update tags on the Key Vault secret.
64
+
65
+ Parameters
66
+ ----------
67
+ tags : dict
68
+ Dictionary of tags to set on the secret
69
+ """
70
+ self.secret_client.update_secret_properties(
71
+ self.KEYVAULT_SECRET_NAME,
72
+ tags=tags
73
+ )
74
+ print("Updated Key Vault tags successfully")
75
+
76
+ def set_secret(self, secret_value: dict):
77
+ """
78
+ Set secret to Azure Key Vault.
79
+
80
+ Parameters
81
+ ----------
82
+ secret_value : dict
83
+ Secret value to set to Azure Key Vault
84
+ """
85
+
86
+ self.secret_client.set_secret(
87
+ self.KEYVAULT_SECRET_NAME,
88
+ json.dumps(secret_value),
89
+ tags={}
90
+ )
91
+ print("Secret set to Key Vault successfully")
92
+
93
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dlt_utils
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Shared utilities for dlt data pipelines with multi-company support
5
5
  Author: Jay van den Bos
6
6
  License: MIT
@@ -18,6 +18,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
18
  Requires-Python: >=3.13
19
19
  Description-Content-Type: text/markdown
20
20
  Requires-Dist: dlt>=1.19.1
21
+ Requires-Dist: azure-identity>=1.15.0
22
+ Requires-Dist: azure-keyvault-secrets>=4.8.0
21
23
  Provides-Extra: dev
22
24
  Requires-Dist: pytest>=7.0; extra == "dev"
23
25
  Requires-Dist: pytest-cov; extra == "dev"
@@ -2,6 +2,7 @@ README.md
2
2
  pyproject.toml
3
3
  dlt_utils/__init__.py
4
4
  dlt_utils/args.py
5
+ dlt_utils/azure_keyvault.py
5
6
  dlt_utils/dates.py
6
7
  dlt_utils/incremental.py
7
8
  dlt_utils/logging.py
@@ -12,5 +13,6 @@ dlt_utils.egg-info/SOURCES.txt
12
13
  dlt_utils.egg-info/dependency_links.txt
13
14
  dlt_utils.egg-info/requires.txt
14
15
  dlt_utils.egg-info/top_level.txt
16
+ tests/test_azure_keyvault.py
15
17
  tests/test_dates.py
16
18
  tests/test_incremental.py
@@ -0,0 +1,8 @@
1
+ dlt>=1.19.1
2
+ azure-identity>=1.15.0
3
+ azure-keyvault-secrets>=4.8.0
4
+
5
+ [dev]
6
+ pytest>=7.0
7
+ pytest-cov
8
+ ruff
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "dlt_utils"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Shared utilities for dlt data pipelines with multi-company support"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -25,6 +25,8 @@ classifiers = [
25
25
  ]
26
26
  dependencies = [
27
27
  "dlt>=1.19.1",
28
+ "azure-identity>=1.15.0",
29
+ "azure-keyvault-secrets>=4.8.0",
28
30
  ]
29
31
 
30
32
  [project.optional-dependencies]
@@ -0,0 +1,126 @@
1
+ """Tests for Azure Key Vault utilities."""
2
+ import json
3
+ import os
4
+ from unittest.mock import MagicMock, patch
5
+
6
+ import pytest
7
+
8
+
9
+ class TestAzureKeyVault:
10
+ """Test cases for AzureKeyVault class."""
11
+
12
+ @patch.dict(os.environ, {
13
+ 'KEYVAULT_BASE_URL': 'https://test-vault.vault.azure.net/',
14
+ 'KEYVAULT_SECRET_NAME': 'test-secret',
15
+ 'AZURE_TENANT_ID': 'test-tenant-id',
16
+ 'AZURE_CLIENT_ID': 'test-client-id',
17
+ 'AZURE_CLIENT_SECRET': 'test-client-secret'
18
+ })
19
+ @patch('dlt_utils.azure_keyvault.SecretClient')
20
+ @patch('dlt_utils.azure_keyvault.ClientSecretCredential')
21
+ def test_init(self, mock_credential, mock_secret_client):
22
+ """Test AzureKeyVault initialization."""
23
+ from dlt_utils.azure_keyvault import AzureKeyVault
24
+
25
+ kv = AzureKeyVault()
26
+
27
+ # Verify credential was created with correct parameters
28
+ mock_credential.assert_called_once_with(
29
+ tenant_id='test-tenant-id',
30
+ client_id='test-client-id',
31
+ client_secret='test-client-secret'
32
+ )
33
+
34
+ # Verify SecretClient was created
35
+ mock_secret_client.assert_called_once()
36
+ assert kv.KEYVAULT_BASE_URL == 'https://test-vault.vault.azure.net/'
37
+ assert kv.KEYVAULT_SECRET_NAME == 'test-secret'
38
+
39
+ @patch.dict(os.environ, {
40
+ 'KEYVAULT_BASE_URL': 'https://test-vault.vault.azure.net/',
41
+ 'KEYVAULT_SECRET_NAME': 'test-secret',
42
+ 'AZURE_TENANT_ID': 'test-tenant-id',
43
+ 'AZURE_CLIENT_ID': 'test-client-id',
44
+ 'AZURE_CLIENT_SECRET': 'test-client-secret'
45
+ })
46
+ @patch('dlt_utils.azure_keyvault.SecretClient')
47
+ @patch('dlt_utils.azure_keyvault.ClientSecretCredential')
48
+ def test_get_secret(self, mock_credential, mock_secret_client):
49
+ """Test getting a secret from Key Vault."""
50
+ from dlt_utils.azure_keyvault import AzureKeyVault
51
+
52
+ # Setup mock
53
+ mock_secret = MagicMock()
54
+ mock_secret.value = '{"key": "value"}'
55
+ mock_secret_client.return_value.get_secret.return_value = mock_secret
56
+
57
+ kv = AzureKeyVault()
58
+ result = kv.get_secret()
59
+
60
+ # Verify get_secret was called with correct secret name
61
+ kv.secret_client.get_secret.assert_called_once_with('test-secret')
62
+ assert result == mock_secret
63
+
64
+ @patch.dict(os.environ, {
65
+ 'KEYVAULT_BASE_URL': 'https://test-vault.vault.azure.net/',
66
+ 'KEYVAULT_SECRET_NAME': 'test-secret',
67
+ 'AZURE_TENANT_ID': 'test-tenant-id',
68
+ 'AZURE_CLIENT_ID': 'test-client-id',
69
+ 'AZURE_CLIENT_SECRET': 'test-client-secret'
70
+ })
71
+ @patch('dlt_utils.azure_keyvault.SecretClient')
72
+ @patch('dlt_utils.azure_keyvault.ClientSecretCredential')
73
+ def test_update_secret_tags(self, mock_credential, mock_secret_client):
74
+ """Test updating secret tags."""
75
+ from dlt_utils.azure_keyvault import AzureKeyVault
76
+
77
+ kv = AzureKeyVault()
78
+ tags = {'environment': 'test', 'version': '1.0'}
79
+ kv.update_secret_tags(tags)
80
+
81
+ # Verify update_secret_properties was called
82
+ kv.secret_client.update_secret_properties.assert_called_once_with(
83
+ 'test-secret',
84
+ tags=tags
85
+ )
86
+
87
+ @patch.dict(os.environ, {
88
+ 'KEYVAULT_BASE_URL': 'https://test-vault.vault.azure.net/',
89
+ 'KEYVAULT_SECRET_NAME': 'test-secret',
90
+ 'AZURE_TENANT_ID': 'test-tenant-id',
91
+ 'AZURE_CLIENT_ID': 'test-client-id',
92
+ 'AZURE_CLIENT_SECRET': 'test-client-secret'
93
+ })
94
+ @patch('dlt_utils.azure_keyvault.SecretClient')
95
+ @patch('dlt_utils.azure_keyvault.ClientSecretCredential')
96
+ def test_set_secret(self, mock_credential, mock_secret_client):
97
+ """Test setting a secret in Key Vault."""
98
+ from dlt_utils.azure_keyvault import AzureKeyVault
99
+
100
+ kv = AzureKeyVault()
101
+ secret_value = {'database': 'prod', 'password': 'secret123'}
102
+ kv.set_secret(secret_value)
103
+
104
+ # Verify set_secret was called with correct parameters
105
+ kv.secret_client.set_secret.assert_called_once_with(
106
+ 'test-secret',
107
+ json.dumps(secret_value),
108
+ tags={}
109
+ )
110
+
111
+
112
+ class TestAzureKeyVaultMissingEnvVars:
113
+ """Test AzureKeyVault behavior with missing environment variables."""
114
+
115
+ @patch.dict(os.environ, {}, clear=True)
116
+ @patch('dlt_utils.azure_keyvault.SecretClient')
117
+ @patch('dlt_utils.azure_keyvault.ClientSecretCredential')
118
+ def test_init_missing_env_vars(self, mock_credential, mock_secret_client):
119
+ """Test initialization with missing environment variables."""
120
+ from dlt_utils.azure_keyvault import AzureKeyVault
121
+
122
+ kv = AzureKeyVault()
123
+
124
+ # Should initialize but with None values
125
+ assert kv.KEYVAULT_BASE_URL is None
126
+ assert kv.KEYVAULT_SECRET_NAME is None
@@ -1,6 +0,0 @@
1
- dlt>=1.19.1
2
-
3
- [dev]
4
- pytest>=7.0
5
- pytest-cov
6
- ruff
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes