This commit is contained in:
commit
4140b85115
|
|
@ -1,5 +1,9 @@
|
||||||
## Keep It Secret Changelog
|
## Keep It Secret Changelog
|
||||||
|
|
||||||
|
#### v1.3.0 (2024-10-24)
|
||||||
|
|
||||||
|
* Support for approle auth in Hashicorp Vault integration.
|
||||||
|
|
||||||
#### v1.2.2 (2024-06-05)
|
#### v1.2.2 (2024-06-05)
|
||||||
|
|
||||||
* TeamCity integration for private builds.
|
* TeamCity integration for private builds.
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@
|
||||||
project = 'Keep It Secret'
|
project = 'Keep It Secret'
|
||||||
copyright = '2023-present Tomek Wójcik'
|
copyright = '2023-present Tomek Wójcik'
|
||||||
author = 'Tomek Wójcik'
|
author = 'Tomek Wójcik'
|
||||||
version = '1.2.2'
|
version = '1.3.0'
|
||||||
|
|
||||||
# The full version, including alpha/beta/rc tags
|
# The full version, including alpha/beta/rc tags
|
||||||
release = '1.2.2'
|
release = '1.3.0'
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,15 @@ to be installed:
|
||||||
|
|
||||||
**API**
|
**API**
|
||||||
|
|
||||||
|
.. autoclass:: keep_it_secret.ext.vault.BaseVaultSecrets
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: keep_it_secret.ext.vault.VaultSecrets
|
.. autoclass:: keep_it_secret.ext.vault.VaultSecrets
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
.. autoclass:: keep_it_secret.ext.vault.AppRoleVaultSecrets
|
||||||
|
:members:
|
||||||
|
|
||||||
.. autoclass:: keep_it_secret.ext.vault.VaultKV2Field
|
.. autoclass:: keep_it_secret.ext.vault.VaultKV2Field
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ from .fields import ( # noqa: F401
|
||||||
)
|
)
|
||||||
from .secrets import Secrets # noqa: F401
|
from .secrets import Secrets # noqa: F401
|
||||||
|
|
||||||
__version__ = '1.2.2'
|
__version__ = '1.3.0'
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'AbstractField',
|
'AbstractField',
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,9 @@ from keep_it_secret.fields import EnvField, Field
|
||||||
from keep_it_secret.secrets import Secrets
|
from keep_it_secret.secrets import Secrets
|
||||||
|
|
||||||
|
|
||||||
class VaultSecrets(Secrets):
|
class BaseVaultSecrets(Secrets):
|
||||||
"""
|
"""
|
||||||
Concrete :py:class:`keep_it_secret.Secrets` subclass that maps environment
|
Base :py:class:`keep_it_secret.Secrets` subclass for Vault-base secrets.
|
||||||
variables to Vault credentials.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
url: str = EnvField.new('VAULT_URL', required=True)
|
url: str = EnvField.new('VAULT_URL', required=True)
|
||||||
|
|
@ -22,13 +21,6 @@ class VaultSecrets(Secrets):
|
||||||
:type: ``str``
|
:type: ``str``
|
||||||
"""
|
"""
|
||||||
|
|
||||||
token: str = EnvField.new('VAULT_TOKEN', required=True)
|
|
||||||
"""
|
|
||||||
Maps ``VAULT_TOKEN`` environment variable.
|
|
||||||
|
|
||||||
:type: ``str``
|
|
||||||
"""
|
|
||||||
|
|
||||||
client_cert_path: str | None = EnvField.new('VAULT_CLIENT_CERT_PATH', required=False)
|
client_cert_path: str | None = EnvField.new('VAULT_CLIENT_CERT_PATH', required=False)
|
||||||
"""
|
"""
|
||||||
Maps ``VAULT_CLIENT_CERT_PATH`` environment variable.
|
Maps ``VAULT_CLIENT_CERT_PATH`` environment variable.
|
||||||
|
|
@ -62,7 +54,6 @@ class VaultSecrets(Secrets):
|
||||||
"""
|
"""
|
||||||
result: dict[str, typing.Any] = {
|
result: dict[str, typing.Any] = {
|
||||||
'url': self.url,
|
'url': self.url,
|
||||||
'token': self.token,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.client_cert_path is not None and self.client_key_path is not None:
|
if self.client_cert_path is not None and self.client_key_path is not None:
|
||||||
|
|
@ -85,6 +76,58 @@ class VaultSecrets(Secrets):
|
||||||
return self.client
|
return self.client
|
||||||
|
|
||||||
|
|
||||||
|
class VaultSecrets(BaseVaultSecrets):
|
||||||
|
"""
|
||||||
|
Concrete :py:class:`BaseVaultSecrets` subclass that uses token to
|
||||||
|
authenticate with Vault.
|
||||||
|
"""
|
||||||
|
|
||||||
|
token: str = EnvField.new('VAULT_TOKEN', required=True)
|
||||||
|
"""
|
||||||
|
Maps ``VAULT_TOKEN`` environment variable.
|
||||||
|
|
||||||
|
:type: ``str``
|
||||||
|
"""
|
||||||
|
|
||||||
|
def as_hvac_client_kwargs(self) -> dict[str, typing.Any]:
|
||||||
|
result = super().as_hvac_client_kwargs()
|
||||||
|
result['token'] = self.token
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
class AppRoleVaultSecrets(BaseVaultSecrets):
|
||||||
|
"""
|
||||||
|
Concrete :py:class:`BaseVaultSecrets` subclass that uses app role to
|
||||||
|
authenticate with Vault.
|
||||||
|
"""
|
||||||
|
|
||||||
|
role_id: str = EnvField.new('VAULT_ROLE_ID', required=True)
|
||||||
|
"""
|
||||||
|
Maps ``VAULT_ROLE_ID`` environment variable.
|
||||||
|
|
||||||
|
:type: ``str``
|
||||||
|
"""
|
||||||
|
|
||||||
|
secret_id: str = EnvField.new('VAULT_SECRET_ID', required=True)
|
||||||
|
"""
|
||||||
|
Maps ``VAULT_SECRET_ID`` environment variable.
|
||||||
|
|
||||||
|
:type: ``str``
|
||||||
|
"""
|
||||||
|
|
||||||
|
def get_client(self) -> hvac.Client:
|
||||||
|
if self.client is None:
|
||||||
|
super().get_client()
|
||||||
|
|
||||||
|
self.client.auth.approle.login( # type: ignore[attr-defined]
|
||||||
|
role_id=self.role_id,
|
||||||
|
secret_id=self.secret_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.client
|
||||||
|
|
||||||
|
|
||||||
class VaultKV2Field(Field):
|
class VaultKV2Field(Field):
|
||||||
"""
|
"""
|
||||||
Concrete :py:class:`keep_it_secret.Field` subclass that uses Hashicorp
|
Concrete :py:class:`keep_it_secret.Field` subclass that uses Hashicorp
|
||||||
|
|
|
||||||
51
poetry.lock
generated
51
poetry.lock
generated
|
|
@ -1,4 +1,4 @@
|
||||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "alabaster"
|
name = "alabaster"
|
||||||
|
|
@ -384,33 +384,33 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flake8"
|
name = "flake8"
|
||||||
version = "6.1.0"
|
version = "7.3.0"
|
||||||
description = "the modular source code checker: pep8 pyflakes and co"
|
description = "the modular source code checker: pep8 pyflakes and co"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8.1"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"},
|
{file = "flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e"},
|
||||||
{file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"},
|
{file = "flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
mccabe = ">=0.7.0,<0.8.0"
|
mccabe = ">=0.7.0,<0.8.0"
|
||||||
pycodestyle = ">=2.11.0,<2.12.0"
|
pycodestyle = ">=2.14.0,<2.15.0"
|
||||||
pyflakes = ">=3.1.0,<3.2.0"
|
pyflakes = ">=3.4.0,<3.5.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flake8-commas"
|
name = "flake8-commas"
|
||||||
version = "2.1.0"
|
version = "4.0.0"
|
||||||
description = "Flake8 lint for trailing commas."
|
description = "Flake8 lint for trailing commas."
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.8"
|
||||||
files = [
|
files = [
|
||||||
{file = "flake8-commas-2.1.0.tar.gz", hash = "sha256:940441ab8ee544df564ae3b3f49f20462d75d5c7cac2463e0b27436e2050f263"},
|
{file = "flake8_commas-4.0.0-py3-none-any.whl", hash = "sha256:cad476d71ba72e8b941a8508d5b9ffb6b03e50f7102982474f085ad0d674b685"},
|
||||||
{file = "flake8_commas-2.1.0-py2.py3-none-any.whl", hash = "sha256:ebb96c31e01d0ef1d0685a21f3f0e2f8153a0381430e748bf0bbbb5d5b453d54"},
|
{file = "flake8_commas-4.0.0.tar.gz", hash = "sha256:a68834b42a9a31c94ca790efe557a932c0eae21a3479c6b9a23c4dc077e3ea96"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
flake8 = ">=2"
|
flake8 = ">=5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "furo"
|
name = "furo"
|
||||||
|
|
@ -500,13 +500,13 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "invoke"
|
name = "invoke"
|
||||||
version = "1.7.3"
|
version = "2.2.1"
|
||||||
description = "Pythonic task execution"
|
description = "Pythonic task execution"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.6"
|
||||||
files = [
|
files = [
|
||||||
{file = "invoke-1.7.3-py3-none-any.whl", hash = "sha256:d9694a865764dd3fd91f25f7e9a97fb41666e822bbb00e670091e3f43933574d"},
|
{file = "invoke-2.2.1-py3-none-any.whl", hash = "sha256:2413bc441b376e5cd3f55bb5d364f973ad8bdd7bf87e53c79de3c11bf3feecc8"},
|
||||||
{file = "invoke-1.7.3.tar.gz", hash = "sha256:41b428342d466a82135d5ab37119685a989713742be46e42a3a399d685579314"},
|
{file = "invoke-2.2.1.tar.gz", hash = "sha256:515bf49b4a48932b79b024590348da22f39c4942dff991ad1fb8b8baea1be707"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1046,13 +1046,13 @@ tests = ["pytest"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pycodestyle"
|
name = "pycodestyle"
|
||||||
version = "2.11.1"
|
version = "2.14.0"
|
||||||
description = "Python style guide checker"
|
description = "Python style guide checker"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"},
|
{file = "pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d"},
|
||||||
{file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"},
|
{file = "pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1068,13 +1068,13 @@ files = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyflakes"
|
name = "pyflakes"
|
||||||
version = "3.1.0"
|
version = "3.4.0"
|
||||||
description = "passive checker of Python programs"
|
description = "passive checker of Python programs"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=3.8"
|
python-versions = ">=3.9"
|
||||||
files = [
|
files = [
|
||||||
{file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"},
|
{file = "pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f"},
|
||||||
{file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"},
|
{file = "pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1199,6 +1199,7 @@ files = [
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
||||||
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
||||||
|
|
@ -1714,4 +1715,4 @@ vault = ["hvac"]
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "e4959d95b206c17013e548f015fbf288d9bc754584bfc128458cadead137a863"
|
content-hash = "1547e872ed842c8e1ea41e45841bf25a327cbaa907e075613c9b12077d2ffefc"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "keep-it-secret"
|
name = "keep-it-secret"
|
||||||
version = "1.2.2"
|
version = "1.3.0"
|
||||||
description = "Keep It Secret by BTHLabs"
|
description = "Keep It Secret by BTHLabs"
|
||||||
authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
|
authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
|
||||||
maintainers = ["BTHLabs <contact@bthlabs.pl>"]
|
maintainers = ["BTHLabs <contact@bthlabs.pl>"]
|
||||||
|
|
@ -17,11 +17,11 @@ hvac = {version = ">=2.1.0", optional = true}
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
boto3 = "1.34.8"
|
boto3 = "1.34.8"
|
||||||
flake8 = "6.1.0"
|
flake8 = "7.3.0"
|
||||||
flake8-commas = "2.1.0"
|
flake8-commas = "4.0.0"
|
||||||
furo = "2023.9.10"
|
furo = "2023.9.10"
|
||||||
hvac = "2.1.0"
|
hvac = "2.1.0"
|
||||||
invoke = "1.7.3"
|
invoke = "2.2.1"
|
||||||
ipdb = "0.13.13"
|
ipdb = "0.13.13"
|
||||||
ipython = "8.19.0"
|
ipython = "8.19.0"
|
||||||
moto = "4.2.12"
|
moto = "4.2.12"
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,30 @@
|
||||||
# type: ignore
|
# type: ignore
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
import hvac
|
||||||
import pytest
|
import pytest
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
from .fixtures import TestingVaultSecrets
|
from .fixtures import TestingVaultSecrets
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def hvac_client() -> mock.Mock:
|
||||||
|
return mock.Mock(spec=hvac.Client)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_hvac_client(mocker: MockerFixture,
|
||||||
|
hvac_client: mock.Mock,
|
||||||
|
) -> mock.Mock:
|
||||||
|
return mocker.patch(
|
||||||
|
'keep_it_secret.ext.vault.hvac.Client',
|
||||||
|
return_value=hvac_client,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def testing_vault_secrets() -> TestingVaultSecrets:
|
def testing_vault_secrets() -> TestingVaultSecrets:
|
||||||
return TestingVaultSecrets()
|
return TestingVaultSecrets()
|
||||||
|
|
|
||||||
124
tests/ext/vault/test_AppRoleVaultSecrets.py
Normal file
124
tests/ext/vault/test_AppRoleVaultSecrets.py
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# type: ignore
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from keep_it_secret.ext import vault
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_ROLE_ID': 'test_role_id',
|
||||||
|
'VAULT_SECRET_ID': 'test_secret_id',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_init():
|
||||||
|
# When
|
||||||
|
result = vault.AppRoleVaultSecrets()
|
||||||
|
|
||||||
|
# Then
|
||||||
|
assert result.client is None
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_ROLE_ID': 'test_role_id',
|
||||||
|
'VAULT_SECRET_ID': 'test_secret_id',
|
||||||
|
'VAULT_CLIENT_CERT_PATH': '/tmp/vault_client_cert.pem',
|
||||||
|
'VAULT_CLIENT_KEY_PATH': '/tmp/vault_client_key.pem',
|
||||||
|
'VAULT_SERVER_CERT_PATH': '/tmp/vault_server_cert.pem',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_as_hvac_client_kwargs():
|
||||||
|
# Given
|
||||||
|
secrets = vault.AppRoleVaultSecrets()
|
||||||
|
|
||||||
|
# When
|
||||||
|
result = secrets.as_hvac_client_kwargs()
|
||||||
|
|
||||||
|
# Then
|
||||||
|
assert result == {
|
||||||
|
'url': 'https://vault.work/',
|
||||||
|
'cert': ('/tmp/vault_client_cert.pem', '/tmp/vault_client_key.pem'),
|
||||||
|
'verify': '/tmp/vault_server_cert.pem',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_ROLE_ID': 'test_role_id',
|
||||||
|
'VAULT_SECRET_ID': 'test_secret_id',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_as_hvac_client_kwargs_without_optional_fields():
|
||||||
|
# Given
|
||||||
|
secrets = vault.AppRoleVaultSecrets()
|
||||||
|
|
||||||
|
# When
|
||||||
|
result = secrets.as_hvac_client_kwargs()
|
||||||
|
|
||||||
|
# Then
|
||||||
|
assert result == {
|
||||||
|
'url': 'https://vault.work/',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_ROLE_ID': 'test_role_id',
|
||||||
|
'VAULT_SECRET_ID': 'test_secret_id',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_get_client_cache_miss(mock_hvac_client: mock.Mock,
|
||||||
|
hvac_client: mock.Mock):
|
||||||
|
# Given
|
||||||
|
mock_hvac_client.return_value = hvac_client
|
||||||
|
|
||||||
|
secrets = vault.AppRoleVaultSecrets()
|
||||||
|
|
||||||
|
# When
|
||||||
|
result = secrets.get_client()
|
||||||
|
|
||||||
|
# Then
|
||||||
|
assert result == hvac_client
|
||||||
|
|
||||||
|
assert secrets.client == hvac_client
|
||||||
|
|
||||||
|
mock_hvac_client.assert_called_once_with(**secrets.as_hvac_client_kwargs())
|
||||||
|
hvac_client.auth.approle.login.assert_called_once_with(
|
||||||
|
role_id='test_role_id',
|
||||||
|
secret_id='test_secret_id',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_ROLE_ID': 'test_role_id',
|
||||||
|
'VAULT_SECRET_ID': 'test_secret_id',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
def test_get_client_cache_hit(mock_hvac_client: mock.Mock,
|
||||||
|
hvac_client: mock.Mock):
|
||||||
|
# Given
|
||||||
|
secrets = vault.AppRoleVaultSecrets()
|
||||||
|
secrets.client = hvac_client
|
||||||
|
|
||||||
|
# When
|
||||||
|
result = secrets.get_client()
|
||||||
|
|
||||||
|
# Then
|
||||||
|
assert result == hvac_client
|
||||||
|
|
||||||
|
mock_hvac_client.assert_not_called()
|
||||||
|
|
@ -5,22 +5,16 @@ from __future__ import annotations
|
||||||
import os
|
import os
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
import pytest
|
|
||||||
from pytest_mock import MockerFixture
|
|
||||||
|
|
||||||
from keep_it_secret.ext import vault
|
from keep_it_secret.ext import vault
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@mock.patch.dict(
|
||||||
def mock_hvac_client(mocker: MockerFixture) -> mock.Mock:
|
os.environ,
|
||||||
return mocker.patch.object(vault.hvac, 'Client')
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_TOKEN': 'test_vault_token',
|
||||||
@pytest.fixture
|
},
|
||||||
def hvac_client() -> mock.Mock:
|
)
|
||||||
return mock.Mock()
|
|
||||||
|
|
||||||
|
|
||||||
def test_init():
|
def test_init():
|
||||||
# When
|
# When
|
||||||
result = vault.VaultSecrets()
|
result = vault.VaultSecrets()
|
||||||
|
|
@ -76,6 +70,13 @@ def test_as_hvac_client_kwargs_without_optional_fields():
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_TOKEN': 'test_vault_token',
|
||||||
|
},
|
||||||
|
)
|
||||||
def test_get_client_cache_miss(mock_hvac_client: mock.Mock,
|
def test_get_client_cache_miss(mock_hvac_client: mock.Mock,
|
||||||
hvac_client: mock.Mock):
|
hvac_client: mock.Mock):
|
||||||
# Given
|
# Given
|
||||||
|
|
@ -94,6 +95,13 @@ def test_get_client_cache_miss(mock_hvac_client: mock.Mock,
|
||||||
mock_hvac_client.assert_called_once_with(**secrets.as_hvac_client_kwargs())
|
mock_hvac_client.assert_called_once_with(**secrets.as_hvac_client_kwargs())
|
||||||
|
|
||||||
|
|
||||||
|
@mock.patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
'VAULT_URL': 'https://vault.work/',
|
||||||
|
'VAULT_TOKEN': 'test_vault_token',
|
||||||
|
},
|
||||||
|
)
|
||||||
def test_get_client_cache_hit(mock_hvac_client: mock.Mock,
|
def test_get_client_cache_hit(mock_hvac_client: mock.Mock,
|
||||||
hvac_client: mock.Mock):
|
hvac_client: mock.Mock):
|
||||||
# Given
|
# Given
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user