oe-python-template 0.13.12__py3-none-any.whl → 0.13.14__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oe_python_template/utils/_sentry.py +102 -1
- {oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/METADATA +1 -1
- {oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/RECORD +6 -6
- {oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/WHEEL +0 -0
- {oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/entry_points.txt +0 -0
- {oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,15 +1,115 @@
|
|
|
1
1
|
"""Sentry integration for application monitoring."""
|
|
2
2
|
|
|
3
|
+
import re
|
|
4
|
+
import urllib.parse
|
|
3
5
|
from typing import Annotated
|
|
4
6
|
|
|
5
7
|
import sentry_sdk
|
|
6
|
-
from pydantic import BeforeValidator, Field, PlainSerializer, SecretStr
|
|
8
|
+
from pydantic import AfterValidator, BeforeValidator, Field, PlainSerializer, SecretStr
|
|
7
9
|
from pydantic_settings import SettingsConfigDict
|
|
8
10
|
from sentry_sdk.integrations.typer import TyperIntegration
|
|
9
11
|
|
|
10
12
|
from ._constants import __env__, __env_file__, __project_name__, __version__
|
|
11
13
|
from ._settings import OpaqueSettings, load_settings, strip_to_none_before_validator
|
|
12
14
|
|
|
15
|
+
_ERR_MSG_MISSING_SCHEME = "Sentry DSN is missing URL scheme (protocol)"
|
|
16
|
+
_ERR_MSG_MISSING_NETLOC = "Sentry DSN is missing network location (domain)"
|
|
17
|
+
_ERR_MSG_NON_HTTPS = "Sentry DSN must use HTTPS protocol for security"
|
|
18
|
+
_ERR_MSG_INVALID_DOMAIN = "Sentry DSN must use a valid Sentry domain (ingest.us.sentry.io or ingest.de.sentry.io)"
|
|
19
|
+
_ERR_MSG_INVALID_FORMAT = "Invalid Sentry DSN format"
|
|
20
|
+
_VALID_SENTRY_DOMAIN_PATTERN = r"^[a-f0-9]+@o\d+\.ingest\.(us|de)\.sentry\.io$"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _validate_url_scheme(parsed_url: urllib.parse.ParseResult) -> None:
|
|
24
|
+
"""Validate that the URL has a scheme.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
parsed_url: The parsed URL to validate
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
ValueError: If URL is missing scheme
|
|
31
|
+
"""
|
|
32
|
+
if not parsed_url.scheme:
|
|
33
|
+
raise ValueError(_ERR_MSG_MISSING_SCHEME)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _validate_url_netloc(parsed_url: urllib.parse.ParseResult) -> None:
|
|
37
|
+
"""Validate that the URL has a network location.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
parsed_url: The parsed URL to validate
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
ValueError: If URL is missing network location
|
|
44
|
+
"""
|
|
45
|
+
if not parsed_url.netloc:
|
|
46
|
+
raise ValueError(_ERR_MSG_MISSING_NETLOC)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _validate_https_scheme(parsed_url: urllib.parse.ParseResult) -> None:
|
|
50
|
+
"""Validate that the URL uses HTTPS scheme.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
parsed_url: The parsed URL to validate
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ValueError: If URL doesn't use HTTPS scheme
|
|
57
|
+
"""
|
|
58
|
+
if parsed_url.scheme != "https":
|
|
59
|
+
raise ValueError(_ERR_MSG_NON_HTTPS)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _validate_sentry_domain(netloc_with_auth: str) -> None:
|
|
63
|
+
"""Validate that the URL uses a valid Sentry domain.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
netloc_with_auth: The network location with auth part
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
ValueError: If URL doesn't use a valid Sentry domain
|
|
70
|
+
"""
|
|
71
|
+
if "@" not in netloc_with_auth:
|
|
72
|
+
raise ValueError(_ERR_MSG_INVALID_DOMAIN)
|
|
73
|
+
|
|
74
|
+
user_pass, domain = netloc_with_auth.split("@", 1)
|
|
75
|
+
full_auth = f"{user_pass}@{domain}"
|
|
76
|
+
if not re.match(_VALID_SENTRY_DOMAIN_PATTERN, full_auth):
|
|
77
|
+
raise ValueError(_ERR_MSG_INVALID_DOMAIN)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def validate_https_dsn(value: SecretStr | None) -> SecretStr | None:
|
|
81
|
+
"""Validate that the Sentry DSN is a valid HTTPS URL.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
value: The DSN value to validate
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
SecretStr | None: The validated DSN value
|
|
88
|
+
|
|
89
|
+
Raises:
|
|
90
|
+
ValueError: If DSN isn't a valid HTTPS URL with specific error details
|
|
91
|
+
"""
|
|
92
|
+
if value is None:
|
|
93
|
+
return value
|
|
94
|
+
|
|
95
|
+
dsn = value.get_secret_value()
|
|
96
|
+
try:
|
|
97
|
+
parsed_url = urllib.parse.urlparse(dsn)
|
|
98
|
+
|
|
99
|
+
# Call validation functions outside of the try block
|
|
100
|
+
_validate_url_scheme(parsed_url)
|
|
101
|
+
_validate_url_netloc(parsed_url)
|
|
102
|
+
_validate_https_scheme(parsed_url)
|
|
103
|
+
_validate_sentry_domain(parsed_url.netloc)
|
|
104
|
+
|
|
105
|
+
except ValueError as exc:
|
|
106
|
+
raise exc from None
|
|
107
|
+
except Exception as exc:
|
|
108
|
+
error_message = _ERR_MSG_INVALID_FORMAT
|
|
109
|
+
raise ValueError(error_message) from exc
|
|
110
|
+
|
|
111
|
+
return value
|
|
112
|
+
|
|
13
113
|
|
|
14
114
|
class SentrySettings(OpaqueSettings):
|
|
15
115
|
"""Configuration settings for Sentry integration."""
|
|
@@ -24,6 +124,7 @@ class SentrySettings(OpaqueSettings):
|
|
|
24
124
|
dsn: Annotated[
|
|
25
125
|
SecretStr | None,
|
|
26
126
|
BeforeValidator(strip_to_none_before_validator),
|
|
127
|
+
AfterValidator(validate_https_dsn),
|
|
27
128
|
PlainSerializer(func=OpaqueSettings.serialize_sensitive_info, return_type=str, when_used="always"),
|
|
28
129
|
Field(description="Sentry DSN", examples=["https://SECRET@SECRET.ingest.de.sentry.io/SECRET"], default=None),
|
|
29
130
|
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oe-python-template
|
|
3
|
-
Version: 0.13.
|
|
3
|
+
Version: 0.13.14
|
|
4
4
|
Summary: 🧠 Copier template to scaffold Python projects compliant with best practices and modern tooling.
|
|
5
5
|
Project-URL: Homepage, https://oe-python-template.readthedocs.io/en/latest/
|
|
6
6
|
Project-URL: Documentation, https://oe-python-template.readthedocs.io/en/latest/
|
|
@@ -28,13 +28,13 @@ oe_python_template/utils/_log.py,sha256=ZW4gs540SdjVK-2KeheLfDY15d_3xpO5FyGn7wTX
|
|
|
28
28
|
oe_python_template/utils/_logfire.py,sha256=wZYNVowQx7kh3XJoJ59FjUKdrta7tp6cXOJRUT6lDU8,2128
|
|
29
29
|
oe_python_template/utils/_notebook.py,sha256=oBQw9IBcXjuhzd1ECfOEPN4WJHGOm9xiPtrs11GtWG4,1777
|
|
30
30
|
oe_python_template/utils/_process.py,sha256=40R0NZMqJUn0iUPERzohSUpJgU1HcJApIg1HipIxFCw,941
|
|
31
|
-
oe_python_template/utils/_sentry.py,sha256=
|
|
31
|
+
oe_python_template/utils/_sentry.py,sha256=7nONiWZP0hWX0QAEPcg7No3FF1BF4S-Sl0wgG7xLw8g,6367
|
|
32
32
|
oe_python_template/utils/_service.py,sha256=atHAejvBucKXjzhsMSdOBBFa7rRD74zcV70Pp0pl0Tg,1038
|
|
33
33
|
oe_python_template/utils/_settings.py,sha256=owFoaHEzJnVD3EVyOWF4rfIY7g6eLnU6rN0m4VHhCbA,2464
|
|
34
34
|
oe_python_template/utils/boot.py,sha256=Qgq1sjT8d3fcfibnMyx5CVUJ_KKXgFI3ozZUIJbhh4I,2921
|
|
35
35
|
oe_python_template/utils/.vendored/bottle.py,sha256=kZAZmh3nRzCUf-9IKGpv0yqlMciZMA_DNaaMDdcQmt0,175437
|
|
36
|
-
oe_python_template-0.13.
|
|
37
|
-
oe_python_template-0.13.
|
|
38
|
-
oe_python_template-0.13.
|
|
39
|
-
oe_python_template-0.13.
|
|
40
|
-
oe_python_template-0.13.
|
|
36
|
+
oe_python_template-0.13.14.dist-info/METADATA,sha256=535E3ddxUlLQusQdLrJGP0NyadIxqL-_H8v7p_NVYgk,34476
|
|
37
|
+
oe_python_template-0.13.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
38
|
+
oe_python_template-0.13.14.dist-info/entry_points.txt,sha256=IroSSWhLGxus9rxcashkYQda39TTvf7LbUMYtOKXUBE,66
|
|
39
|
+
oe_python_template-0.13.14.dist-info/licenses/LICENSE,sha256=5H409K6xzz9U5eUaoAHQExNkoWJRlU0LEj6wL2QJ34s,1113
|
|
40
|
+
oe_python_template-0.13.14.dist-info/RECORD,,
|
|
File without changes
|
{oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{oe_python_template-0.13.12.dist-info → oe_python_template-0.13.14.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|