sf-veritas 0.9.7__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.

Potentially problematic release.


This version of sf-veritas might be problematic. Click here for more details.

Files changed (86) hide show
  1. sf_veritas/.gitignore +2 -0
  2. sf_veritas/__init__.py +4 -0
  3. sf_veritas/app_config.py +49 -0
  4. sf_veritas/cli.py +336 -0
  5. sf_veritas/constants.py +3 -0
  6. sf_veritas/custom_excepthook.py +285 -0
  7. sf_veritas/custom_log_handler.py +53 -0
  8. sf_veritas/custom_output_wrapper.py +107 -0
  9. sf_veritas/custom_print.py +34 -0
  10. sf_veritas/django_app.py +5 -0
  11. sf_veritas/env_vars.py +83 -0
  12. sf_veritas/exception_handling_middleware.py +18 -0
  13. sf_veritas/exception_metaclass.py +69 -0
  14. sf_veritas/frame_tools.py +112 -0
  15. sf_veritas/import_hook.py +62 -0
  16. sf_veritas/infra_details/__init__.py +3 -0
  17. sf_veritas/infra_details/get_infra_details.py +24 -0
  18. sf_veritas/infra_details/kubernetes/__init__.py +3 -0
  19. sf_veritas/infra_details/kubernetes/get_cluster_name.py +147 -0
  20. sf_veritas/infra_details/kubernetes/get_details.py +7 -0
  21. sf_veritas/infra_details/running_on/__init__.py +17 -0
  22. sf_veritas/infra_details/running_on/kubernetes.py +11 -0
  23. sf_veritas/interceptors.py +252 -0
  24. sf_veritas/local_env_detect.py +118 -0
  25. sf_veritas/package_metadata.py +6 -0
  26. sf_veritas/patches/__init__.py +0 -0
  27. sf_veritas/patches/concurrent_futures.py +19 -0
  28. sf_veritas/patches/constants.py +1 -0
  29. sf_veritas/patches/exceptions.py +82 -0
  30. sf_veritas/patches/multiprocessing.py +32 -0
  31. sf_veritas/patches/network_libraries/__init__.py +51 -0
  32. sf_veritas/patches/network_libraries/aiohttp.py +100 -0
  33. sf_veritas/patches/network_libraries/curl_cffi.py +93 -0
  34. sf_veritas/patches/network_libraries/http_client.py +64 -0
  35. sf_veritas/patches/network_libraries/httpcore.py +152 -0
  36. sf_veritas/patches/network_libraries/httplib2.py +76 -0
  37. sf_veritas/patches/network_libraries/httpx.py +123 -0
  38. sf_veritas/patches/network_libraries/niquests.py +192 -0
  39. sf_veritas/patches/network_libraries/pycurl.py +71 -0
  40. sf_veritas/patches/network_libraries/requests.py +187 -0
  41. sf_veritas/patches/network_libraries/tornado.py +139 -0
  42. sf_veritas/patches/network_libraries/treq.py +122 -0
  43. sf_veritas/patches/network_libraries/urllib_request.py +129 -0
  44. sf_veritas/patches/network_libraries/utils.py +101 -0
  45. sf_veritas/patches/os.py +17 -0
  46. sf_veritas/patches/threading.py +32 -0
  47. sf_veritas/patches/web_frameworks/__init__.py +45 -0
  48. sf_veritas/patches/web_frameworks/aiohttp.py +133 -0
  49. sf_veritas/patches/web_frameworks/async_websocket_consumer.py +132 -0
  50. sf_veritas/patches/web_frameworks/blacksheep.py +107 -0
  51. sf_veritas/patches/web_frameworks/bottle.py +142 -0
  52. sf_veritas/patches/web_frameworks/cherrypy.py +246 -0
  53. sf_veritas/patches/web_frameworks/django.py +307 -0
  54. sf_veritas/patches/web_frameworks/eve.py +138 -0
  55. sf_veritas/patches/web_frameworks/falcon.py +229 -0
  56. sf_veritas/patches/web_frameworks/fastapi.py +145 -0
  57. sf_veritas/patches/web_frameworks/flask.py +186 -0
  58. sf_veritas/patches/web_frameworks/klein.py +40 -0
  59. sf_veritas/patches/web_frameworks/litestar.py +217 -0
  60. sf_veritas/patches/web_frameworks/pyramid.py +89 -0
  61. sf_veritas/patches/web_frameworks/quart.py +155 -0
  62. sf_veritas/patches/web_frameworks/robyn.py +114 -0
  63. sf_veritas/patches/web_frameworks/sanic.py +120 -0
  64. sf_veritas/patches/web_frameworks/starlette.py +144 -0
  65. sf_veritas/patches/web_frameworks/strawberry.py +269 -0
  66. sf_veritas/patches/web_frameworks/tornado.py +129 -0
  67. sf_veritas/patches/web_frameworks/utils.py +55 -0
  68. sf_veritas/print_override.py +13 -0
  69. sf_veritas/regular_data_transmitter.py +358 -0
  70. sf_veritas/request_interceptor.py +399 -0
  71. sf_veritas/request_utils.py +104 -0
  72. sf_veritas/server_status.py +1 -0
  73. sf_veritas/shutdown_flag.py +11 -0
  74. sf_veritas/subprocess_startup.py +3 -0
  75. sf_veritas/test_cli.py +145 -0
  76. sf_veritas/thread_local.py +436 -0
  77. sf_veritas/timeutil.py +114 -0
  78. sf_veritas/transmit_exception_to_sailfish.py +28 -0
  79. sf_veritas/transmitter.py +58 -0
  80. sf_veritas/types.py +44 -0
  81. sf_veritas/unified_interceptor.py +323 -0
  82. sf_veritas/utils.py +39 -0
  83. sf_veritas-0.9.7.dist-info/METADATA +83 -0
  84. sf_veritas-0.9.7.dist-info/RECORD +86 -0
  85. sf_veritas-0.9.7.dist-info/WHEEL +4 -0
  86. sf_veritas-0.9.7.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,358 @@
