Created
November 23, 2024 04:34
-
-
Save mpkocher/8410ace54c03a8017f21aa729759132d to your computer and use it in GitHub Desktop.
Modeling Secrets in Pydantic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Pydantic Secrets | |
https://docs.pydantic.dev/latest/api/types/#pydantic.types.SecretStr | |
- Why does the "Box'ed" secret container understand (or leak) information of the secret? | |
- Internally, the "Box" shouldn't use `.get_secret_value()`. Otherwise, it's leaking info. | |
- Mixing up the Box and `.get_secret_value()` undermines the point of using `.get_secret_value()` | |
- Why is the hash value leaking? Comparing two secrets should require and explicit `s1.get_secret_value() == s2.get_secret_value()` call. | |
- Why does the repr/str communicate "non-empty" values? This is encouraging and enabling an anti-pattern. | |
- Documenting this functionality is confusing because the "Box" knows something about the secret. | |
For "non-provided" Secrets (e.g., Model(secret="")), it's better to model them as `None | Secret[T]`, where `T` would be a non-empty value. | |
Here's an example: | |
""" | |
from typing import Annotated | |
from pydantic import StringConstraints | |
from pydantic.types import Secret | |
StrNonEmpty = Annotated[str, StringConstraints(min_length=1)] | |
class SecretStrNonEmpty(Secret[StrNonEmpty]): | |
def _display(self) -> str: | |
return "*" * 5 | |
def __eq__(self, other) -> bool: | |
# If you want to access the secret, then | |
# explicitly call, .get_secret_value() | |
return False | |
def __hash__(self) -> int: | |
# Same reasoning as __eq___ | |
return id(self) | |
class A(BaseModel): | |
x: SecretStrNonEmpty | |
class B(BaseModel): | |
x: SecretStrNonEmpty | None | |
def example(): | |
axs = tuple(map(lambda x: A(x=x), ("a", "aa", "aaa"))) | |
print(axs) | |
bxs = tuple(map(lambda x: B(x=x), ('b', "b", None))) | |
print(bxs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment