From a13b1252a7a79e914a8390fa2861c273dd66e9e9 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Mon, 26 Sep 2022 17:28:25 -0700 Subject: [PATCH 01/10] Add cruft --- .cruft.json | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .cruft.json diff --git a/.cruft.json b/.cruft.json new file mode 100644 index 00000000..52401569 --- /dev/null +++ b/.cruft.json @@ -0,0 +1,20 @@ +{ + "template": "https://github.com/PrefectHQ/prefect-collection-template", + "commit": "c0ea1b51ff5cf11aca3e64168d1025c6bcab4bca", + "checkout": "generated_rest", + "context": { + "cookiecutter": { + "full_name": "Prefect Technologies, Inc.", + "email": "help@prefect.io", + "github_organization": "PrefectHQ", + "collection_name": "prefect-gcp", + "collection_slug": "prefect_gcp", + "collection_short_description": "Prefect integrations for interacting with Google Cloud Platform.", + "_copy_without_render": [ + ".github/workflows/*.yml" + ], + "_template": "https://github.com/PrefectHQ/prefect-collection-template" + } + }, + "directory": null +} From 4f4d5418dd0f70243fa4363764d5602eb5396655 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Tue, 13 Dec 2022 19:56:33 -0800 Subject: [PATCH 02/10] Implement secret block --- prefect_gcp/secret_manager.py | 110 ++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index b3933870..733d5375 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -1,8 +1,18 @@ from functools import partial -from typing import TYPE_CHECKING, Optional, Union +from typing import TYPE_CHECKING, Any, Optional, Union from anyio import to_thread +from google.cloud.secretmanager_v1.types.resources import Secret, SecretPayload +from google.cloud.secretmanager_v1.types.service import ( + AccessSecretVersionRequest, + AddSecretVersionRequest, + CreateSecretRequest, + DeleteSecretRequest, +) from prefect import get_run_logger, task +from prefect.blocks.abstract import SecretBlock +from prefect.utilities.asyncutils import run_sync_in_worker_thread +from pydantic import Field if TYPE_CHECKING: from prefect_gcp.credentials import GcpCredentials @@ -67,7 +77,7 @@ def example_cloud_storage_create_secret_flow(): @task async def update_secret( secret_name: str, - secret_value: Union[str, bytes], + secret_data: Union[str, bytes], gcp_credentials: "GcpCredentials", timeout: float = 60, project: Optional[str] = None, @@ -77,7 +87,7 @@ async def update_secret( Args: secret_name: Name of the secret to retrieve. - secret_value: Desired value of the secret. Can be either `str` or `bytes`. + secret_data: Desired value of the secret. Can be either `str` or `bytes`. gcp_credentials: Credentials to use for authentication with GCP. timeout: The number of seconds the transport should wait for the server response. @@ -96,7 +106,7 @@ async def update_secret( @flow() def example_cloud_storage_update_secret_flow(): gcp_credentials = GcpCredentials(project="project") - secret_path = update_secret("secret_name", "secret_value", gcp_credentials) + secret_path = update_secret("secret_name", "secret_data", gcp_credentials) return secret_path example_cloud_storage_update_secret_flow() @@ -109,12 +119,12 @@ def example_cloud_storage_update_secret_flow(): project = project or gcp_credentials.project parent = f"projects/{project}/secrets/{secret_name}" - if isinstance(secret_value, str): - secret_value = secret_value.encode("UTF-8") + if isinstance(secret_data, str): + secret_data = secret_data.encode("UTF-8") partial_add = partial( client.add_secret_version, parent=parent, - payload={"data": secret_value}, + payload={"data": secret_data}, timeout=timeout, ) response = await to_thread.run_sync(partial_add) @@ -152,8 +162,8 @@ async def read_secret( @flow() def example_cloud_storage_read_secret_flow(): gcp_credentials = GcpCredentials(project="project") - secret_value = read_secret("secret_name", gcp_credentials, version_id=1) - return secret_value + secret_data = read_secret("secret_name", gcp_credentials, version_id=1) + return secret_data example_cloud_storage_read_secret_flow() ``` @@ -251,8 +261,8 @@ async def delete_secret_version( @flow() def example_cloud_storage_delete_secret_version_flow(): gcp_credentials = GcpCredentials(project="project") - secret_value = delete_secret_version("secret_name", 1, gcp_credentials) - return secret_value + secret_data = delete_secret_version("secret_name", 1, gcp_credentials) + return secret_data example_cloud_storage_delete_secret_version_flow() ``` @@ -270,3 +280,81 @@ def example_cloud_storage_delete_secret_version_flow(): partial_destroy = partial(client.destroy_secret_version, name=name, timeout=timeout) await to_thread.run_sync(partial_destroy) return name + + +class SecretManager(SecretBlock): + + gcp_credentials: GcpCredentials + secret_name: str = Field(default=..., description="Name of the secret to retrieve.") + + async def read_secret( + self, + version_id: Union[str, int] = "latest", + ) -> Any: + client = self.gcp_credentials.get_secret_manager_client() + project = self.gcp_credentials.project + name = f"projects/{project}/secrets/{self.secret_name}/versions/{version_id}" + request = AccessSecretVersionRequest(name=name) + response = await run_sync_in_worker_thread( + client.access_secret_version, request=request + ) + secret = response.payload.data.decode("UTF-8") + return secret + + async def write_secret(self, secret_data: bytes) -> str: + """ + Writes the secret to the secret storage service. + + Args: + secret_data: The secret to write. + + Returns: + The path that the secret was written to. + """ + client = self.gcp_credentials.get_secret_manager_client() + project = self.gcp_credentials.project + + parent = f"projects/{project}/" + secret_id = self.secret_name + secret = Secret(payload=SecretPayload(data=secret_data)) + request = CreateSecretRequest(parent=parent, secret_id=secret_id, secret=secret) + response = await run_sync_in_worker_thread( + client.create_secret, request=request + ) + return response.name + + async def update_secret(self, secret_data) -> str: + """ + Updates the secret to the secret storage service. + + Args: + secret_data: The secret to update. + + Returns: + The path that the secret was updated to. + """ + client = self.gcp_credentials.get_secret_manager_client() + project = self.gcp_credentials.project + + parent = f"projects/{project}/secrets/{self.secret_name}/" + secret = Secret(payload=SecretPayload(data=secret_data)) + request = AddSecretVersionRequest(parent=parent, secret=secret) + response = await run_sync_in_worker_thread( + client.add_secret_version, request=request + ) + return response.name + + async def delete_secret(self) -> str: + """ + Deletes the secret from the secret storage service. + + Returns: + The path that the secret was deleted from. + """ + client = self.gcp_credentials.get_secret_manager_client() + project = self.gcp_credentials.project + + name = f"projects/{project}/secrets/{self.secret_name}/" + request = DeleteSecretRequest(name=name) + await run_sync_in_worker_thread(client.delete_secret, request=request) + return name From 53dde3c2c10f0e32c386ce9389538083f1215a16 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Tue, 13 Dec 2022 19:57:49 -0800 Subject: [PATCH 03/10] Do not rename other --- prefect_gcp/secret_manager.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index 733d5375..10c129a9 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -77,7 +77,7 @@ def example_cloud_storage_create_secret_flow(): @task async def update_secret( secret_name: str, - secret_data: Union[str, bytes], + secret_value: Union[str, bytes], gcp_credentials: "GcpCredentials", timeout: float = 60, project: Optional[str] = None, @@ -87,7 +87,7 @@ async def update_secret( Args: secret_name: Name of the secret to retrieve. - secret_data: Desired value of the secret. Can be either `str` or `bytes`. + secret_value: Desired value of the secret. Can be either `str` or `bytes`. gcp_credentials: Credentials to use for authentication with GCP. timeout: The number of seconds the transport should wait for the server response. @@ -106,7 +106,7 @@ async def update_secret( @flow() def example_cloud_storage_update_secret_flow(): gcp_credentials = GcpCredentials(project="project") - secret_path = update_secret("secret_name", "secret_data", gcp_credentials) + secret_path = update_secret("secret_name", "secret_value", gcp_credentials) return secret_path example_cloud_storage_update_secret_flow() @@ -119,12 +119,12 @@ def example_cloud_storage_update_secret_flow(): project = project or gcp_credentials.project parent = f"projects/{project}/secrets/{secret_name}" - if isinstance(secret_data, str): - secret_data = secret_data.encode("UTF-8") + if isinstance(secret_value, str): + secret_value = secret_value.encode("UTF-8") partial_add = partial( client.add_secret_version, parent=parent, - payload={"data": secret_data}, + payload={"data": secret_value}, timeout=timeout, ) response = await to_thread.run_sync(partial_add) @@ -162,8 +162,8 @@ async def read_secret( @flow() def example_cloud_storage_read_secret_flow(): gcp_credentials = GcpCredentials(project="project") - secret_data = read_secret("secret_name", gcp_credentials, version_id=1) - return secret_data + secret_value = read_secret("secret_name", gcp_credentials, version_id=1) + return secret_value example_cloud_storage_read_secret_flow() ``` @@ -261,8 +261,8 @@ async def delete_secret_version( @flow() def example_cloud_storage_delete_secret_version_flow(): gcp_credentials = GcpCredentials(project="project") - secret_data = delete_secret_version("secret_name", 1, gcp_credentials) - return secret_data + secret_value = delete_secret_version("secret_name", 1, gcp_credentials) + return secret_value example_cloud_storage_delete_secret_version_flow() ``` From 83325347e8c44f6ff323d880455ad372e5ffb4c6 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Wed, 14 Dec 2022 13:25:51 -0800 Subject: [PATCH 04/10] Make bytes --- prefect_gcp/secret_manager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index 10c129a9..9d2d8225 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -1,5 +1,5 @@ from functools import partial -from typing import TYPE_CHECKING, Any, Optional, Union +from typing import TYPE_CHECKING, Optional, Union from anyio import to_thread from google.cloud.secretmanager_v1.types.resources import Secret, SecretPayload @@ -290,7 +290,7 @@ class SecretManager(SecretBlock): async def read_secret( self, version_id: Union[str, int] = "latest", - ) -> Any: + ) -> bytes: client = self.gcp_credentials.get_secret_manager_client() project = self.gcp_credentials.project name = f"projects/{project}/secrets/{self.secret_name}/versions/{version_id}" From 3d86fea7b0a87ab81db7955c154b642c1f7d9041 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Mon, 19 Dec 2022 12:42:50 -0800 Subject: [PATCH 05/10] Fix implementations, add logs, and changelog --- CHANGELOG.md | 2 + prefect_gcp/secret_manager.py | 87 ++++++++++++++++++++--------------- 2 files changed, 52 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a4923f7..65370b00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `SecretBlock` methods - [#86](https://github.com/PrefectHQ/prefect-gcp/pull/86) + ### Changed - Made `GcpCredentials.get_access_token` sync compatible - [#80](https://github.com/PrefectHQ/prefect-gcp/pull/80) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index 9d2d8225..8c1306e9 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -1,8 +1,13 @@ from functools import partial -from typing import TYPE_CHECKING, Optional, Union +from typing import Optional, Union from anyio import to_thread -from google.cloud.secretmanager_v1.types.resources import Secret, SecretPayload +from google.api_core.exceptions import NotFound +from google.cloud.secretmanager_v1.types.resources import ( + Replication, + Secret, + SecretPayload, +) from google.cloud.secretmanager_v1.types.service import ( AccessSecretVersionRequest, AddSecretVersionRequest, @@ -11,11 +16,10 @@ ) from prefect import get_run_logger, task from prefect.blocks.abstract import SecretBlock -from prefect.utilities.asyncutils import run_sync_in_worker_thread +from prefect.utilities.asyncutils import run_sync_in_worker_thread, sync_compatible from pydantic import Field -if TYPE_CHECKING: - from prefect_gcp.credentials import GcpCredentials +from prefect_gcp.credentials import GcpCredentials @task @@ -285,8 +289,9 @@ def example_cloud_storage_delete_secret_version_flow(): class SecretManager(SecretBlock): gcp_credentials: GcpCredentials - secret_name: str = Field(default=..., description="Name of the secret to retrieve.") + secret_name: str = Field(default=..., description="Name of the secret to manage.") + @sync_compatible async def read_secret( self, version_id: Union[str, int] = "latest", @@ -295,15 +300,20 @@ async def read_secret( project = self.gcp_credentials.project name = f"projects/{project}/secrets/{self.secret_name}/versions/{version_id}" request = AccessSecretVersionRequest(name=name) + + self.logger.debug(f"Preparing to read secret data from {name!r}.") response = await run_sync_in_worker_thread( client.access_secret_version, request=request ) secret = response.payload.data.decode("UTF-8") + self.logger.info(f"The secret {name!r} data was successfully read.") return secret + @sync_compatible async def write_secret(self, secret_data: bytes) -> str: """ - Writes the secret to the secret storage service. + Writes the secret data to the secret storage service; if it doesn't exist + it will be created. Args: secret_data: The secret to write. @@ -313,37 +323,37 @@ async def write_secret(self, secret_data: bytes) -> str: """ client = self.gcp_credentials.get_secret_manager_client() project = self.gcp_credentials.project - - parent = f"projects/{project}/" - secret_id = self.secret_name - secret = Secret(payload=SecretPayload(data=secret_data)) - request = CreateSecretRequest(parent=parent, secret_id=secret_id, secret=secret) - response = await run_sync_in_worker_thread( - client.create_secret, request=request - ) - return response.name - - async def update_secret(self, secret_data) -> str: - """ - Updates the secret to the secret storage service. - - Args: - secret_data: The secret to update. - - Returns: - The path that the secret was updated to. - """ - client = self.gcp_credentials.get_secret_manager_client() - project = self.gcp_credentials.project - - parent = f"projects/{project}/secrets/{self.secret_name}/" - secret = Secret(payload=SecretPayload(data=secret_data)) - request = AddSecretVersionRequest(parent=parent, secret=secret) - response = await run_sync_in_worker_thread( - client.add_secret_version, request=request - ) + parent = f"projects/{project}/secrets/{self.secret_name}" + payload = SecretPayload(data=secret_data) + add_request = AddSecretVersionRequest(parent=parent, payload=payload) + + self.logger.debug(f"Preparing to write secret data to {parent!r}.") + try: + response = await run_sync_in_worker_thread( + client.add_secret_version, request=add_request + ) + except NotFound: + self.logger.info( + f"The secret {parent!r} does not exist yet, creating it now." + ) + create_parent = f"projects/{project}" + secret_id = self.secret_name + secret = Secret(replication=Replication(automatic=Replication.Automatic())) + create_request = CreateSecretRequest( + parent=create_parent, secret_id=secret_id, secret=secret + ) + await run_sync_in_worker_thread( + client.create_secret, request=create_request + ) + + response = await run_sync_in_worker_thread( + client.add_secret_version, request=add_request + ) + + self.logger.info(f"The secret data was written successfully to {parent!r}.") return response.name + @sync_compatible async def delete_secret(self) -> str: """ Deletes the secret from the secret storage service. @@ -354,7 +364,10 @@ async def delete_secret(self) -> str: client = self.gcp_credentials.get_secret_manager_client() project = self.gcp_credentials.project - name = f"projects/{project}/secrets/{self.secret_name}/" + name = f"projects/{project}/secrets/{self.secret_name}" request = DeleteSecretRequest(name=name) + + self.logger.debug(f"Preparing to delete the secret {name!r}.") await run_sync_in_worker_thread(client.delete_secret, request=request) + self.logger.info(f"The secret {name!r} was successfully deleted.") return name From 6f1e9484075b78a94f070d82a7fee07d67d46325 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Mon, 19 Dec 2022 16:27:22 -0800 Subject: [PATCH 06/10] Add tests --- prefect_gcp/secret_manager.py | 1 + tests/conftest.py | 27 ++++++++++++++++++++------- tests/test_secret_manager.py | 32 +++++++++++++++++++++++++++++--- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index 8c1306e9..6ec1fa94 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -346,6 +346,7 @@ async def write_secret(self, secret_data: bytes) -> str: client.create_secret, request=create_request ) + self.logger.debug(f"Preparing to write secret data to {parent!r} again.") response = await run_sync_in_worker_thread( client.add_secret_version, request=add_request ) diff --git a/tests/conftest.py b/tests/conftest.py index f40fd16f..824e4a84 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ from unittest.mock import MagicMock import pytest +from google.api_core.exceptions import NotFound as ApiCoreNotFound from google.cloud.aiplatform_v1.types.job_state import JobState from google.cloud.exceptions import NotFound from prefect.testing.utilities import prefect_test_harness @@ -139,25 +140,37 @@ class SecretManagerClient: def __init__(self, credentials=None, project=None): self.credentials = credentials self.project = project + self._secrets = {} - def create_secret(self, parent=None, secret_id=None, **kwds): + def create_secret(self, request=None, parent=None, secret_id=None, **kwds): response = MagicMock() - response.name = secret_id + if request: + parent = request.parent + secret_id = request.secret_id + name = f"{parent}/secrets/{secret_id}" + response.name = name + self._secrets[name] = None return response - def add_secret_version(self, parent, payload, **kwds): + def add_secret_version(self, request=None, parent=None, payload=None, **kwds): response = MagicMock() - response.name = payload["data"] + if request: + parent = request.parent + + if parent not in self._secrets: + raise ApiCoreNotFound(f"{parent!r} does not exist.") + + response.name = parent return response - def access_secret_version(self, name, **kwds): + def access_secret_version(self, request=None, name=None, **kwds): response = MagicMock() payload = MagicMock() - payload.data = f"{name}".encode() + payload.data = "secret_data".encode("utf-8") response.payload = payload return response - def delete_secret(self, name, **kwds): + def delete_secret(self, request=None, name=None, **kwds): return name def destroy_secret_version(self, name, **kwds): diff --git a/tests/test_secret_manager.py b/tests/test_secret_manager.py index 31906425..431bbd08 100644 --- a/tests/test_secret_manager.py +++ b/tests/test_secret_manager.py @@ -2,6 +2,7 @@ from prefect import flow from prefect_gcp.secret_manager import ( + SecretManager, create_secret, delete_secret, delete_secret_version, @@ -15,19 +16,20 @@ def test_create_secret(gcp_credentials): def test_flow(): return create_secret("secret_name", gcp_credentials) - assert test_flow() == "secret_name" + assert test_flow() == "projects/gcp_credentials_project/secrets/secret_name" @pytest.mark.parametrize("secret_value", ["secret", b"secret_byte"]) def test_update_secret(secret_value, gcp_credentials): @flow def test_flow(): + create_secret("secret_name", gcp_credentials) return update_secret("secret_name", secret_value, gcp_credentials) if isinstance(secret_value, str): secret_value = secret_value.encode("UTF-8") - assert test_flow() == secret_value + assert test_flow() == "projects/gcp_credentials_project/secrets/secret_name" def test_read_secret(gcp_credentials): @@ -35,7 +37,7 @@ def test_read_secret(gcp_credentials): def test_flow(): return read_secret("secret_name", gcp_credentials) - expected = "projects/gcp_credentials_project/secrets/secret_name/versions/latest" + expected = "secret_data" assert test_flow() == expected @@ -72,3 +74,27 @@ def test_flow(): project = project or gcp_credentials.project path = f"projects/{project}/secrets/{secret_name}/versions/{version_id}" assert test_flow() == path + + +class TestSecretManager: + @pytest.fixture + def secret_manager(self, gcp_credentials): + _secret_manager = SecretManager( + gcp_credentials=gcp_credentials, secret_name="my_secret_name" + ) + return _secret_manager + + def test_write_secret(self, secret_manager): + expected = "projects/gcp_credentials_project/secrets/my_secret_name" + actual = secret_manager.write_secret(secret_data=b"my_secret_data") + assert actual == expected + + def test_read_secret(self, secret_manager): + expected = "secret_data" + actual = secret_manager.read_secret() + assert actual == expected + + def test_delete_secret(self, secret_manager): + expected = "projects/gcp_credentials_project/secrets/my_secret_name" + actual = secret_manager.delete_secret() + assert actual == expected From 91262253effffd685203a0261f670aac06e25ec9 Mon Sep 17 00:00:00 2001 From: Andrew <15331990+ahuang11@users.noreply.github.com> Date: Mon, 19 Dec 2022 16:28:22 -0800 Subject: [PATCH 07/10] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65370b00..28d4b0b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- `SecretBlock` methods - [#86](https://github.com/PrefectHQ/prefect-gcp/pull/86) +- `SecretBlock` block with `read_secret`, `write_secret`, and `delete_secret` methods - [#86](https://github.com/PrefectHQ/prefect-gcp/pull/86) ### Changed From 62fd3aa9ea59be40ef3e042cbd791c261f1416e7 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Tue, 20 Dec 2022 11:59:47 -0800 Subject: [PATCH 08/10] Comments --- prefect_gcp/secret_manager.py | 9 ++++++--- tests/conftest.py | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index 6ec1fa94..d2cca019 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -290,15 +290,15 @@ class SecretManager(SecretBlock): gcp_credentials: GcpCredentials secret_name: str = Field(default=..., description="Name of the secret to manage.") + secret_version: str = "latest" @sync_compatible async def read_secret( self, - version_id: Union[str, int] = "latest", ) -> bytes: client = self.gcp_credentials.get_secret_manager_client() project = self.gcp_credentials.project - name = f"projects/{project}/secrets/{self.secret_name}/versions/{version_id}" + name = f"projects/{project}/secrets/{self.secret_name}/versions/{self.secret_version}" # noqa request = AccessSecretVersionRequest(name=name) self.logger.debug(f"Preparing to read secret data from {name!r}.") @@ -306,7 +306,10 @@ async def read_secret( client.access_secret_version, request=request ) secret = response.payload.data.decode("UTF-8") - self.logger.info(f"The secret {name!r} data was successfully read.") + self.logger.info( + f"The secret {name!r} data version {self.secret_version!r} " + f"was successfully read." + ) return secret @sync_compatible diff --git a/tests/conftest.py b/tests/conftest.py index 824e4a84..74e6cafb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -136,7 +136,7 @@ def load_table_from_file(self, *args, **kwargs): return output -class SecretManagerClient: +class GcpSecretClient: def __init__(self, credentials=None, project=None): self.credentials = credentials self.project = project @@ -219,7 +219,7 @@ def gcp_credentials(monkeypatch, google_auth, mock_credentials, job_service_clie gcp_credentials_mock._service_account_email = "my_service_account_email" gcp_credentials_mock.cloud_storage_client = CloudStorageClient() - gcp_credentials_mock.secret_manager_client = SecretManagerClient() + gcp_credentials_mock.secret_manager_client = GcpSecretClient() gcp_credentials_mock.job_service_client = job_service_client gcp_credentials_mock.job_service_client.__enter__.return_value = job_service_client From a3b3af2b93de2d76cf6cfd4bbb9db975ecac2c85 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Tue, 20 Dec 2022 13:33:05 -0800 Subject: [PATCH 09/10] Rename --- prefect_gcp/secret_manager.py | 2 +- tests/test_secret_manager.py | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/prefect_gcp/secret_manager.py b/prefect_gcp/secret_manager.py index d2cca019..59a29176 100644 --- a/prefect_gcp/secret_manager.py +++ b/prefect_gcp/secret_manager.py @@ -286,7 +286,7 @@ def example_cloud_storage_delete_secret_version_flow(): return name -class SecretManager(SecretBlock): +class GcpSecret(SecretBlock): gcp_credentials: GcpCredentials secret_name: str = Field(default=..., description="Name of the secret to manage.") diff --git a/tests/test_secret_manager.py b/tests/test_secret_manager.py index 431bbd08..2d5dd68e 100644 --- a/tests/test_secret_manager.py +++ b/tests/test_secret_manager.py @@ -2,7 +2,7 @@ from prefect import flow from prefect_gcp.secret_manager import ( - SecretManager, + GcpSecret, create_secret, delete_secret, delete_secret_version, @@ -76,25 +76,25 @@ def test_flow(): assert test_flow() == path -class TestSecretManager: +class TestGcpSecret: @pytest.fixture - def secret_manager(self, gcp_credentials): - _secret_manager = SecretManager( + def gcp_secret(self, gcp_credentials): + _gcp_secret = GcpSecret( gcp_credentials=gcp_credentials, secret_name="my_secret_name" ) - return _secret_manager + return _gcp_secret - def test_write_secret(self, secret_manager): + def test_write_secret(self, gcp_secret): expected = "projects/gcp_credentials_project/secrets/my_secret_name" - actual = secret_manager.write_secret(secret_data=b"my_secret_data") + actual = gcp_secret.write_secret(secret_data=b"my_secret_data") assert actual == expected - def test_read_secret(self, secret_manager): + def test_read_secret(self, gcp_secret): expected = "secret_data" - actual = secret_manager.read_secret() + actual = gcp_secret.read_secret() assert actual == expected - def test_delete_secret(self, secret_manager): + def test_delete_secret(self, gcp_secret): expected = "projects/gcp_credentials_project/secrets/my_secret_name" - actual = secret_manager.delete_secret() + actual = gcp_secret.delete_secret() assert actual == expected From ad07a0f1e9ee66c984319bc03908c9b2739f8861 Mon Sep 17 00:00:00 2001 From: ahuang11 Date: Tue, 20 Dec 2022 13:45:43 -0800 Subject: [PATCH 10/10] Tweaks --- CHANGELOG.md | 2 +- tests/conftest.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3216ba4b..689117d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - `list_blobs`, `download_object_to_path`, `download_object_to_file_object`, `download_folder_to_path`, `upload_from_path`, `upload_from_file_object`, `upload_from_folder` methods in `GcsBucket` - [#85](https://github.com/PrefectHQ/prefect-gcp/pull/85) -- `SecretBlock` block with `read_secret`, `write_secret`, and `delete_secret` methods - [#86](https://github.com/PrefectHQ/prefect-gcp/pull/86) +- `GcpSecret` block with `read_secret`, `write_secret`, and `delete_secret` methods - [#86](https://github.com/PrefectHQ/prefect-gcp/pull/86) ### Changed diff --git a/tests/conftest.py b/tests/conftest.py index 63d34817..2593ffe2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -142,7 +142,7 @@ def load_table_from_file(self, *args, **kwargs): return output -class GcpSecretClient: +class SecretManagerClient: def __init__(self, credentials=None, project=None): self.credentials = credentials self.project = project @@ -225,7 +225,7 @@ def gcp_credentials(monkeypatch, google_auth, mock_credentials, job_service_clie gcp_credentials_mock._service_account_email = "my_service_account_email" gcp_credentials_mock.cloud_storage_client = CloudStorageClient() - gcp_credentials_mock.secret_manager_client = GcpSecretClient() + gcp_credentials_mock.secret_manager_client = SecretManagerClient() gcp_credentials_mock.job_service_client = job_service_client gcp_credentials_mock.job_service_client.__enter__.return_value = job_service_client