1
+ import threading
2
+ from typing import Any, Dict, List, Optional
3
+
4
+ import requests
5
+
6
+ from . import app_config
7
+ from .env_vars import SF_DEBUG
8
+ from .package_metadata import PACKAGE_LIBRARY_TYPE, __version__
9
+ from .request_utils import non_blocking_post
10
+ from .thread_local import suppress_network_recording
11
+ from .timeutil import TimeSync
12
+
13
+
14
+ class BaseTransmitter:
15
+ def __init__(self, api_key: str = None):
16
+ self.api_key = api_key or app_config._sailfish_api_key
17
+ self.endpoint = app_config._sailfish_graphql_endpoint
18
+ self.query_type = "mutation"
19
+ self.service_identifier = app_config._service_identifier
20
+ self.git_sha = app_config._git_sha
21
+
22
+ @property
23
+ def query_name(self) -> str:
24
+ return (
25
+ self.operation_name[0].lower() + self.operation_name[1:]
26
+ if self.operation_name
27
+ else ""
28
+ )
29
+
30
+ # TODO - Strip out everything EXCEPT for `reentrancyGuardPreactive`
31
+ def get_default_variables(self):
32
+ timestamp_ms = TimeSync.get_instance().get_utc_time_in_ms()
33
+ return {
34
+ "apiKey": self.api_key,
35
+ "serviceUuid": app_config._service_uuid,
36
+ "timestampMs": str(timestamp_ms),
37
+ }
38
+
39
+ def get_variables(
40
+ self,
41
+ additional_variables: Optional[Dict[str, Any]] = None,
42
+ ) -> Dict[str, Any]:
43
+ additional_variables = (
44
+ additional_variables if additional_variables is not None else {}
45
+ )
46
+ return {
47
+ **additional_variables,
48
+ **self.get_default_variables(),
49
+ }
50
+
51
+
52
+ class ServiceIdentifier(BaseTransmitter):
53
+ def __init__(self, api_key: str = app_config._sailfish_api_key):
54
+ super().__init__(api_key)
55
+ self.operation_name = "IdentifyServiceDetails"
56
+
57
+ def do_send(self, args) -> None:
58
+ if app_config._service_identification_received:
59
+ return
60
+ try:
61
+ threading.Thread(target=self.send, args=args).start()
62
+ except RuntimeError:
63
+ return
64
+
65
+ def send(self):
66
+ """
67
+ Sends the service identification details as a GraphQL mutation.
68
+ This method overrides the `send` method from `DataTransmitter`.
69
+ """
70
+
71
+ query = f"""
72
+ {self.query_type} {self.operation_name}(
73
+ $apiKey: String!,
74
+ $timestampMs: String!,
75
+ $serviceUuid: String!,
76
+ $serviceIdentifier: String,
77
+ $serviceVersion: String,
78
+ $serviceAdditionalMetadata: JSON,
79
+ $library: String!,
80
+ $version: String!,
81
+ $infrastructureType: String,
82
+ $infrastructureDetails: JSON,
83
+ $setupInterceptorsFilePath: String,
84
+ $setupInterceptorsLineNumber: Int
85
+ ) {{
86
+ {self.query_name}(
87
+ apiKey: $apiKey,
88
+ timestampMs: $timestampMs,
89
+ serviceUuid: $serviceUuid,
90
+ serviceIdentifier: $serviceIdentifier,
91
+ serviceVersion: $serviceVersion,
92
+ serviceAdditionalMetadata: $serviceAdditionalMetadata,
93
+ library: $library,
94
+ version: $version,
95
+ infrastructureType: $infrastructureType,
96
+ infrastructureDetails: $infrastructureDetails
97
+ setupInterceptorsFilePath: $setupInterceptorsFilePath,
98
+ setupInterceptorsLineNumber: $setupInterceptorsLineNumber
99
+ )
100
+ }}
101
+ """
102
+
103
+ try:
104
+ if SF_DEBUG:
105
+ print(f"Sending query: {query}", log=False)
106
+
107
+ # Non-blocking POST request to send the GraphQL query
108
+ variables = self.get_variables(
109
+ {
110
+ "serviceIdentifier": app_config._service_identifier,
111
+ "gitSha": app_config._git_sha,
112
+ "serviceVersion": app_config._service_version,
113
+ "serviceAdditionalMetadata": app_config._service_additional_metadata,
114
+ "library": PACKAGE_LIBRARY_TYPE,
115
+ "version": __version__,
116
+ "infrastructureType": app_config._infra_details.system.value, # or whatever string you're passing
117
+ "infrastructureDetails": app_config._infra_details.details,
118
+ "setupInterceptorsFilePath": app_config._setup_interceptors_call_filename,
119
+ "setupInterceptorsLineNumber": app_config._setup_interceptors_call_lineno,
120
+ },
121
+ )
122
+
123
+ future = non_blocking_post(
124
+ self.endpoint, self.operation_name, query, variables
125
+ )
126
+ if future is None:
127
+ return
128
+ response = future.result()
129
+ if SF_DEBUG and response is None:
130
+ print(
131
+ f"IdentifyServiceDetails NOT sent successfully for service: UUID={app_config._service_uuid}",
132
+ log=False,
133
+ )
134
+ return
135
+ service_identification_received = response.get("data", {}).get(
136
+ self.query_name, False
137
+ )
138
+ app_config._service_identification_received = (
139
+ service_identification_received
140
+ )
141
+ if SF_DEBUG:
142
+ print(
143
+ f"IdentifyServiceDetails sent successfully for service: UUID={app_config._service_uuid}; service_identification_received={str(service_identification_received)}",
144
+ log=False,
145
+ )
146
+
147
+ except Exception as e:
148
+ # Log any exceptions that occur during sending
149
+ if SF_DEBUG:
150
+ print(f"Error occurred while sending service identification: {e}")
151
+
152
+
153
+ class DataTransmitter(BaseTransmitter):
154
+ def __init__(self, api_key: str = None):
155
+ self.api_key = api_key or app_config._sailfish_api_key
156
+ self.endpoint = app_config._sailfish_graphql_endpoint
157
+ self.operation_name: Optional[str] = ""
158
+ self.query_type = "mutation"
159
+ self.service_identifier = ServiceIdentifier()
160
+
161
+ def check_if_contents_should_be_ignored(
162
+ self, contents
163
+ ): # pylint: disable=unused-argument
164
+ return False
165
+
166
+ def _send_app_identifier(self) -> None:
167
+ if SF_DEBUG:
168
+ print(
169
+ "_send_app_identifier...SENDING DATA...args=",
170
+ set(),
171
+ log=False,
172
+ )
173
+ self.service_identifier.do_send(set())
174
+
175
+ def do_send(self, args) -> None:
176
+ self._send_app_identifier()
177
+ try:
178
+ threading.Thread(target=self.send, args=args).start()
179
+ except RuntimeError:
180
+ return
181
+
182
+ def send(self, contents, session_id: str):
183
+ if self.check_if_contents_should_be_ignored(contents):
184
+ return
185
+ query = f"""
186
+ {self.query_type} {self.operation_name}($apiKey: String!, $serviceUuid: String!, $contents: String!, $library: String!, $timestampMs: String!, $version: String!) {{
187
+ {self.query_name}(apiKey: $apiKey, serviceUuid: $serviceUuid, contents: $contents, library: $library, timestampMs: $timestampMs, version: $version)
188
+ }}
189
+ """
190
+
191
+ non_blocking_post(
192
+ self.endpoint,
193
+ self.operation_name,
194
+ query,
195
+ self.get_variables({"contents": contents}),
196
+ )
197
+
198
+
199
+ class DomainsToNotPassHeaderToTransmitter(DataTransmitter):
200
+ def __init__(self, api_key: str = app_config._sailfish_api_key):
201
+ super().__init__(api_key)
202
+ self.operation_name = "DomainsToNotPassHeaderTo"
203
+
204
+ def send(
205
+ self,
206
+ domains: List[str],
207
+ ):
208
+ query = f"""
209
+ {self.query_type} {self.operation_name}($apiKey: String!, $serviceUuid: String!, $timestampMs: String!, $domains: [String!]!) {{
210
+ {self.query_name}(apiKey: $apiKey, serviceUuid: $serviceUuid, timestampMs: $timestampMs, domains: $domains)
211
+ }}
212
+ """
213
+ variables = self.get_variables(
214
+ {
215
+ "domains": domains,
216
+ },
217
+ )
218
+
219
+ non_blocking_post(self.endpoint, self.operation_name, query, variables)
220
+
221
+
222
+ class UpdateServiceIdentifierMetadata(DataTransmitter):
223
+ def __init__(self, api_key: str = app_config._sailfish_api_key):
224
+ super().__init__(api_key)
225
+ self.operation_name = "UpdateServiceDetails"
226
+
227
+ def send(
228
+ self,
229
+ domains: List[str],
230
+ ):
231
+ query = f"""
232
+ {self.query_type} {self.operation_name}($apiKey: String!, $serviceUuid: String!, $domains: [String!]!) {{
233
+ {self.query_name}(apiKey: $apiKey, serviceUuid: $serviceUuid, domains: $domains)
234
+ }}
235
+ """
236
+ variables = self.get_variables(
237
+ {
238
+ "domains": domains,
239
+ },
240
+ )
241
+
242
+ non_blocking_post(self.endpoint, self.operation_name, query, variables)
243
+
244
+
245
+ class NetworkHopsTransmitter(DataTransmitter):
246
+ """
247
+ A transmitter class responsible for sending network hop data as a GraphQL mutation.
248
+
249
+ This class extends `DataTransmitter` and sends `collectNetworkHops` mutation requests
250
+ to log network hop details for a given session.
251
+
252
+ Attributes:
253
+ operation_name (str): The GraphQL mutation name ("collectNetworkHops").
254
+
255
+ Methods:
256
+ send(session_id: str, line: str, column: str, name: str, entrypoint: str):
257
+ Sends a non-blocking GraphQL mutation request to log network hops.
258
+ """
259
+
260
+ def __init__(self, api_key: str = app_config._sailfish_api_key):
261
+ super().__init__(api_key)
262
+ self.operation_name = "collectNetworkHops"
263
+
264
+ def send(
265
+ self,
266
+ session_id: str,
267
+ line: str,
268
+ column: str,
269
+ name: str,
270
+ entrypoint: str,
271
+ ):
272
+ query = f"""
273
+ {self.query_type} {self.operation_name}(
274
+ $apiKey: String!,
275
+ $sessionId: String!,
276
+ $timestampMs: String!,
277
+ $line: String!,
278
+ $column: String!,
279
+ $name: String!,
280
+ $entrypoint: String!,
281
+ $serviceUuid: String
282
+ ) {{
283
+ {self.query_name}(
284
+ apiKey: $apiKey,
285
+ sessionId: $sessionId,
286
+ timestampMs: $timestampMs,
287
+ line: $line,
288
+ column: $column,
289
+ name: $name,
290
+ entrypoint: $entrypoint,
291
+ serviceUuid: $serviceUuid
292
+ )
293
+ }}
294
+ """
295
+
296
+ variables = self.get_variables(
297
+ {
298
+ "sessionId": session_id,
299
+ "line": line,
300
+ "column": column,
301
+ "name": name,
302
+ "entrypoint": entrypoint,
303
+ "serviceUuid": app_config._service_uuid,
304
+ }
305
+ )
306
+ if SF_DEBUG:
307
+ print("[[NetworkHopsTransmitter.send]] variables=", variables, log=False)
308
+ non_blocking_post(self.endpoint, self.operation_name, query, variables)
309
+
310
+
311
+ class NetworkRequestTransmitter(DataTransmitter):
312
+ def __init__(self, api_key: str = None):
313
+ super().__init__(api_key)
314
+ self.operation_name = "collectNetworkRequest"
315
+
316
+ def send(
317
+ self,
318
+ request_id: str,
319
+ page_visit_id: Optional[str],
320
+ recording_session_id: str,
321
+ service_uuid: str,
322
+ timestamp_start: int,
323
+ timestamp_end: int,
324
+ response_code: int,
325
+ success: bool,
326
+ error: Optional[str],
327
+ url: str,
328
+ method: str,
329
+ ):
330
+ # build the mutation to match the new input type:
331
+ query = f"""
332
+ {self.query_type} {self.operation_name}($data: NetworkRequestInput!) {{
333
+ {self.query_name}(data: $data)
334
+ }}
335
+ """
336
+
337
+ # Only include fields expected by the NetworkRequestInput type
338
+ variables = {
339
+ "data": {
340
+ "apiKey": self.api_key,
341
+ "requestId": request_id,
342
+ "pageVisitId": page_visit_id,
343
+ "recordingSessionId": recording_session_id,
344
+ "serviceUuid": app_config._service_uuid,
345
+ "timestampStart": timestamp_start,
346
+ "timestampEnd": timestamp_end,
347
+ "responseCode": response_code,
348
+ "success": success,
349
+ "error": error,
350
+ "url": url,
351
+ "method": method,
352
+ }
353
+ }
354
+
355
+ if SF_DEBUG:
356
+ print(f"[NetworkRequestTransmitter] variables={variables}", log=False)
357
+
358
+ non_blocking_post(self.endpoint, self.operation_name, query, variables)