Skip to content

Commit

Permalink
Merge pull request #367 from lsst-sqre/tickets/DM-48495
Browse files Browse the repository at this point in the history
DM-48495: Allow SecretStr for EncryptedPydanticRedisStorage
  • Loading branch information
rra authored Jan 22, 2025
2 parents 5eee3d0 + cb1e076 commit 3354734
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 3 deletions.
3 changes: 3 additions & 0 deletions changelog.d/20250122_084940_rra_DM_48495.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### New features

- Allow the encryption key to be passed to `safir.redis.EncryptedPydanticRedisStorage` as a `pydantic.SecretStr` instead of `str`. This allows easier integration with secrets that come from Pydantic-parsed settings.
6 changes: 4 additions & 2 deletions safir/src/safir/redis/_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"Install it with `pip install safir[redis]`."
) from e
from cryptography.fernet import Fernet
from pydantic import BaseModel
from pydantic import BaseModel, SecretStr

from safir.slack.blockkit import (
SlackCodeBlock,
Expand Down Expand Up @@ -241,10 +241,12 @@ def __init__(
*,
datatype: type[S],
redis: redis.Redis,
encryption_key: str,
encryption_key: str | SecretStr,
key_prefix: str = "",
) -> None:
super().__init__(datatype=datatype, redis=redis, key_prefix=key_prefix)
if isinstance(encryption_key, SecretStr):
encryption_key = encryption_key.get_secret_value()
self._fernet = Fernet(encryption_key.encode())

def _serialize(self, obj: S) -> bytes:
Expand Down
23 changes: 22 additions & 1 deletion safir/tests/redis_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import pytest
import redis.asyncio as redis
from cryptography.fernet import Fernet
from pydantic import BaseModel, Field
from pydantic import BaseModel, Field, SecretStr

from safir.redis import (
DeserializeError,
Expand Down Expand Up @@ -77,6 +77,27 @@ async def test_encrypted_pydantic_redis_storage(
await basic_testing(storage)


@pytest.mark.asyncio
async def test_encrypted_pydantic_redis_storage_secretstr(
redis_client: redis.Redis,
) -> None:
"""Test that the secret can be passed as str or SecretStr."""
encryption_key = Fernet.generate_key().decode()
storage = EncryptedPydanticRedisStorage(
datatype=DemoModel, redis=redis_client, encryption_key=encryption_key
)

await storage.store("mark42", DemoModel(name="Mark", value=42))

storage = EncryptedPydanticRedisStorage(
datatype=DemoModel,
redis=redis_client,
encryption_key=SecretStr(encryption_key),
)

assert await storage.get("mark42") == DemoModel(name="Mark", value=42)


class PetModel(BaseModel):
id: int
name: str
Expand Down

0 comments on commit 3354734

Please sign in to comment.