From a20dec3572a3d5a88360fa074f7b2293ecda675a Mon Sep 17 00:00:00 2001 From: Russ Allbery Date: Wed, 17 Jul 2024 22:32:04 -0700 Subject: [PATCH] Accept SecretStr as the Slack webhook URL Allow the URL argument to SlackWebhookClient and SlackRouteErrorHandler to be given as a SecretStr so that applications that get that value from a SecretStr field of their configuration don't have to convert it first. --- changelog.d/20240717_223040_rra_DM_45281_queue.md | 3 +++ src/safir/slack/webhook.py | 10 +++++++--- tests/slack/webhook_test.py | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 changelog.d/20240717_223040_rra_DM_45281_queue.md diff --git a/changelog.d/20240717_223040_rra_DM_45281_queue.md b/changelog.d/20240717_223040_rra_DM_45281_queue.md new file mode 100644 index 00000000..0137c4fc --- /dev/null +++ b/changelog.d/20240717_223040_rra_DM_45281_queue.md @@ -0,0 +1,3 @@ +### New features + +- Allow the Slack webhook URL argument to `SlackWebhookClient` and `SlackRouteErrorHandler` to be given as a Pydantic `SecretStr` instead of a `str`. This simplifies code in applications that get that value from a secret. diff --git a/src/safir/slack/webhook.py b/src/safir/slack/webhook.py index 906a1894..f472c4b7 100644 --- a/src/safir/slack/webhook.py +++ b/src/safir/slack/webhook.py @@ -8,6 +8,7 @@ from fastapi import HTTPException, Request, Response from fastapi.exceptions import RequestValidationError from fastapi.routing import APIRoute +from pydantic import SecretStr from starlette.exceptions import HTTPException as StarletteHTTPException from structlog.stdlib import BoundLogger @@ -56,9 +57,12 @@ class SlackWebhookClient: """ def __init__( - self, hook_url: str, application: str, logger: BoundLogger + self, hook_url: str | SecretStr, application: str, logger: BoundLogger ) -> None: - self._hook_url = hook_url + if isinstance(hook_url, SecretStr): + self._hook_url = hook_url.get_secret_value() + else: + self._hook_url = hook_url self._application = application self._logger = logger @@ -175,7 +179,7 @@ class SlackRouteErrorHandler(APIRoute): @classmethod def initialize( - cls, hook_url: str, application: str, logger: BoundLogger + cls, hook_url: str | SecretStr, application: str, logger: BoundLogger ) -> None: """Configure Slack alerting. diff --git a/tests/slack/webhook_test.py b/tests/slack/webhook_test.py index 51fe7f77..9780d4b9 100644 --- a/tests/slack/webhook_test.py +++ b/tests/slack/webhook_test.py @@ -8,6 +8,7 @@ import structlog from fastapi import APIRouter, FastAPI from httpx import ASGITransport, AsyncClient +from pydantic import SecretStr from safir.datetime import current_datetime, format_datetime_for_logging from safir.slack.blockkit import SlackException, SlackMessage @@ -44,7 +45,7 @@ async def test_post(mock_slack: MockSlackWebhook) -> None: @pytest.mark.asyncio async def test_post_exception(mock_slack: MockSlackWebhook) -> None: logger = structlog.get_logger(__file__) - client = SlackWebhookClient(mock_slack.url, "App", logger) + client = SlackWebhookClient(SecretStr(mock_slack.url), "App", logger) exc = SlackException("Some exception message") await client.post_exception(exc)