diff --git a/content/response_integrations/google/azure_monitor/.python-version b/content/response_integrations/google/azure_monitor/.python-version new file mode 100644 index 0000000000..902b2c90c8 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/.python-version @@ -0,0 +1 @@ +3.11 \ No newline at end of file diff --git a/content/response_integrations/google/azure_monitor/__init__.py b/content/response_integrations/google/azure_monitor/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/actions/__init__.py b/content/response_integrations/google/azure_monitor/actions/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/actions/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/actions/ping.py b/content/response_integrations/google/azure_monitor/actions/ping.py new file mode 100644 index 0000000000..00a47eb919 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/actions/ping.py @@ -0,0 +1,48 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from azure_monitor.core.base_action import BaseAction +from azure_monitor.core.constants import PING_SCRIPT_NAME + +if TYPE_CHECKING: + from typing import NoReturn + + +SUCCESS_MESSAGE: str = ( + "Successfully connected to the Azure Monitor server with the provided " + "connection parameters!" +) +ERROR_MESSAGE: str = "Failed to connect to the Azure Monitor server!" + + +class Ping(BaseAction): + def __init__(self) -> None: + super().__init__(PING_SCRIPT_NAME) + self.output_message: str = SUCCESS_MESSAGE + self.error_output_message: str = ERROR_MESSAGE + + def _perform_action(self, _=None) -> None: + self.api_client.test_connectivity() + + +def main() -> NoReturn: + Ping().run() + + +if __name__ == "__main__": + main() diff --git a/content/response_integrations/google/azure_monitor/actions/ping.yaml b/content/response_integrations/google/azure_monitor/actions/ping.yaml new file mode 100644 index 0000000000..63239a14b4 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/actions/ping.yaml @@ -0,0 +1,20 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Ping +description: Use the Ping action to test the connectivity to Azure Monitor. +integration_identifier: AzureMonitor +parameters: [] +dynamic_results_metadata: [] +creator: admin diff --git a/content/response_integrations/google/azure_monitor/actions/search_logs.py b/content/response_integrations/google/azure_monitor/actions/search_logs.py new file mode 100644 index 0000000000..680406321e --- /dev/null +++ b/content/response_integrations/google/azure_monitor/actions/search_logs.py @@ -0,0 +1,190 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from datetime import datetime, timezone +from dateutil.parser import parse as isoparse + +from TIPCommon.extraction import extract_action_param +from TIPCommon.validation import ParameterValidator + +from azure_monitor.core.base_action import BaseAction +from azure_monitor.core.constants import ( + DEFAULT_MIN_ROWS, + DEFAULT_RESULTS_TO_RETURN, + DEFAULT_TIME_FRAME, + MAX_RESULTS_LIMIT, + SEARCH_LOGS_SCRIPT_NAME, + TimeFrameDDLEnum, +) +from azure_monitor.core.exceptions import AzureMonitorErrorInvalidParameterError + +if TYPE_CHECKING: + from typing import NoReturn + + from TIPCommon.types import SingleJson + + from azure_monitor.core.data_models import AzureLogEntry + + +SUCCESS_MESSAGE: str = ( + 'Successfully returned results for the query "{query}" in Azure Monitor.' +) +NO_RESULTS_MESSAGE: str = ( + 'No results were found for the query "{query}" in Azure Monitor.' +) + + +class SearchLogsAction(BaseAction): + def __init__(self) -> None: + super().__init__(SEARCH_LOGS_SCRIPT_NAME) + + def _extract_action_parameters(self) -> None: + self.params.workspace_id = extract_action_param( + self.soar_action, + param_name="Workspace ID", + print_value=True, + ) + self.params.query = extract_action_param( + self.soar_action, + param_name="Query", + is_mandatory=True, + print_value=True, + ) + self.params.time_frame = extract_action_param( + self.soar_action, + param_name="Time Frame", + default_value=DEFAULT_TIME_FRAME, + print_value=True, + ) + self.params.start_time = extract_action_param( + self.soar_action, + param_name="Start Time", + print_value=True, + ) + self.params.end_time = extract_action_param( + self.soar_action, + param_name="End Time", + print_value=True, + ) + self.params.max_results_to_return = extract_action_param( + self.soar_action, + param_name="Max Results To Return", + is_mandatory=True, + input_type=int, + default_value=DEFAULT_RESULTS_TO_RETURN, + print_value=True, + ) + + def _validate_params(self) -> None: + validator: ParameterValidator = ParameterValidator(self.soar_action) + self._validate_time_params(validator) + self._validate_max_results_param(validator) + + def _validate_time_params(self, validator: ParameterValidator) -> None: + """ + Validate the provided time_frame, start_time, end_time parameters + & sets ISO8601 strings directly for API usage. + + Sets: + self.params.start_time: str (ISO 8601) + self.params.end_time: str (ISO 8601) + """ + + def _validate_iso8601(value: str, param_name: str) -> None: + """Validate if given value is ISO 8601 datetime string.""" + try: + isoparse(value) + + except (ValueError, TypeError) as error: + raise AzureMonitorErrorInvalidParameterError( + f"'{param_name}' must be a valid ISO 8601 datetime string " + f"(e.g., '2025-10-29T10:15:00Z'). Provided: '{value}'" + ) from error + + self.params.time_frame = validator.validate_ddl( + param_name="Time Frame", + value=self.params.time_frame, + ddl_values=TimeFrameDDLEnum.values(), + print_value=True, + ) + time_frame = TimeFrameDDLEnum(self.params.time_frame) + + if time_frame != TimeFrameDDLEnum.CUSTOM: + self.params.start_time = time_frame.to_start_time_iso() + self.params.end_time = ( + datetime.now(timezone.utc) + .isoformat(timespec="milliseconds") + .replace("+00:00", "Z") + ) + + if self.params.start_time or self.params.end_time: + self.logger.warn( + f"Time Frame is set to '{time_frame.value}'. Ignoring any " + "'Start Time' or 'End Time' parameters provided by the user." + ) + + else: + if not self.params.start_time: + raise AzureMonitorErrorInvalidParameterError( + "'Start Time' must be provided if 'Time Frame' is set to 'Custom'." + ) + _validate_iso8601(self.params.start_time, "Start Time") + + if self.params.end_time: + _validate_iso8601(self.params.end_time, "End Time") + + self.params.end_time = self.params.end_time or datetime.now( + timezone.utc + ).isoformat(timespec="milliseconds").replace("+00:00", "Z") + + self.logger.info(f"Using start_time {self.params.start_time}") + self.logger.info(f"Using end_time {self.params.end_time}") + + def _validate_max_results_param(self, validator: ParameterValidator) -> None: + self.params.max_results_to_return = validator.validate_range( + param_name="Max Results To Return", + value=self.params.max_results_to_return, + min_limit=DEFAULT_MIN_ROWS, + max_limit=MAX_RESULTS_LIMIT, + print_value=True, + ) + + def _perform_action(self, _=None): + search_logs: list[AzureLogEntry] = self.api_client.search_logs( + query=self.params.query, + start_time=self.params.start_time, + end_time=self.params.end_time, + max_rows=self.params.max_results_to_return, + workspace_id=self.params.workspace_id, + ) + if not search_logs: + self.output_message = NO_RESULTS_MESSAGE.format(query=self.params.query) + return + + self.output_message: str = SUCCESS_MESSAGE.format(query=self.params.query) + self.json_results: list[SingleJson] = [ + search_log.to_json() for search_log in search_logs + ] + + +def main() -> NoReturn: + SearchLogsAction().run() + + +if __name__ == "__main__": + main() diff --git a/content/response_integrations/google/azure_monitor/actions/search_logs.yaml b/content/response_integrations/google/azure_monitor/actions/search_logs.yaml new file mode 100644 index 0000000000..69653cb3e9 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/actions/search_logs.yaml @@ -0,0 +1,66 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +name: Search Logs +description: Use the Search Logs action to search logs based on the provided query + in Azure Monitor. +integration_identifier: AzureMonitor +parameters: +- name: Workspace ID + default_value: '' + type: string + description: ID of the workspace that needs to be searched. If nothing is provided, + action will take the Workspace ID provided in the integration configuration. + is_mandatory: false +- name: Query + default_value: '' + type: string + description: Query that needs to be executed. + is_mandatory: true +- name: Time Frame + default_value: Last Hour + type: ddl + optional_values: + - Last Hour + - Last 6 Hours + - Last 24 Hours + - Last Week + - Last Month + - Custom + description: Time frame for the query. If "Custom" is selected, you also need + to provide "Start Time". + is_mandatory: false +- name: Start Time + default_value: '' + type: string + description: 'Start time for the query. This parameter is mandatory, if "Custom" + is selected for the "Time Frame" parameter. Format: ISO 8601.' + is_mandatory: false +- name: End Time + default_value: '' + type: string + description: 'End time for the query. Format: ISO 8601. If nothing is provided + and "Custom" is selected for the "Time Frame" parameter then this parameter + will use current time.' + is_mandatory: false +- name: Max Results To Return + default_value: 100 + type: string + description: 'How many results should be returned from the search. Maximum: 1000.' + is_mandatory: true +dynamic_results_metadata: +- result_example_path: resources/search_logs_JsonResult_example.json + result_name: JsonResult + show_result: true +creator: admin diff --git a/content/response_integrations/google/azure_monitor/core/__init__.py b/content/response_integrations/google/azure_monitor/core/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/core/api_client.py b/content/response_integrations/google/azure_monitor/core/api_client.py new file mode 100644 index 0000000000..100590daf5 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/api_client.py @@ -0,0 +1,118 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from datetime import datetime, timedelta, timezone +from typing import TYPE_CHECKING, NamedTuple + +from TIPCommon.base.interfaces import Apiable + +from azure_monitor.core.api_utils import get_full_url, validate_response +from azure_monitor.core.constants import DEFAULT_MIN_ROWS, DEFAULT_PING_LOGS_QUERY +from azure_monitor.core.data_parser import parse_azure_monitor_response + +if TYPE_CHECKING: + from requests import Response + + from TIPCommon.base.interfaces.logger import ScriptLogger + from TIPCommon.types import SingleJson + + from azure_monitor.core.auth import AuthenticatedSession + from azure_monitor.core.data_models import AzureLogEntry + + +class ApiParameters(NamedTuple): + api_root: str + workspace_id: str + + +class AzureMonitorApiClient(Apiable): + def __init__( + self, + authenticated_session: AuthenticatedSession, + configuration: ApiParameters, + logger: ScriptLogger, + ) -> None: + super().__init__( + authenticated_session=authenticated_session, + configuration=configuration, + ) + self.logger: ScriptLogger = logger + self.api_root: str = configuration.api_root + self.workspace_id: str = configuration.workspace_id + + def test_connectivity(self) -> None: + """Test connectivity to API.""" + url: str = get_full_url( + self.api_root, + endpoint_id="ping", + workspace_id=self.workspace_id, + ) + end_time = datetime.now(timezone.utc) + start_time = end_time - timedelta(hours=1) + time_span = ( + f"{start_time.isoformat(timespec='milliseconds')}/" + f"{end_time.isoformat(timespec='milliseconds')}" + ) + payload: dict[str, str] = { + "query": DEFAULT_PING_LOGS_QUERY, + "maxRows": DEFAULT_MIN_ROWS, + "timespan": time_span, + } + + response: Response = self.session.post( + url, + json=payload, + ) + validate_response(response) + + def search_logs( + self, + query: str, + start_time: str, + end_time: str, + max_rows: int, + workspace_id: str | None = None, + ) -> list[AzureLogEntry]: + """Search logs in Azure Monitor. + Args: + query (str): The query to execute. + start_time (str): The start time for the query in ISO 8601 format. + end_time (str): The end time for the query in ISO 8601 format. + max_rows (int): The maximum number of rows to return. + workspace_id (str | None): The workspace ID to use. If None, uses the + default. + + Returns: + list[AzureLogEntry]: The list of AzureLogEntry objects. + """ + workspace_id: str = workspace_id or self.workspace_id + + url: str = get_full_url( + self.api_root, + endpoint_id="search_logs", + workspace_id=workspace_id, + ) + time_span: str = f"{start_time}/{end_time}" + payload: dict[str, str | int] = { + "query": query, + "maxRows": max_rows, + "timespan": time_span, + } + + response: Response = self.session.post(url, json=payload) + validate_response(response) + + return parse_azure_monitor_response(response.json()) diff --git a/content/response_integrations/google/azure_monitor/core/api_utils.py b/content/response_integrations/google/azure_monitor/core/api_utils.py new file mode 100644 index 0000000000..1ead37440e --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/api_utils.py @@ -0,0 +1,97 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import json +from urllib.parse import urljoin + +import requests + +from azure_monitor.core.constants import ENDPOINTS +from azure_monitor.core.exceptions import ( + AzureMonitorHTTPError, + InvalidCredsError, + InvalidRequestParametersError, +) + + +def get_full_url( + api_root: str, + endpoint_id: str, + endpoints: dict[str, str] = None, + **kwargs, +) -> str: + """Construct the full URL using a URL identifier and optional variables + + Args: + api_root (str): The root of the API endpoint + endpoint_id (str): The identifier for the specific URL + endpoints (dict[str, str]): endpoints dictionary object + kwargs (dict): Variables passed for string formatting + + Returns: + str: The full URL constructed from API root, endpoint identifier and variables + + """ + endpoints = endpoints or ENDPOINTS + return urljoin(api_root, endpoints[endpoint_id].format(**kwargs)) + + +def validate_response( + response: requests.Response, + error_msg: str = "An error occurred", +) -> None: + """ + Validate an HTTP response and raise custom exceptions with detailed messages. + + Args: + response (requests.Response): The HTTP response to validate. + error_msg (str): Default message prefix to include in raised errors. + + Raises: + InvalidRequestParametersError: For 400, 403, or 404 HTTP status codes. + AzureMonitorHTTPError: For all other HTTP errors. + """ + try: + response.raise_for_status() + return + + except requests.HTTPError as error: + status = response.status_code + + try: + error_json = response.json() + error_info = error_json.get("error", {}) + inner_error = error_info.get("innererror", {}) + + message = ( + inner_error.get("innererror", {}).get("message") + or inner_error.get("message") + or error_info.get("message") + or response.text + or "Unknown error" + ) + except (json.JSONDecodeError, KeyError, AttributeError): + message = response.text or "Unknown error" + + if "error_description" in error_json: + raise InvalidCredsError("Please Check your Credentials.") from error + + if status in (400, 403, 404): + raise InvalidRequestParametersError(message) from error + + raise AzureMonitorHTTPError( + f"{error_msg}: {message} (Status code: {status})" + ) from error diff --git a/content/response_integrations/google/azure_monitor/core/auth.py b/content/response_integrations/google/azure_monitor/core/auth.py new file mode 100644 index 0000000000..139e1057e4 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/auth.py @@ -0,0 +1,214 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import copy +import dataclasses +from typing import TYPE_CHECKING + +from soar_sdk.SiemplifyAction import SiemplifyAction +from soar_sdk.SiemplifyConnectors import SiemplifyConnectorExecution +from soar_sdk.SiemplifyJob import SiemplifyJob + +from TIPCommon.base.interfaces import Authable +from TIPCommon.base.utils import CreateSession +from TIPCommon.extraction import extract_script_param +from azure_monitor.core import api_utils +from azure_monitor.core.constants import ( + DEFAULT_API_ROOT, + DEFAULT_LOGIN_API_ROOT, + DEFAULT_VERIFY_SSL, + INTEGRATION_IDENTIFIER, + TOKEN_PAYLOAD_FROM_SECRET, +) +from azure_monitor.core.data_models import IntegrationParameters +from azure_monitor.core.exceptions import AzureMonitorError + +if TYPE_CHECKING: + from requests import Session + + from TIPCommon.types import ChronicleSOAR + + +@dataclasses.dataclass(slots=True) +class SessionAuthenticationParameters: + login_api_root: str + api_root: str + tenant_id: str + client_id: str + client_secret: str + verify_ssl: bool + + +def build_auth_params(soar_sdk_object: ChronicleSOAR) -> IntegrationParameters: + """Extract auth params for Auth manager + + Args: + soar_sdk_object: ChronicleSOAR SDK object + + Returns: + SessionAuthenticationParameters: SessionAuthenticationParameters object. + + """ + sdk_class = type(soar_sdk_object).__name__ + if sdk_class == SiemplifyAction.__name__: + input_dictionary = soar_sdk_object.get_configuration(INTEGRATION_IDENTIFIER) + elif sdk_class in ( + SiemplifyConnectorExecution.__name__, + SiemplifyJob.__name__, + ): + input_dictionary = soar_sdk_object.parameters + else: + raise AzureMonitorError( + f"Provided SOAR instance is not supported! type: {sdk_class}.", + ) + + login_api_root = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Login API Root", + default_value=DEFAULT_LOGIN_API_ROOT, + is_mandatory=True, + print_value=True, + ) + api_root = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="API Root", + default_value=DEFAULT_API_ROOT, + is_mandatory=True, + print_value=True, + ) + tenant_id = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Tenant ID", + is_mandatory=True, + print_value=True, + ) + client_id = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Client ID", + is_mandatory=True, + print_value=True, + ) + client_secret = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Client Secret", + is_mandatory=True, + ) + workspace_id = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Workspace ID", + is_mandatory=True, + print_value=True, + ) + verify_ssl = extract_script_param( + soar_sdk_object, + input_dictionary=input_dictionary, + param_name="Verify SSL", + default_value=DEFAULT_VERIFY_SSL, + input_type=bool, + is_mandatory=True, + print_value=True, + ) + + return IntegrationParameters( + login_api_root=login_api_root, + api_root=api_root, + tenant_id=tenant_id, + client_id=client_id, + client_secret=client_secret, + workspace_id=workspace_id, + verify_ssl=verify_ssl, + ) + + +class AuthenticatedSession(Authable): + def authenticate_session(self, params: SessionAuthenticationParameters) -> None: + self.session = get_authenticated_session(params) + + +def get_authenticated_session( + session_parameters: SessionAuthenticationParameters, +) -> Session: + """Returns a requests Session object authenticated with a Bearer token. + Args: + session_parameters (SessionAuthenticationParameters): The authentication + parameters. + + Returns: + Session: The authenticated requests Session object. + """ + session: Session = CreateSession.create_session() + _authenticate_session(session, session_parameters=session_parameters) + return session + + +def _authenticate_session( + session: Session, + session_parameters: SessionAuthenticationParameters, +) -> None: + """Perform OAuth2 Client Credentials authentication to obtain and attach an access + token. + Args: + session (Session): The requests Session object to authenticate. + session_parameters (SessionAuthenticationParameters): The authentication + parameters. + """ + session.verify = session_parameters.verify_ssl + access_token = generate_tokens(session, session_parameters) + + session.headers.update({"Authorization": f"Bearer {access_token}"}) + + +def generate_tokens( + session: Session, + session_parameters: SessionAuthenticationParameters, +) -> str: + """Generate access token using client credentials flow. + + Args: + session (Session): The requests session to use for the token request. + session_parameters (SessionAuthenticationParameters): The authentication + parameters. + + Returns: + str: The access token. + """ + payload = copy.deepcopy(TOKEN_PAYLOAD_FROM_SECRET) + payload.update( + { + "client_id": session_parameters.client_id, + "client_secret": session_parameters.client_secret, + "resource": session_parameters.api_root, + } + ) + token_url = api_utils.get_full_url( + api_root=session_parameters.login_api_root, + endpoint_id="bearer_token_url", + tenant_id=session_parameters.tenant_id, + ) + + response = session.post(token_url, data=payload) + api_utils.validate_response(response) + + token_info = response.json() + access_token = token_info.get("access_token") + + return access_token diff --git a/content/response_integrations/google/azure_monitor/core/base_action.py b/content/response_integrations/google/azure_monitor/core/base_action.py new file mode 100644 index 0000000000..5000928cc5 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/base_action.py @@ -0,0 +1,68 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from abc import ABC +from typing import TYPE_CHECKING + +from TIPCommon.base.action import Action + +from azure_monitor.core.api_client import ApiParameters, AzureMonitorApiClient +from azure_monitor.core.auth import ( + AuthenticatedSession, + build_auth_params, + SessionAuthenticationParameters, +) + +if TYPE_CHECKING: + import requests + + +class BaseAction(Action, ABC): + """Base action class.""" + + def _init_api_clients(self) -> AzureMonitorApiClient: + """Prepare API client""" + auth_params = build_auth_params(self.soar_action) + authenticator: AuthenticatedSession = AuthenticatedSession() + auth_params_for_session = SessionAuthenticationParameters( + login_api_root=auth_params.login_api_root, + api_root=auth_params.api_root, + tenant_id=auth_params.tenant_id, + client_id=auth_params.client_id, + client_secret=auth_params.client_secret, + verify_ssl=auth_params.verify_ssl, + ) + authenticator.authenticate_session(auth_params_for_session) + authenticated_session: requests.Session = authenticator.session + + api_params: ApiParameters = ApiParameters( + api_root=auth_params.api_root, + workspace_id=auth_params.workspace_id, + ) + + return AzureMonitorApiClient( + authenticated_session=authenticated_session, + configuration=api_params, + logger=self.logger, + ) + + @property + def result_value(self) -> bool: + return self._result_value + + @result_value.setter + def result_value(self, value: bool) -> None: + self._result_value = value diff --git a/content/response_integrations/google/azure_monitor/core/constants.py b/content/response_integrations/google/azure_monitor/core/constants.py new file mode 100644 index 0000000000..b8b319e8d2 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/constants.py @@ -0,0 +1,104 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from datetime import datetime, timedelta, timezone +from enum import Enum +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from collections.abc import Mapping + + +INTEGRATION_IDENTIFIER: str = "AzureMonitor" +INTEGRATION_DISPLAY_NAME: str = "Azure Monitor" + +PING_SCRIPT_NAME: str = f"{INTEGRATION_IDENTIFIER} - Ping" +SEARCH_LOGS_SCRIPT_NAME: str = f"{INTEGRATION_IDENTIFIER} - Search Logs" + + +DEFAULT_LOGIN_API_ROOT: str = "https://login.microsoftonline.com" +DEFAULT_API_ROOT: str = "https://api.loganalytics.io" +DEFAULT_VERIFY_SSL: bool = True + +GRANT_TYPE: str = "client_credentials" +TOKEN_PAYLOAD_FROM_SECRET: Mapping[str, str] = { + "grant_type": GRANT_TYPE, + "client_id": "", + "client_secret": "", + "resource": "", +} + + +ENDPOINTS: Mapping[str, str] = { + "bearer_token_url": "{tenant_id}/oauth2/token", + "ping": "/v1/workspaces/{workspace_id}/query", + "search_logs": "/v1/workspaces/{workspace_id}/query", +} + +DEFAULT_PING_LOGS_QUERY: str = "AzureActivity" +DEFAULT_MIN_ROWS: int = 1 +DEFAULT_TIME_FRAME: str = "Last Hour" +DEFAULT_RESULTS_TO_RETURN: int = 100 +MAX_RESULTS_LIMIT: int = 1000 + + +class DDLEnum(Enum): + @classmethod + def values(cls) -> list[str]: + return [item.value for item in cls] + + +class TimeFrameDDLEnum(DDLEnum): + LAST_HOUR = "Last Hour" + LAST_6_HOURS = "Last 6 Hours" + LAST_24_HOURS = "Last 24 Hours" + LAST_WEEK = "Last Week" + LAST_MONTH = "Last Month" + CUSTOM = "Custom" + + def to_start_time_iso(self) -> datetime.date: + """ + Converts the selected time frame enum into an ISO 8601 formatted UTC start time + string. + + This method calculates the start time corresponding to the selected + `TimeFrameDDLEnum` value (e.g., last hour, last 6 hours, last week, etc.) + relative to the current UTC time, and returns it as an ISO 8601 string + with millisecond precision and a 'Z' suffix. + + Raises: + ValueError: If the enum value is not supported. + + Returns: + str: The calculated start time in ISO 8601 format with milliseconds and + UTC indicator. Example: '2025-10-30T08:42:15.123Z' + """ + now = datetime.now(timezone.utc) + match self: + case TimeFrameDDLEnum.LAST_HOUR: + start_time = now - timedelta(hours=1) + case TimeFrameDDLEnum.LAST_6_HOURS: + start_time = now - timedelta(hours=6) + case TimeFrameDDLEnum.LAST_24_HOURS: + start_time = now - timedelta(hours=24) + case TimeFrameDDLEnum.LAST_WEEK: + start_time = now - timedelta(days=7) + case TimeFrameDDLEnum.LAST_MONTH: + start_time = now - timedelta(days=30) + case _: + raise ValueError(f"Unsupported timeframe: {self}") + + return start_time.isoformat(timespec="milliseconds").replace("+00:00", "Z") diff --git a/content/response_integrations/google/azure_monitor/core/data_models.py b/content/response_integrations/google/azure_monitor/core/data_models.py new file mode 100644 index 0000000000..29a92a40eb --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/data_models.py @@ -0,0 +1,95 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +import re +from dataclasses import dataclass, field, fields, make_dataclass +from typing import Any, TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Type, Self + + from TIPCommon.types import SingleJson + + +@dataclass(slots=True) +class IntegrationParameters: + login_api_root: str + api_root: str + tenant_id: str + client_id: str + client_secret: str + workspace_id: str + verify_ssl: bool + + +def to_snake_case(name: str) -> str: + """Convert PascalCase or camelCase to snake_case.""" + name = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", name) + return name.lower() + + +@dataclass(slots=True) +class AzureLogEntry: + """Dynamic model for a single row from Azure Monitor logs.""" + + data: SingleJson = field(default_factory=dict) + + @classmethod + def from_json(cls, table_json: SingleJson) -> list[Self]: + """Create list of AzureLogEntry (with dynamic fields) from JSON response. + + Args: + table_json (SingleJson): JSON response from Azure Monitor logs. + + Returns: + list[Self]: List of AzureLogEntry objects. + """ + entries: list[Self] = [] + + for table in table_json.get("tables", []): + columns = [col["name"] for col in table.get("columns", [])] + snake_columns = [to_snake_case(col) for col in columns] + rows = table.get("rows", []) + + dynamic_entry = make_dataclass( + "DynamicAzureLogEntry", + [(col, Any, field(default=None)) for col in snake_columns], + bases=(cls,), + slots=True, + ) + + for row in rows: + data = dict(zip(snake_columns, row)) + entries.append(dynamic_entry(**data)) + + return entries + + def to_json(self) -> SingleJson: + """Convert AzureLogEntry (including dynamic subclass) to JSON. + + Returns: + SingleJson: JSON representation of AzureLogEntry. + """ + result: SingleJson = {} + for f in fields(self): + if f.name == "data": + continue + + value = getattr(self, f.name) + pascal_name = "".join(part.capitalize() for part in f.name.split("_")) + result[pascal_name] = value + + return result diff --git a/content/response_integrations/google/azure_monitor/core/data_parser.py b/content/response_integrations/google/azure_monitor/core/data_parser.py new file mode 100644 index 0000000000..ae34f6f56d --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/data_parser.py @@ -0,0 +1,33 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from typing import TYPE_CHECKING + +from azure_monitor.core.data_models import AzureLogEntry + +if TYPE_CHECKING: + from TIPCommon.types import SingleJson + + +def parse_azure_monitor_response(response_json: SingleJson) -> list[AzureLogEntry]: + """Parse Azure Monitor API response into list of JSON entries. + Args: + response_json (dict): Raw response from Azure Monitor API. + + Returns: + list[AzureLogEntry]: Transformed list of entries. + """ + return list(AzureLogEntry.from_json(response_json)) diff --git a/content/response_integrations/google/azure_monitor/core/exceptions.py b/content/response_integrations/google/azure_monitor/core/exceptions.py new file mode 100644 index 0000000000..6aef34b2ab --- /dev/null +++ b/content/response_integrations/google/azure_monitor/core/exceptions.py @@ -0,0 +1,37 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +class AzureMonitorError(Exception): + """General exception for Azure Monitor.""" + + +class AzureMonitorErrorInvalidParameterError(AzureMonitorError): + """Invalid Parameter error.""" + + +class AzureMonitorHTTPError(AzureMonitorError): + """Exception in case of HTTP error.""" + + def __init__(self, message, *args, status_code=None) -> None: + super().__init__(message, *args) + self.status_code = status_code + + +class InvalidRequestParametersError(AzureMonitorError): + """Invalid HTTP Requests Parameters Error.""" + + +class InvalidCredsError(AzureMonitorError): + """Invalid Credentials Error.""" diff --git a/content/response_integrations/google/azure_monitor/definition.yaml b/content/response_integrations/google/azure_monitor/definition.yaml new file mode 100644 index 0000000000..4f634d2f58 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/definition.yaml @@ -0,0 +1,67 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +identifier: AzureMonitor +name: Azure Monitor +parameters: +- name: Login API Root + default_value: https://login.microsoftonline.com + type: string + description: The login API root of the Azure Monitor service. + is_mandatory: true + integration_identifier: AzureMonitor +- name: API Root + default_value: https://api.loganalytics.io + type: string + description: The API root of the Azure Monitor service. + is_mandatory: true + integration_identifier: AzureMonitor +- name: Tenant ID + default_value: '' + type: string + description: The Azure Monitor account tenant ID. + is_mandatory: true + integration_identifier: AzureMonitor +- name: Client ID + default_value: '' + type: string + description: The Azure Monitor account Client ID. + is_mandatory: true + integration_identifier: AzureMonitor +- name: Client Secret + default_value: '' + type: password + description: The Azure Monitor account Client Secret. + is_mandatory: true + integration_identifier: AzureMonitor +- name: Workspace ID + default_value: '' + type: string + description: The Azure Monitor account Workspace ID. + is_mandatory: false + integration_identifier: AzureMonitor +- name: Verify SSL + default_value: true + type: boolean + description: If selected, the integration validates the SSL certificate when connecting + to the Azure Monitor server. Enabled by default. + is_mandatory: false + integration_identifier: AzureMonitor +documentation_link: https://docs.cloud.google.com/chronicle/docs/soar/marketplace-integrations/azure-monitor +categories: +- IT & Infrastructure +- Azure +- Cloud +svg_logo_path: resources/logo.svg +image_path: resources/image.png diff --git a/content/response_integrations/google/azure_monitor/main.py b/content/response_integrations/google/azure_monitor/main.py new file mode 100644 index 0000000000..ed3e72f84c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/main.py @@ -0,0 +1,20 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +def main(): + print("Hello from azure-monitor!") + + +if __name__ == "__main__": + main() diff --git a/content/response_integrations/google/azure_monitor/pyproject.toml b/content/response_integrations/google/azure_monitor/pyproject.toml new file mode 100644 index 0000000000..98b4b80761 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/pyproject.toml @@ -0,0 +1,50 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +[project] +name = "AzureMonitor" +version = "6.0" +description = "Azure Monitor is a comprehensive monitoring solution for collecting, analyzing, and responding to monitoring data from your cloud and on-premises environments." +requires-python = ">=3.11,<3.12" +dependencies = [ + "environmentcommon", + "python-dateutil>=2.9.0.post0", + "requests==2.32.5", + "tipcommon", +] + +[dependency-groups] +dev = [ + "integration-testing", + "pytest>=9.1.1", + "pytest-json-report>=1.5.0", + "soar-sdk", +] + +[tool.uv] +[[tool.uv.index]] +url = "https://pypi.org/simple" +default = true + +[tool.uv.sources.environmentcommon] +path = "../../../../packages/envcommon/whls/EnvironmentCommon-1.0.2-py2.py3-none-any.whl" + +[tool.uv.sources.tipcommon] +path = "../../../../packages/tipcommon/whls/TIPCommon-2.2.12-py2.py3-none-any.whl" + +[tool.uv.sources.soar-sdk] +git = "https://github.com/chronicle/soar-sdk.git" + +[tool.uv.sources.integration-testing] +path = "../../../../packages/integration_testing_whls/integration_testing-2.2.12-py3-none-any.whl" diff --git a/content/response_integrations/google/azure_monitor/release_notes.yaml b/content/response_integrations/google/azure_monitor/release_notes.yaml new file mode 100644 index 0000000000..c6a01c538e --- /dev/null +++ b/content/response_integrations/google/azure_monitor/release_notes.yaml @@ -0,0 +1,76 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- description: New Integration Added - Azure Monitor. + version: 1.0 + item_name: Azure Monitor + item_type: Integration + publish_time: '2025-11-12' + ticket_number: '437036087' + new: true + regressive: false + deprecated: false + removed: false +- description: Search Logs - Updated Predefined Widget. + version: 2.0 + item_name: Search Logs + item_type: Widget + publish_time: '2026-03-18' + ticket_number: '487544122' + new: false + regressive: false + deprecated: false + removed: false +- description: Updated integration metadata + version: 3.0 + item_name: AzureMonitor + item_type: Integration + publish_time: '2026-03-19' + ticket_number: '' + new: false + regressive: false + deprecated: false + removed: false +- description: Updated the integration AI metadata + version: 4.0 + item_name: AzureMonitor + item_type: Integration + publish_time: '2026-07-19' + ticket_number: '' + new: false + regressive: false + deprecated: false + removed: false +- description: Integration - Updated documentation link. + version: 5.0 + item_name: AzureMonitor + item_type: Integration + publish_time: '2026-07-22' + ticket_number: '535931521' + new: false + regressive: false + deprecated: false + removed: false + +- description: 'Integration - Source code for the integration is now available publicly + on Github. Link to repo: https://github.com/chronicle/content-hub' + integration_version: 6.0 + item_name: AzureMonitor + item_type: Integration + publish_time: '2026-08-20' + new: false + regressive: false + deprecated: false + removed: false + ticket_number: '495762513' diff --git a/content/response_integrations/google/azure_monitor/resources/ai/actions_ai_description.yaml b/content/response_integrations/google/azure_monitor/resources/ai/actions_ai_description.yaml new file mode 100644 index 0000000000..7330395b64 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/resources/ai/actions_ai_description.yaml @@ -0,0 +1,323 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +Ping: + ai_description: >- + ### General Description + + The **Ping** action is designed to verify the connectivity between Google SecOps + and the Azure Monitor service. It ensures that the provided credentials (Tenant + ID, Client ID, Client Secret) and the Workspace ID are valid and that the network + path to the Azure Log Analytics API is open. + + + ### Flow Description + + 1. **Authentication**: The action retrieves the integration configuration and + performs an OAuth2 Client Credentials flow to obtain an access token from the + Microsoft identity platform. + + 2. **Connectivity Test**: It sends a POST request to the Azure Monitor Query API + endpoint (`/v1/workspaces/{workspace_id}/query`). + + 3. **Validation**: The request includes a simple query (`AzureActivity`) limited + to a single row and a one-hour time window to verify the API is responsive. + + 4. **Result**: If the API returns a successful response, the action reports a + successful connection. Otherwise, it parses the error message from the response + and reports a failure. + + + ### Additional Notes + + This action is typically used during the initial setup of the integration or for + troubleshooting connection issues. It performs a minimal query against the AzureActivity + table to confirm end-to-end communication. + ai_short_description: >- + Verifies connectivity between Google SecOps and the Azure Monitor service by authenticating + and executing a minimal test query. + capabilities: + can_create_case_comments: false + can_create_insight: false + can_modify_alert_data: false + can_mutate_external_data: false + can_mutate_internal_data: false + can_update_entities: false + external_data_mutation_explanation: null + fetches_data: false + internal_data_mutation_explanation: null + reasoning: >- + The action makes a POST request to the Azure Monitor API to test connectivity. + It does not fetch contextual data for alerts/entities, mutate external data + (it only runs a read-only query), mutate internal data, update entities, create + insights, modify alert data, or create case comments. + entity_usage: + entity_types: + address: false + alert: false + application: false + child_hash: false + child_process: false + cluster: false + container: false + credit_card: false + cve: false + cve_id: false + database: false + deployment: false + destination_domain: false + domain: false + email_message: false + event: false + file_hash: false + file_name: false + generic: false + host_name: false + ip_set: false + mac_address: false + parent_hash: false + parent_process: false + phone_number: false + pod: false + process: false + service: false + source_domain: false + threat_actor: false + threat_campaign: false + threat_signature: false + url: false + usb: false + user: false + filters_by_additional_properties: false + filters_by_alert_identifier: false + filters_by_case_identifier: false + filters_by_creation_time: false + filters_by_entity_type: false + filters_by_identifier: false + filters_by_is_artifact: false + filters_by_is_enriched: false + filters_by_is_internal: false + filters_by_is_pivot: false + filters_by_is_suspicious: false + filters_by_is_vulnerable: false + filters_by_modification_time: false + reasoning: >- + The action does not iterate over `target_entities` or use any entity-specific + identifiers. It performs a general connectivity test to the Azure Monitor API + without relying on any case or entity data. Therefore, all entity type and filter + flags are false. + outcome_categories: + add_alert_comment: false + add_ioc_to_allowlist: false + add_ioc_to_blocklist: false + contain_host: false + create_ticket: false + delete_email: false + disable_identity: false + download_file: false + enable_identity: false + enrich_asset: false + enrich_ioc: false + execute_command_on_the_host: false + get_alert_information: false + reasoning: >- + The action is a simple connectivity test (Ping) that authenticates and runs + a minimal query against Azure Monitor to verify API access. It does not enrich + IOCs/assets, update alerts, manage tickets, modify blocklists/allowlists, manage + identities, contain hosts, search events (for actual results), or perform any + other categorized outcome. + remove_ioc_from_allowlist: false + remove_ioc_from_blocklist: false + reset_identity_password: false + search_asset: false + search_email: false + search_events: false + send_email: false + send_message: false + submit_file: false + uncontain_host: false + update_alert: false + update_email: false + update_identity: false + update_ticket: false + parameters_description: There are no parameters for this action +Search Logs: + ai_description: >- + ### General Description + + The **Search Logs** action allows users to execute KQL (Kusto Query Language) + queries against an Azure Monitor Log Analytics workspace to retrieve log data. + It is designed for flexible data retrieval, supporting both predefined time ranges + and custom ISO 8601 timeframes. The results are returned as a list of JSON objects + representing the log entries found. + + + ### Flow Description + + 1. **Parameter Extraction:** The action retrieves the workspace ID, query, time + settings, and result limits from the input parameters. + + 2. **Time Calculation:** It determines the `timespan` for the API request. If + a predefined time frame is used, it calculates the start time relative to the + current UTC time. If `Custom` is used, it validates the provided ISO 8601 strings. + + 3. **API Request:** A POST request is sent to the Azure Monitor Log Analytics + query endpoint (`/v1/workspaces/{workspace_id}/query`) containing the query, timespan, + and row limit. + + 4. **Data Parsing:** The raw tabular response from Azure is parsed into dynamic + JSON objects where column names are converted to snake_case. + + 5. **Result Delivery:** The action populates the JSON results with the retrieved + log entries and provides a summary message indicating success or if no results + were found. + + + ### Additional Notes + + - **Time Logic:** If the 'Time Frame' parameter is set to any value other than + `Custom`, the 'Start Time' and 'End Time' parameters provided by the user are + ignored in favor of the calculated relative time. + + - **Validation:** The action validates that 'Max Results To Return' does not exceed + 1000 and ensures that 'Start Time' is provided when using a custom timeframe. + ai_short_description: >- + Executes KQL queries against an Azure Monitor Log Analytics workspace to retrieve + log data based on specified timeframes and returns the results as JSON objects. + capabilities: + can_create_case_comments: false + can_create_insight: false + can_modify_alert_data: false + can_mutate_external_data: false + can_mutate_internal_data: false + can_update_entities: false + external_data_mutation_explanation: null + fetches_data: true + internal_data_mutation_explanation: null + reasoning: >- + The action fetches data by making a POST request to the Azure Monitor query + API to retrieve logs. It does not mutate external data (it only queries/reads + data). It does not mutate internal data, update entities, create insights, modify + alerts, or create case comments. + entity_usage: + entity_types: + address: false + alert: false + application: false + child_hash: false + child_process: false + cluster: false + container: false + credit_card: false + cve: false + cve_id: false + database: false + deployment: false + destination_domain: false + domain: false + email_message: false + event: false + file_hash: false + file_name: false + generic: false + host_name: false + ip_set: false + mac_address: false + parent_hash: false + parent_process: false + phone_number: false + pod: false + process: false + service: false + source_domain: false + threat_actor: false + threat_campaign: false + threat_signature: false + url: false + usb: false + user: false + filters_by_additional_properties: false + filters_by_alert_identifier: false + filters_by_case_identifier: false + filters_by_creation_time: false + filters_by_entity_type: false + filters_by_identifier: false + filters_by_is_artifact: false + filters_by_is_enriched: false + filters_by_is_internal: false + filters_by_is_pivot: false + filters_by_is_suspicious: false + filters_by_is_vulnerable: false + filters_by_modification_time: false + reasoning: >- + The action does not iterate over `siemplify.target_entities` or use any entity-specific + identifiers. It executes a general log search based on the provided query parameter. + Therefore, it does not run on entities and all entity type and filter flags + must be false. + outcome_categories: + add_alert_comment: false + add_ioc_to_allowlist: false + add_ioc_to_blocklist: false + contain_host: false + create_ticket: false + delete_email: false + disable_identity: false + download_file: false + enable_identity: false + enrich_asset: false + enrich_ioc: false + execute_command_on_the_host: false + get_alert_information: false + reasoning: >- + The action executes a query to retrieve historical logs or telemetry data from + Azure Monitor. This directly aligns with the 'Search Events' expected outcome. + It does not enrich specific IOCs or assets, nor does it mutate any external + or internal state. + remove_ioc_from_allowlist: false + remove_ioc_from_blocklist: false + reset_identity_password: false + search_asset: false + search_email: false + search_events: true + send_email: false + send_message: false + submit_file: false + uncontain_host: false + update_alert: false + update_email: false + update_identity: false + update_ticket: false + parameters_description: >- + | Parameter | Type | Mandatory | Description | + + | --- | --- | --- | --- | + + | Workspace ID | String | No | ID of the workspace that needs to be searched. + If nothing is provided, action will take the Workspace ID provided in the integration + configuration. | + + | Query | String | Yes | Query that needs to be executed. | + + | Time Frame | Dropdown | No | Time frame for the query. If "Custom" is selected, + you also need to provide "Start Time". | + + | Start Time | String | No | Start time for the query. This parameter is mandatory, + if "Custom" is selected for the "Time Frame" parameter. Format: ISO 8601. | + + | End Time | String | No | End time for the query. Format: ISO 8601. If nothing + is provided and "Custom" is selected for the "Time Frame" parameter then this + parameter will use current time. | + + | Max Results To Return | Integer | Yes | How many results should be returned + from the search. Maximum: 1000. | diff --git a/content/response_integrations/google/azure_monitor/resources/ai/integration_ai_description.yaml b/content/response_integrations/google/azure_monitor/resources/ai/integration_ai_description.yaml new file mode 100644 index 0000000000..01a60b282f --- /dev/null +++ b/content/response_integrations/google/azure_monitor/resources/ai/integration_ai_description.yaml @@ -0,0 +1,27 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +product_categories: + reasoning: '' + siem: false + edr: false + network_security: false + threat_intelligence: false + email_security: false + iam_and_identity_management: false + cloud_security: false + itsm: false + vulnerability_management: false + asset_inventory: false + collaboration: false diff --git a/content/response_integrations/google/azure_monitor/resources/image.png b/content/response_integrations/google/azure_monitor/resources/image.png new file mode 100644 index 0000000000..3a0bf40e75 Binary files /dev/null and b/content/response_integrations/google/azure_monitor/resources/image.png differ diff --git a/content/response_integrations/google/azure_monitor/resources/logo.svg b/content/response_integrations/google/azure_monitor/resources/logo.svg new file mode 100644 index 0000000000..9319607e7f --- /dev/null +++ b/content/response_integrations/google/azure_monitor/resources/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/content/response_integrations/google/azure_monitor/resources/search_logs_JsonResult_example.json b/content/response_integrations/google/azure_monitor/resources/search_logs_JsonResult_example.json new file mode 100644 index 0000000000..9c3b1facf2 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/resources/search_logs_JsonResult_example.json @@ -0,0 +1,10 @@ +[ + { + "TimeGenerated": "2025-10-29T11:50:45.3033407Z", + "OperationName": "Update Documents" + }, + { + "TimeGenerated": "2025-10-29T11:50:47.0376269Z", + "OperationName": "Update Incidents" + } +] \ No newline at end of file diff --git a/content/response_integrations/google/azure_monitor/tests/__init__.py b/content/response_integrations/google/azure_monitor/tests/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/tests/common.py b/content/response_integrations/google/azure_monitor/tests/common.py new file mode 100644 index 0000000000..54abfa209c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/common.py @@ -0,0 +1,58 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations +import json +from integration_testing.common import get_def_file_content + +import pathlib + +from TIPCommon.types import SingleJson +from azure_monitor.core.data_models import AzureLogEntry +from integration_testing.common import get_def_file_content + + +CONFIG_PATH: pathlib.Path = pathlib.Path(__file__).parent / "config.json" +CONFIG: SingleJson = get_def_file_content(CONFIG_PATH) +MOCK_PATH: pathlib.Path = pathlib.Path(__file__).parent / "mock_data.json" +MOCK_DATA: SingleJson = get_def_file_content(MOCK_PATH) +LIST_LOGS: SingleJson = MOCK_DATA["search_logs"] +LIST_LOG_ENTRY: list[AzureLogEntry] = AzureLogEntry.from_json(LIST_LOGS) + + +def azure_log_entries_to_api_json(entries: list[AzureLogEntry]) -> SingleJson: + """Convert list of AzureLogEntry objects into API-style JSON format. + + Args: + entries (list[AzureLogEntry]): List of AzureLogEntry instances. + + Returns: + SingleJson: JSON object following Azure Monitor API format. + """ + return { + "tables": [ + { + "name": "PrimaryResult", + "columns": [ + {"name": "TimeGenerated", "type": "datetime"}, + {"name": "OperationName", "type": "string"}, + ], + "rows": [ + [entry.time_generated, entry.operation_name] + for entry in entries + ], + } + ] + } +INTEGRATION_PATH: pathlib.Path = pathlib.Path(__file__).parent.parent diff --git a/content/response_integrations/google/azure_monitor/tests/config.json b/content/response_integrations/google/azure_monitor/tests/config.json new file mode 100644 index 0000000000..1228a44b35 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/config.json @@ -0,0 +1,9 @@ +{ + "Login API Root": "https://login.microsoftonline.com", + "API Root": "https://api.loganalytics.io", + "Tenant ID": "dummy_tenant_id", + "Client ID": "dummy_client_id", + "Client Secret": "dummy_secret_id", + "Workspace ID": "dummy_workspace_id", + "Verify SSL": true +} \ No newline at end of file diff --git a/content/response_integrations/google/azure_monitor/tests/conftest.py b/content/response_integrations/google/azure_monitor/tests/conftest.py new file mode 100644 index 0000000000..94da898d89 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/conftest.py @@ -0,0 +1,79 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +pytest_plugins = ("integration_testing.conftest",) +import sys +import os +import pkgutil +import importlib +import soar_sdk +sdk_dir = soar_sdk.__path__[0] +if sdk_dir not in sys.path: + sys.path.insert(0, sdk_dir) +original_stdout = sys.stdout +for _, name, _ in pkgutil.iter_modules(soar_sdk.__path__): + try: + flat_mod = importlib.import_module(name) + sys.modules[f'soar_sdk.{name}'] = flat_mod + setattr(soar_sdk, name, flat_mod) + except Exception: + pass +sys.stdout = original_stdout +import pytest + +from TIPCommon.base.utils import CreateSession + +from azure_monitor.core.api_client import ( + AzureMonitorApiClient, + ApiParameters, +) +from integration_testing.common import use_live_api +from integration_testing.request import MockRequest +from integration_testing.requests.response import MockResponse +from integration_testing.logger import Logger +from azure_monitor.tests.common import CONFIG +from azure_monitor.tests.core.product import AzureMonitor +from azure_monitor.tests.core.session import AzureMonitorSession + + +@pytest.fixture(name="azure_monitor") +def azure_monitor_product() -> AzureMonitor: + yield AzureMonitor() + + +@pytest.fixture(name="script_session", autouse=True) +def azure_monitor_script_session( + monkeypatch: pytest.MonkeyPatch, + azure_monitor: AzureMonitor, +) -> AzureMonitorSession: + session = AzureMonitorSession(azure_monitor) + """Create script session""" + if not use_live_api(): + monkeypatch.setattr(CreateSession, "create_session", lambda *_: session) + yield session + + +@pytest.fixture(name="manager") +def azure_monitor_manager(script_session: AzureMonitorSession) -> AzureMonitorApiClient: + """azure_monitor_ manager""" + api_root: str = CONFIG["API Root"] + workspace_id: str = CONFIG["Workspace ID"] + logger = Logger() + api_params: ApiParameters = ApiParameters(api_root, workspace_id) + + yield AzureMonitorApiClient(script_session, api_params, logger) + +@pytest.fixture(name='sdk_session', autouse=True) +def sdk_session_fixture(script_session): + return script_session diff --git a/content/response_integrations/google/azure_monitor/tests/core/__init__.py b/content/response_integrations/google/azure_monitor/tests/core/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/core/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/tests/core/product.py b/content/response_integrations/google/azure_monitor/tests/core/product.py new file mode 100644 index 0000000000..c1251ef7e9 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/core/product.py @@ -0,0 +1,33 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import abc +from typing import MutableMapping + +from azure_monitor.core.data_models import AzureLogEntry + + +class AzureMonitor(abc.ABC): + + def __init__(self) -> None: + self._logs: MutableMapping[str, list[AzureLogEntry]] = {} + + def add_logs(self, query: str, logs: list[AzureLogEntry]) -> None: + self._logs[query] = logs + + def get_logs(self, query: str) -> list[AzureLogEntry]: + return self._logs[query] + + def cleanup_logs(self) -> None: + self._logs.clear() diff --git a/content/response_integrations/google/azure_monitor/tests/core/session.py b/content/response_integrations/google/azure_monitor/tests/core/session.py new file mode 100644 index 0000000000..0b277bcadd --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/core/session.py @@ -0,0 +1,64 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from collections.abc import Iterable + +from azure_monitor.tests import common +from azure_monitor.tests.core.product import AzureMonitor +from integration_testing import router +from integration_testing.request import MockRequest +from integration_testing.requests.response import MockResponse +from integration_testing.requests.session import MockSession, RouteFunction + + +class AzureMonitorSession(MockSession[MockRequest, MockResponse, AzureMonitor]): + def get_routed_functions(self) -> Iterable[RouteFunction]: + return [ + self.search_logs, + get_oauth_token, + ] + + @router.post("/v1/workspaces/[a-zA-Z0-9_-]+/query") + def search_logs(self, request: MockRequest) -> MockResponse: + """Search logs mock implementation""" + if "invalid_query" in request.kwargs["json"]["query"]: + return MockResponse(status_code=200, content={}) + if "invalid_workspace_id" in request.url.path: + return MockResponse( + status_code=403, content={"error": {"message": "Invalid Workspace ID."}} + ) + + logs = self._product.get_logs(request.kwargs["json"]["query"]) + + return MockResponse( + status_code=200, content=common.azure_log_entries_to_api_json(logs) + ) + + +@router.post("/[a-zA-Z0-9_-]+/oauth2/token") +def get_oauth_token(request: MockRequest) -> MockResponse: + """Get an OAuth token""" + if "invalid_client_id" in request.kwargs["data"].values(): + return MockResponse( + status_code=401, + content={ + "error": "unauthorized_client", + "error_description": "Invalid client id is provided.", + }, + ) + + return MockResponse( + status_code=200, + content=common.MOCK_DATA["oauth_token"], + ) diff --git a/content/response_integrations/google/azure_monitor/tests/mock_data.json b/content/response_integrations/google/azure_monitor/tests/mock_data.json new file mode 100644 index 0000000000..37131ea092 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/mock_data.json @@ -0,0 +1,38 @@ +{ + "oauth_token": { + "token_type": "Bearer", + "expires_in": "3599", + "ext_expires_in": "3599", + "expires_on": "1761765809", + "not_before": "1761761909", + "resource": "https://abc.com", + "access_token": "dummy_value" + }, + "search_logs": { + "tables": [ + { + "name": "PrimaryResult", + "columns": [ + { + "name": "TimeGenerated", + "type": "datetime" + }, + { + "name": "OperationName", + "type": "string" + } + ], + "rows": [ + [ + "2025-10-29T12:42:44.6629245Z", + "Create role assignment" + ], + [ + "2025-10-29T12:42:44.6782565Z", + "Create role assignment" + ] + ] + } + ] + } +} \ No newline at end of file diff --git a/content/response_integrations/google/azure_monitor/tests/test_actions/__init__.py b/content/response_integrations/google/azure_monitor/tests/test_actions/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/test_actions/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/tests/test_actions/test_ping.py b/content/response_integrations/google/azure_monitor/tests/test_actions/test_ping.py new file mode 100644 index 0000000000..1781a020c2 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/test_actions/test_ping.py @@ -0,0 +1,81 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from TIPCommon.base.action import ExecutionState +from TIPCommon.base.data_models import ActionOutput + +from azure_monitor.actions import ping +from azure_monitor.tests import common +from azure_monitor.tests.core.product import AzureMonitor +from azure_monitor.tests.core.session import AzureMonitorSession +from integration_testing.platform.script_output import MockActionOutput +from integration_testing.set_meta import set_metadata + + +PING_SUCCESS_MESSAGE: str = ( + "Successfully connected to the Azure Monitor server with the provided connection " + "parameters!" +) + +FAILED_OUTPUT_MESSAGE: str = ( + "Failed to connect to the Azure Monitor server!\nReason: " + "Please Check your Credentials." +) + + +# pylint: disable=unused-argument + + +@set_metadata(integration_config=common.CONFIG) +def test_ping_success( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + ping.main() + + assert len(script_session.request_history) == 2 + assert action_output.results == ActionOutput( + output_message=PING_SUCCESS_MESSAGE, + result_value=True, + execution_state=ExecutionState.COMPLETED, + json_output=None, + ) + + +FAILED_CONFIG = common.CONFIG.copy() +FAILED_CONFIG["Client ID"] = "invalid_client_id" + + +@set_metadata(integration_config=FAILED_CONFIG) +def test_ping_failed( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + + ping.main() + + assert len(script_session.request_history) == 1 + assert action_output.results == ActionOutput( + output_message=FAILED_OUTPUT_MESSAGE, + result_value=False, + execution_state=ExecutionState.FAILED, + json_output=None, + ) diff --git a/content/response_integrations/google/azure_monitor/tests/test_actions/test_search_logs.py b/content/response_integrations/google/azure_monitor/tests/test_actions/test_search_logs.py new file mode 100644 index 0000000000..72f0e7cf00 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/test_actions/test_search_logs.py @@ -0,0 +1,290 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from TIPCommon.base.action import ExecutionState + +from azure_monitor.actions import search_logs +from azure_monitor.tests import common +from azure_monitor.tests.core.product import AzureMonitor +from azure_monitor.tests.core.session import AzureMonitorSession +from integration_testing.platform.script_output import MockActionOutput +from integration_testing.set_meta import set_metadata + + +SUCCESS_MESSAGE: str = ( + 'Successfully returned results for the query "{query}" in Azure Monitor.' +) +NO_RESULTS_OUTPUT_MESSAGE: str = ( + 'No results were found for the query "invalid_query" in Azure Monitor.' +) + +CUSTOM_TIME_FRAME_VALIDATION_MESSAGE: str = ( + 'Error executing action "AzureMonitor - Search Logs"\n' + "Reason: 'Start Time' must be provided if 'Time Frame' is set to 'Custom'." +) +ISO_FORMAT_VALIDATION_MESSAGE: str = ( + 'Error executing action "AzureMonitor - Search Logs"\n' + "Reason: 'Start Time' must be a valid ISO 8601 datetime string " + "(e.g., '2025-10-29T10:15:00Z'). Provided: 'abc'" +) +MAX_RESULTS_MIN_LIMIT_MESSAGE: str = ( + 'Error executing action "AzureMonitor - Search Logs"\n' + 'Reason: Invalid parameter "Max Results To Return". The value must be between 1 ' + "and 1000. Wrong value provided: -1" +) +MAX_RESULTS_MAX_LIMIT_MESSAGE: str = ( + 'Error executing action "AzureMonitor - Search Logs"\n' + 'Reason: Invalid parameter "Max Results To Return". The value must be between 1 ' + "and 1000. Wrong value provided: 1001" +) +FAILED_OUTPUT_MESSAGE: str = ( + 'Error executing action "AzureMonitor - Search Logs"\n' + "Reason: Invalid Workspace ID." +) + +DEFAULT_PARAMETERS: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Last Hour", + "Max Results To Return": 100, +} +PARAMETERS_INVALID_QUERY: dict[str, str] = { + "Query": "invalid_query", + "Time Frame": "Last Hour", + "Max Results To Return": 100, +} +CUSTOM_TIME_FRAME_VALIDATION_PARAMETERS: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Custom", + "Max Results To Return": 100, +} +CUSTOM_TIME_FRAME_SUCCESSFUL_EXECUTION_PARAMETERS: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Custom", + "Max Results To Return": 100, + "Start Time": "2025-10-29T10:15:00Z", + "End Time": "2025-10-29T12:15:00Z", +} +ISO_FORMAT_VALIDATION_PARAMETERS: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Custom", + "Max Results To Return": 100, + "Start Time": "abc", + "End Time": "xyz", +} +MAX_RESULTS_MIN_LIMIT_PARAMETERS_VALIDATION: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Last Hour", + "Max Results To Return": -1, +} +MAX_RESULTS_MAX_LIMIT_PARAMETERS_VALIDATION: dict[str, str] = { + "Query": "AzureActivity", + "Time Frame": "Last Hour", + "Max Results To Return": 1001, +} +WORKSPACE_ID_PARAMETERS: dict[str, str] = { + "Workspace ID": "workspace_id", + "Query": "AzureActivity", + "Time Frame": "Last Hour", + "Max Results To Return": 100, +} +INVALID_WORKSPACE_ID_PARAMETERS: dict[str, str] = { + "Workspace ID": "invalid_workspace_id", + "Query": "AzureActivity", + "Time Frame": "Last Hour", + "Max Results To Return": 100, +} + +JSON_OUTPUT_RESULT: list[dict[str, str]] = [ + { + "TimeGenerated": "2025-10-29T12:42:44.6629245Z", + "OperationName": "Create role assignment", + }, + { + "TimeGenerated": "2025-10-29T12:42:44.6782565Z", + "OperationName": "Create role assignment", + }, +] + + +# pylint: disable=unused-argument + + +@set_metadata(integration_config=common.CONFIG, parameters=DEFAULT_PARAMETERS) +def test_search_logs_success( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + search_logs.main() + + assert len(script_session.request_history) == 2 + assert action_output.results.output_message == SUCCESS_MESSAGE.format(query=query) + assert action_output.results.result_value is True + assert action_output.results.execution_state == ExecutionState.COMPLETED + assert action_output.results.json_output.json_result == JSON_OUTPUT_RESULT + + +@set_metadata(integration_config=common.CONFIG, parameters=PARAMETERS_INVALID_QUERY) +def test_search_logs_invalid_query( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + search_logs.main() + + assert len(script_session.request_history) == 2 + assert action_output.results.output_message == NO_RESULTS_OUTPUT_MESSAGE + assert action_output.results.result_value is True + assert action_output.results.execution_state == ExecutionState.COMPLETED + assert action_output.results.json_output is None + + +@set_metadata( + integration_config=common.CONFIG, + parameters=CUSTOM_TIME_FRAME_VALIDATION_PARAMETERS, +) +def test_search_logs_custom_time_frame_validation( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + search_logs.main() + + assert len(script_session.request_history) == 1 + assert action_output.results.output_message == CUSTOM_TIME_FRAME_VALIDATION_MESSAGE + assert action_output.results.result_value is False + assert action_output.results.execution_state == ExecutionState.FAILED + assert action_output.results.json_output is None + + +@set_metadata( + integration_config=common.CONFIG, + parameters=ISO_FORMAT_VALIDATION_PARAMETERS, +) +def test_search_logs_iso_format_validation( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + search_logs.main() + + assert len(script_session.request_history) == 1 + assert action_output.results.output_message == ISO_FORMAT_VALIDATION_MESSAGE + assert action_output.results.result_value is False + assert action_output.results.execution_state == ExecutionState.FAILED + assert action_output.results.json_output is None + + +@set_metadata( + integration_config=common.CONFIG, + parameters=CUSTOM_TIME_FRAME_SUCCESSFUL_EXECUTION_PARAMETERS, +) +def test_search_logs_success_with_custom_time_frame( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + search_logs.main() + + assert len(script_session.request_history) == 2 + assert action_output.results.output_message == SUCCESS_MESSAGE.format(query=query) + assert action_output.results.result_value is True + assert action_output.results.execution_state == ExecutionState.COMPLETED + assert action_output.results.json_output.json_result == JSON_OUTPUT_RESULT + + +@set_metadata( + integration_config=common.CONFIG, + parameters=MAX_RESULTS_MIN_LIMIT_PARAMETERS_VALIDATION, +) +def test_search_logs_max_results_min_limit_validation( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + search_logs.main() + + assert len(script_session.request_history) == 1 + assert action_output.results.output_message == MAX_RESULTS_MIN_LIMIT_MESSAGE + assert action_output.results.result_value is False + assert action_output.results.execution_state == ExecutionState.FAILED + assert action_output.results.json_output is None + + +@set_metadata( + integration_config=common.CONFIG, + parameters=MAX_RESULTS_MAX_LIMIT_PARAMETERS_VALIDATION, +) +def test_search_logs_max_results_max_limit_validation( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + search_logs.main() + + assert len(script_session.request_history) == 1 + assert action_output.results.output_message == MAX_RESULTS_MAX_LIMIT_MESSAGE + assert action_output.results.result_value is False + assert action_output.results.execution_state == ExecutionState.FAILED + assert action_output.results.json_output is None + + +@set_metadata(integration_config=common.CONFIG, parameters=WORKSPACE_ID_PARAMETERS) +def test_search_logs_success_with_workspace_id( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + search_logs.main() + + assert len(script_session.request_history) == 2 + assert action_output.results.output_message == SUCCESS_MESSAGE.format(query=query) + assert action_output.results.result_value is True + assert action_output.results.execution_state == ExecutionState.COMPLETED + assert action_output.results.json_output.json_result == JSON_OUTPUT_RESULT + + +@set_metadata( + integration_config=common.CONFIG, + parameters=INVALID_WORKSPACE_ID_PARAMETERS, +) +def test_search_logs_failed_with_invalid_workspace_id( + azure_monitor: AzureMonitor, + script_session: AzureMonitorSession, + action_output: MockActionOutput, +) -> None: + azure_monitor.cleanup_logs() + query = "AzureActivity" + azure_monitor.add_logs(query, common.LIST_LOG_ENTRY) + search_logs.main() + + assert len(script_session.request_history) == 2 + assert action_output.results.output_message == FAILED_OUTPUT_MESSAGE + assert action_output.results.result_value is False + assert action_output.results.execution_state == ExecutionState.FAILED + assert action_output.results.json_output is None diff --git a/content/response_integrations/google/azure_monitor/tests/test_defaults/__init__.py b/content/response_integrations/google/azure_monitor/tests/test_defaults/__init__.py new file mode 100644 index 0000000000..9f71a2dc3c --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/test_defaults/__init__.py @@ -0,0 +1,14 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + diff --git a/content/response_integrations/google/azure_monitor/tests/test_defaults/test_imports.py b/content/response_integrations/google/azure_monitor/tests/test_defaults/test_imports.py new file mode 100644 index 0000000000..c5e5a63a04 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/tests/test_defaults/test_imports.py @@ -0,0 +1,23 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import annotations + +from integration_testing.default_tests.import_test import import_all_integration_modules + +from azure_monitor.tests import common + + +def test_imports() -> None: + import_all_integration_modules(common.INTEGRATION_PATH) diff --git a/content/response_integrations/google/azure_monitor/uv.lock b/content/response_integrations/google/azure_monitor/uv.lock new file mode 100644 index 0000000000..0a7c1e596a --- /dev/null +++ b/content/response_integrations/google/azure_monitor/uv.lock @@ -0,0 +1,873 @@ +version = 1 +revision = 3 +requires-python = "==3.11.*" + +[[package]] +name = "aiohappyeyeballs" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.14.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "typing-extensions" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/d9/22ce5786ac0c1653ae8b6c23bded02c1686d11f0dbb45b31ce128e0df985/aiohttp-3.14.3.tar.gz", hash = "sha256:9491196535a88924a60afd5b5f434b5b203b6cc616250878dbdb223a8f7844bc", size = 7971213, upload-time = "2026-07-23T01:57:27.037Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/5c/b3e4ff8ad43a8afef9602c5e90285936da1beaea8b029016b793891f03c3/aiohttp-3.14.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e568e14940c09955aa51f4e645b6daa18a581c5dcfcd73744dcc86a856e3ced3", size = 764250, upload-time = "2026-07-23T01:52:48.525Z" }, + { url = "https://files.pythonhosted.org/packages/0e/da/f1b384465e51449d844056b75070461da03a9a23e6c1747003695bf4172a/aiohttp-3.14.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:54cfcdee2770dac994417cbb0ee1f3eb0e7cb6b30c79bf44f2c02ff79ec5124a", size = 516281, upload-time = "2026-07-23T01:52:51.047Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/01264f820ee2e3712a827892b1cd6ff80f3300c1fcbffbb45714a915d47a/aiohttp-3.14.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:21c016079415ed3fd676963e9793700a566d85dbbd6bfc564b9b2d209147dcc8", size = 514742, upload-time = "2026-07-23T01:52:53.779Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8d/a71c6f2db52ac1ed142b133f7feddaa6b70539c3f4de24d7e226c95b794c/aiohttp-3.14.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d6088ec9894113802bddb3c09e974929aed2c7b3a8c456219b8aab4481f1a239", size = 1780613, upload-time = "2026-07-23T01:52:56.948Z" }, + { url = "https://files.pythonhosted.org/packages/a5/11/3dd9b3fb3a170f6ec9011b5291d876a6fab4086714c9e158600edf01b4fd/aiohttp-3.14.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:16ea7e24c309fb7c0bbd505d149abe4fe4dccfb8db911db7dbec0921bc889a6f", size = 1737688, upload-time = "2026-07-23T01:52:59.294Z" }, + { url = "https://files.pythonhosted.org/packages/6d/3e/834c26918be7d88068822b40e0db30fca50b5f4fe79104aa16a93f1d74e6/aiohttp-3.14.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:56f355e79f71aef2a85c80305cc915f894b170dba76de5fe84f6351939b83c06", size = 1845742, upload-time = "2026-07-23T01:53:01.641Z" }, + { url = "https://files.pythonhosted.org/packages/cc/c9/49ab8572df7d66bc13d11e31f781292badb04180dd87ba98733066c6aed7/aiohttp-3.14.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:18c441d0a8fca6de8d1f546849b9f0ab20d435993e2c5b59562b2fae6be2f929", size = 1928412, upload-time = "2026-07-23T01:53:04.018Z" }, + { url = "https://files.pythonhosted.org/packages/a5/b9/2b8f0c0ce09c87a1daf80fd483431b56b1435d3f62789bc86f572e1245de/aiohttp-3.14.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:53e7b4ce82b54a8bcc71b3b67a5cbd177ca1d7f592cbc92cd38b7349f73482db", size = 1786220, upload-time = "2026-07-23T01:53:06.481Z" }, + { url = "https://files.pythonhosted.org/packages/85/00/9c45f81de11710460edfa1dc81317b6e882703b160926c879a9d20da9fcc/aiohttp-3.14.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f55119f7bf25f49ed210f6096090715da24f2943c62102448915fde3c62877ce", size = 1637231, upload-time = "2026-07-23T01:53:10.258Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/967d628e910756f3539c6107cb7844a1b69440dcb3029a5ee7871b09ab63/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9aa6e61fdf20105c4144e755bd586008ff450791d67b1c8146fdc15959c4d51c", size = 1753161, upload-time = "2026-07-23T01:53:13.817Z" }, + { url = "https://files.pythonhosted.org/packages/11/b2/0c3d4114f0aee4f580f5b3b4eb71b24d7a23b834ea506a4dfebe76513f35/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ccd4893707b3e2a13e39c90d43cf80edf2e4d0457935bcc103bf2346214c3f15", size = 1756356, upload-time = "2026-07-23T01:53:16.211Z" }, + { url = "https://files.pythonhosted.org/packages/63/5d/99e7d91c82f1399d1ae2a854e080bd1493fbc31e5e959dbc4ec33dac3bec/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2466434105a4e03113c36ec775cc2ebe6676b62eae326fa670bb607ef788c1c", size = 1819846, upload-time = "2026-07-23T01:53:18.289Z" }, + { url = "https://files.pythonhosted.org/packages/ad/05/d5e1cb6480eeffd3f901d40a2c5e2d1e7effdc797837da3b490272699f13/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:ba59d59aba08ac02fc03b0c8983ccd5ee39a199d0552ce9e6d2b4845b34d59ae", size = 1628531, upload-time = "2026-07-23T01:53:23.86Z" }, + { url = "https://files.pythonhosted.org/packages/c9/90/b934682bcaefae18a9e04f3dff5b68522ba810906358ae5029b68110ea3b/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ed099d105449c4f9e84f24af203cd131349d4761d8813fa7e02c32e7128cd910", size = 1832712, upload-time = "2026-07-23T01:53:27.551Z" }, + { url = "https://files.pythonhosted.org/packages/21/df/6061679faaf81fac746e7307c7adb71e858071a5d34c27583afefc64f543/aiohttp-3.14.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:152516815ef926786a0b6ae2b8f1fd2e0c71582dee0b435636865316fd4891b7", size = 1775014, upload-time = "2026-07-23T01:53:30.223Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1d/f854878bbc69b88faefe924b619a34a6f59ec05fd387c77690667eaa75eb/aiohttp-3.14.3-cp311-cp311-win32.whl", hash = "sha256:a4af35c443e0b1a1bd6a8af3f3485d7fda15c142751a00f3ff8090f0b93346fa", size = 456006, upload-time = "2026-07-23T01:53:34.97Z" }, + { url = "https://files.pythonhosted.org/packages/73/0c/2af9d1674baccd1dbd47282a93d660a22e57ef6167c856deb24b4214fbab/aiohttp-3.14.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1e74298bab6ee0d6e749ed4fd1901c7e604bdda32c03d787a2cc71c46d0433d", size = 481069, upload-time = "2026-07-23T01:53:39.673Z" }, + { url = "https://files.pythonhosted.org/packages/8e/76/88401ff3fc95e85c5fc38d588f36f55e61ecb64343b2bc8d69326f453cc0/aiohttp-3.14.3-cp311-cp311-win_arm64.whl", hash = "sha256:03cd2bde3d7f085b64e549c985f4bb928cad7e8ecf5323bfca320db548d81b39", size = 453021, upload-time = "2026-07-23T01:53:43.749Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "anyio" +version = "4.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz", hash = "sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size = 260176, upload-time = "2026-07-12T20:29:07.082Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl", hash = "sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size = 125813, upload-time = "2026-07-12T20:29:05.763Z" }, +] + +[[package]] +name = "arrow" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, +] + +[[package]] +name = "attrs" +version = "26.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz", hash = "sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32", size = 952055, upload-time = "2026-03-19T14:22:25.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl", hash = "sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309", size = 67548, upload-time = "2026-03-19T14:22:23.645Z" }, +] + +[[package]] +name = "azuremonitor" +version = "6.0" +source = { virtual = "." } +dependencies = [ + { name = "environmentcommon" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "tipcommon" }, +] + +[package.dev-dependencies] +dev = [ + { name = "integration-testing" }, + { name = "pytest" }, + { name = "pytest-json-report" }, + { name = "soar-sdk" }, +] + +[package.metadata] +requires-dist = [ + { name = "environmentcommon", path = "../../../../packages/envcommon/whls/EnvironmentCommon-1.0.2-py2.py3-none-any.whl" }, + { name = "python-dateutil", specifier = ">=2.9.0.post0" }, + { name = "requests", specifier = "==2.32.5" }, + { name = "tipcommon", path = "../../../../packages/tipcommon/whls/TIPCommon-2.2.12-py2.py3-none-any.whl" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "integration-testing", path = "../../../../packages/integration_testing_whls/integration_testing-2.2.12-py3-none-any.whl" }, + { name = "pytest", specifier = ">=9.1.1" }, + { name = "pytest-json-report", specifier = ">=1.5.0" }, + { name = "soar-sdk", git = "https://github.com/chronicle/soar-sdk.git" }, +] + +[[package]] +name = "certifi" +version = "2026.7.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/c2/24167ea9858356b47a87a50d39908bfdb72ceeefe0041586e704e5376b3a/certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55", size = 138112, upload-time = "2026-07-22T03:35:12.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775", size = 136983, upload-time = "2026-07-22T03:35:11.276Z" }, +] + +[[package]] +name = "cffi" +version = "2.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be", size = 530807, upload-time = "2026-08-03T21:21:18.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/d2/16d99a0c4948febc0ebd133a13b2f688ff7f8cb04da971e1128872ce0c03/cffi-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c8d2c9fd1f2d16f780d15127abb050d13d1a76c03a4bd87d7e4980e45e511e12", size = 183838, upload-time = "2026-08-03T21:19:29.637Z" }, + { url = "https://files.pythonhosted.org/packages/cd/95/31b535a9f0220ae9f357de4a08d57ce89cb417653c2fd9f075f50822a388/cffi-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:398aff33cee2767e3e781d2554c54bd0dff386bb437581e0d8011fde1a942ec1", size = 184168, upload-time = "2026-08-03T21:19:30.764Z" }, + { url = "https://files.pythonhosted.org/packages/ad/5a/4707a0dc1f203f5dde5a907b0d4e3c25d71120241048bd5bc6f1bb9d4e71/cffi-2.1.1-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:154852545011f779917b11c78db2358d095da62a9a172b78ad0a583ee5adc0d0", size = 211805, upload-time = "2026-08-03T21:19:31.867Z" }, + { url = "https://files.pythonhosted.org/packages/ad/66/c19feabb28485b6e0bbaaafa90837a1ef5d302e90f2178bd33f17a49879b/cffi-2.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3311ed60d36f83378794e1009ac6258bafbf81f7888b4caa7b35a521e3f95813", size = 218716, upload-time = "2026-08-03T21:19:32.896Z" }, + { url = "https://files.pythonhosted.org/packages/a7/92/500760486c8baab49a7a8a58ba7fc3355ec3974b454b8a09e528efde9e1d/cffi-2.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6e192623c49c94421616a5778fba35cf0d5a8d000650c1967ef4448ee5cdd990", size = 205569, upload-time = "2026-08-03T21:19:34.142Z" }, + { url = "https://files.pythonhosted.org/packages/a5/a7/a67c733254d6e7373f7822f8082d8d6beade791e0cf12a7611f376fa61c7/cffi-2.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a6e721d4b0e45d5b65e87534470e67b18dcd092c83f68fba09f152b9cbc061af", size = 204907, upload-time = "2026-08-03T21:19:35.174Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a4/4399daaf8f7dfee9d7c3327fdb0426ee041cc63edc358b93911ceb2bfc7a/cffi-2.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e261f78cb6ceaaa36f42f2613f4380d94d9c759a9c73c769ee6e0247364632", size = 217807, upload-time = "2026-08-03T21:19:36.286Z" }, + { url = "https://files.pythonhosted.org/packages/28/f7/dabe6da2466ecbd82dc62e7342dc6b1065dad990c06f00f0ede9ebf2a0ed/cffi-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7225e4514edb64eb6740324353e0da0711954fd8d7da4576755b1c6e09b697cd", size = 221252, upload-time = "2026-08-03T21:19:37.416Z" }, + { url = "https://files.pythonhosted.org/packages/ce/87/616202d8e51342c07d2534c510111c4cc37201775ce8f60802c9335d1edd/cffi-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df913725b79db7bcf03448f36b7bf8815363417d5b58deecf9305e3e30f0f21a", size = 214214, upload-time = "2026-08-03T21:19:38.507Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c6/ab025d75d2c26c19b087c0124e75ee31cb65032f4fe345d356d8c507ab97/cffi-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f5cfbc5fe74540d335175b656c725d74d90e3730c626d92575eea35029d9afaa", size = 219408, upload-time = "2026-08-03T21:19:39.809Z" }, + { url = "https://files.pythonhosted.org/packages/db/e2/7e8109f65445bdc673a7b54f02c677de462db75674220fd1335efc8eb598/cffi-2.1.1-cp311-cp311-win32.whl", hash = "sha256:f8ec5e643a9a937f64e1999eb9f75d072263751912dc5cd06d3c85f8f44be7c3", size = 174470, upload-time = "2026-08-03T21:19:41.246Z" }, + { url = "https://files.pythonhosted.org/packages/73/c0/77ba02423c2f7d7091143c45cd49e0e6575c4c1967394bb542bd923a9b74/cffi-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:42f6930c31dc7f50732c9ae793c2786c7b6b044195967bbdde40bb9be81c4cc0", size = 185096, upload-time = "2026-08-03T21:19:42.615Z" }, + { url = "https://files.pythonhosted.org/packages/7c/47/9f1f85f9672ceda4984dc6c4f8824e8558992a2972c3d3c81fb8eb28d4ba/cffi-2.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:c7659f22557c5a0bc4855cd635f55edec690cc008a40768527762cb9fb263455", size = 179941, upload-time = "2026-08-03T21:19:43.747Z" }, +] + +[[package]] +name = "chardet" +version = "7.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/51/cd61c567092a6cec796144510a68aff158ebfc1df82950a45bae65f28413/chardet-7.6.0.tar.gz", hash = "sha256:93d9df6089ded42ed1fe9f57e272c0b74bd0464d45c0c7d50f09f26f31105c3c", size = 914462, upload-time = "2026-08-14T20:36:59.305Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/2e/d8634bee23a07bf512512ddf6218a68e47f045ae061c0cc80657ed79dcc0/chardet-7.6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6424512f576fa7e88b7431d38a42d57552c8f717465a975fc42e497cd280d833", size = 1088243, upload-time = "2026-08-14T20:36:17.135Z" }, + { url = "https://files.pythonhosted.org/packages/55/95/bd6d59026638cec47dace85858171fbecadd2f9e58cb2b973dc515aa790c/chardet-7.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:284136186ff90735f901ed0a1c6d41e7af67c666841cc0eceb58482a21b7056c", size = 1068688, upload-time = "2026-08-14T20:36:19.183Z" }, + { url = "https://files.pythonhosted.org/packages/7f/4a/60ed03656b28c1f4d378bc3cfe8a6cdda62c7c289398f925610fbbabfd00/chardet-7.6.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5e9b31b9ae93872d66439b046a1e08c2ea99791f3c254dce1e2633e395c5587c", size = 1487945, upload-time = "2026-08-14T20:36:20.64Z" }, + { url = "https://files.pythonhosted.org/packages/03/25/9c8db4f951e974a4db5558d9eea62e1fd5b5889c9d0ad0315eed67c5cdb3/chardet-7.6.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa03322e07ac08d520ec50bb50c73143d0892d1adc067d4c5e58f4ef4b2363a8", size = 1510112, upload-time = "2026-08-14T20:36:22.248Z" }, + { url = "https://files.pythonhosted.org/packages/76/1b/59eb88a78d8f5855c27c25788088df82834ad067f3dddaf4d86ef03cf2d3/chardet-7.6.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0ad9bc6dab4f338673353fa3f0dc96122f559aaf746087408106e2fcbf132fe8", size = 1462470, upload-time = "2026-08-14T20:36:23.557Z" }, + { url = "https://files.pythonhosted.org/packages/02/af/46c80c317f9b4dd61f15c33b1e073fbdd64d13c70fe19e34943071dc9e50/chardet-7.6.0-cp311-cp311-win_amd64.whl", hash = "sha256:360260d074d8712ac1e9048fcafb0fdde246f9d0b12555748ad0017c5ecee43d", size = 1157092, upload-time = "2026-08-14T20:36:25.082Z" }, + { url = "https://files.pythonhosted.org/packages/cf/6e/5a0b348fa4cd7847567a28c6e697ccf58391960bfd13a6e7473ee23ca2f2/chardet-7.6.0-py3-none-any.whl", hash = "sha256:4076d795897ce45239825956a1334e134322ecc4bfe84dbb12acd5390de0fbc1", size = 680279, upload-time = "2026-08-14T20:36:57.763Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/3f/143b048436775b0f76ac3eec145c019e8173ccc2885c8f20319b996d5e83/charset_normalizer-3.5.1.tar.gz", hash = "sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3", size = 171764, upload-time = "2026-08-15T08:20:44.807Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/b6/034f6802e9c3f6418966cfabb7db8c9252cc2429c5098f41cc43af804149/charset_normalizer-3.5.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eda059b6bc8bc0812d626fd91a7ce01bf583df0a61296eff390fd94141a34e30", size = 363585, upload-time = "2026-08-15T08:16:46.646Z" }, + { url = "https://files.pythonhosted.org/packages/d5/fa/6a7e2a7c4b5451912b8c417732df79574354443592a88d616de03da66ae5/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa2bb0b37202dca27175591f761108b5d34096ade1191ffe4808bdf6b1571488", size = 251189, upload-time = "2026-08-15T08:16:48.287Z" }, + { url = "https://files.pythonhosted.org/packages/a4/c8/ab42b07cfd82e919f427fcfaa7c41abae8242833ad1aad66d42bae40b669/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b2b1b3fa5670c127b246df1d0c059defd41f689a868a3b9d79df9b1cac42d22", size = 239724, upload-time = "2026-08-15T08:16:49.67Z" }, + { url = "https://files.pythonhosted.org/packages/e7/80/b9348b5d3041209f98b4cdad7655766369233f1d533f4f4f7558e9717bec/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e5e4d73d588ca5ed09df1b7dcd1b203d1df3c542e3f50d126c947d432b10731", size = 280078, upload-time = "2026-08-15T08:16:51.228Z" }, + { url = "https://files.pythonhosted.org/packages/82/38/083a24028304bc85bb9e376fed801178423dcbb67495f73b6ea0624e1894/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b54e7e13267d49ffbfe68e25b3cbd774dab38fa37238f71265e91b36146eb21c", size = 276650, upload-time = "2026-08-15T08:16:52.625Z" }, + { url = "https://files.pythonhosted.org/packages/0d/35/731ac04aa0a097fc1c97f0994c375bdb230c6c96619db794208fe664e9ce/charset_normalizer-3.5.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c7b742bf31c88566b4bb6335a7f393bb322e580b6bb98df7bd0c25e6e3519ce8", size = 262325, upload-time = "2026-08-15T08:16:54.085Z" }, + { url = "https://files.pythonhosted.org/packages/f5/28/c2028e7021fb89c6e56868ed0e387b8e9aa811abdd2ab3208d6578d2c930/charset_normalizer-3.5.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ba32c4d2abf1d2fe7cf27d280f4cca5664233b0f885549c7761719eb977f486", size = 261140, upload-time = "2026-08-15T08:16:55.604Z" }, + { url = "https://files.pythonhosted.org/packages/28/f0/0c0ceec6d98b7daa62e361e418135d59685811d79ba11529aad5cdf15e84/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0722590aabf9dc6a6c0343d523c05458fa2b5047dbe6302fd526bb570600753f", size = 252791, upload-time = "2026-08-15T08:16:57.103Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3e/48f4cd187b1c33189d86039e9cbe4f92c05454175504b44ff81806d4d1bf/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:aa1099b956fb795e686d073568f6dc002a0bb89765ea6d5b055dd7d9bf1b116c", size = 240730, upload-time = "2026-08-15T08:16:58.418Z" }, + { url = "https://files.pythonhosted.org/packages/42/85/f9e22af69af67c54cce42be9455d9c81294f918b4ccc454db01f66efcac2/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd6c173f04743d483881bffa1478d5a4624475b8cd1d2194956a75548e191c18", size = 280791, upload-time = "2026-08-15T08:16:59.918Z" }, + { url = "https://files.pythonhosted.org/packages/fd/4c/9044135f42127630b6fa742feb51256353f6ab87a78f2fdd1de3de955a7f/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:f298e218441525d3794428b4c8b8fb8662c6d3ea79925d4807ee6b9a96a3bca5", size = 259598, upload-time = "2026-08-15T08:17:01.421Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ed/1dd7cfebb4e75812934c49ca3b79757d11948053f7937ab7070c151f3c55/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6e2912d4babbc65196ac13c2f53468dc57fb8b9c25ef913e8c59ddf7c6dc0e1b", size = 278217, upload-time = "2026-08-15T08:17:02.782Z" }, + { url = "https://files.pythonhosted.org/packages/bf/eb/239c84503cc9e3ba6eb34686a24bc66e84f3924efdd7e38e751a19f6bc10/charset_normalizer-3.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3d27167433c0d5f18dc850f07d0b3816221984fecdc405d6c157a6f0b8f8e9e6", size = 263417, upload-time = "2026-08-15T08:17:04.216Z" }, + { url = "https://files.pythonhosted.org/packages/37/ab/4e4510e1e288478e2c8333131d1c1382382ba8cd2165053c79e39d1da961/charset_normalizer-3.5.1-cp311-cp311-win32.whl", hash = "sha256:ac00177c4831ffa650f8609e4bdddd5fe09c03b1c0c47acece7e6ea20421598b", size = 181774, upload-time = "2026-08-15T08:17:05.58Z" }, + { url = "https://files.pythonhosted.org/packages/e3/57/32f0ccea59e8612057c61d6fd22ef2cb63cca93c9fe594094919696ac170/charset_normalizer-3.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:f9b1e28d0e8dbfa858abdba91d6b547beaf2df1a59bec6da6faae7b96a4991a9", size = 206653, upload-time = "2026-08-15T08:17:07.075Z" }, + { url = "https://files.pythonhosted.org/packages/17/d4/b65c433fc521e58b5f54293982a5e51c05cb5f2dd3f1c7a6acb65b75324e/charset_normalizer-3.5.1-cp311-cp311-win_arm64.whl", hash = "sha256:ae31a1a1db2ee6cc2942fccaf695c934bc7f3db9f2133a3fef1f367cf1a4ab10", size = 185630, upload-time = "2026-08-15T08:17:08.502Z" }, + { url = "https://files.pythonhosted.org/packages/5b/97/fb4e82231aba271ffd775a1b4993b0defc4e3059f286ae41d9433409fe85/charset_normalizer-3.5.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2", size = 331467, upload-time = "2026-08-15T08:19:50.959Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2f/fe3f187327aac18e2d54e9d2b08e15d27bf9b642d9e51c219f130fc34d1a/charset_normalizer-3.5.1-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99", size = 253057, upload-time = "2026-08-15T08:19:52.654Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c7/9e48cee5c161fe24da823b61bf381921d77cb994a0a4de148e95018c1984/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2", size = 240930, upload-time = "2026-08-15T08:19:54.163Z" }, + { url = "https://files.pythonhosted.org/packages/49/e0/716601f3cc69be7b198951150c75ead1ece33c3c8036ff6ffa46029659a0/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235", size = 230822, upload-time = "2026-08-15T08:19:55.807Z" }, + { url = "https://files.pythonhosted.org/packages/d3/05/71bfc5caa0abcc45aea1f6a4d50ac68e59605ddc7666fe8494f4cd229665/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598", size = 260037, upload-time = "2026-08-15T08:19:57.312Z" }, + { url = "https://files.pythonhosted.org/packages/c3/92/de7e32ed05341e7a9c4c877c318418197b7f2d66a3b68d561bf2ac57ca3e/charset_normalizer-3.5.1-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96", size = 255097, upload-time = "2026-08-15T08:19:59.056Z" }, + { url = "https://files.pythonhosted.org/packages/f5/7b/ade0a122600319dfa0b1000ab0f9731c94a817904cf3c5de408c73a4ede7/charset_normalizer-3.5.1-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962", size = 250166, upload-time = "2026-08-15T08:20:00.612Z" }, + { url = "https://files.pythonhosted.org/packages/75/9c/019fbb9f4834491a160951349b1a3714439376f66e5f7cf18b4f18f0c7aa/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3", size = 241821, upload-time = "2026-08-15T08:20:02.321Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b8/11d4840bfc99330cc7fbcc2681ee5a044553a6e77655508d8f9b2bff7b34/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950", size = 232529, upload-time = "2026-08-15T08:20:04.008Z" }, + { url = "https://files.pythonhosted.org/packages/18/96/2b3a21492d9f65171ac75d872f5018260013d00bfa0ff70ec9f179148cbd/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8", size = 260348, upload-time = "2026-08-15T08:20:05.877Z" }, + { url = "https://files.pythonhosted.org/packages/d6/aa/a69a2028e8bd052476c245460ab19d7de595de084dd968f2d75cd50c3e25/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031", size = 247234, upload-time = "2026-08-15T08:20:07.487Z" }, + { url = "https://files.pythonhosted.org/packages/35/8a/3d130aeabcaf3d2466af76b7b141c08d9e89c9016ab4b7cdd0f7dc2d1c62/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072", size = 256917, upload-time = "2026-08-15T08:20:09.142Z" }, + { url = "https://files.pythonhosted.org/packages/80/c2/a7379b840292d0c1ab9fbd17d1f3967aa81794dc95bc74be8999d7fedcf7/charset_normalizer-3.5.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d", size = 254846, upload-time = "2026-08-15T08:20:10.727Z" }, + { url = "https://files.pythonhosted.org/packages/01/65/d43b714731bb2f40d4053dfa00ecfc1c5a301f8e3316c5db3a09af59fe94/charset_normalizer-3.5.1-cp37-abi3-win32.whl", hash = "sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc", size = 174216, upload-time = "2026-08-15T08:20:12.334Z" }, + { url = "https://files.pythonhosted.org/packages/35/4f/b911ed898b26a09789eba9c9200c999aff6c61b4bafaf4838e56d1a1e1a3/charset_normalizer-3.5.1-cp37-abi3-win_amd64.whl", hash = "sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959", size = 199764, upload-time = "2026-08-15T08:20:13.908Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a7/920baf467bfd9bf689f3b318340f37aee4572a71f162bd8db51da55ba4fa/charset_normalizer-3.5.1-cp37-abi3-win_arm64.whl", hash = "sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e", size = 287318, upload-time = "2026-08-15T08:20:15.551Z" }, + { url = "https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl", hash = "sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6", size = 68658, upload-time = "2026-08-15T08:20:43.306Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "cryptography" +version = "50.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:031e2d5dd4bb9caa3ca9c82e5a197fd8ae680232cee62603d1a813f3f07e3d03", size = 4001252, upload-time = "2026-07-31T14:23:33.331Z" }, + { url = "https://files.pythonhosted.org/packages/57/ef/8f2df13c7216bcad3e1c74e07f6e193d93e998e114f524a53877c9af27ad/cryptography-50.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd9192b7b70c573d7f214eb1ae35e00d359f6f5e4b27c7e21e30de1fc6204645", size = 4719554, upload-time = "2026-07-31T14:23:35.611Z" }, + { url = "https://files.pythonhosted.org/packages/d9/41/029086c34d91052fc3b88bcc8056f709a7c915c7a23b235a54eb800b1c97/cryptography-50.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:06a32a980526a6ab9a4b9bf8f7385800791e2bb960903cb6b530e4817509a3b7", size = 4702130, upload-time = "2026-07-31T14:23:37.635Z" }, + { url = "https://files.pythonhosted.org/packages/7d/ff/b6ce0954962e7f7b969f850a883744197bb3910bdfd7b6da162eab7d9f68/cryptography-50.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a1b30560f2acc95aa8b2e06e716a13dbfc97314747b80d9707e307f77b40d6b3", size = 4725244, upload-time = "2026-07-31T14:23:39.471Z" }, + { url = "https://files.pythonhosted.org/packages/06/1e/63a1027cb7fec360a182208e1b7767d5aa1fe57be3d6aa856e69a321edc0/cryptography-50.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8d89f3976b10b4ce31118de72329025f70d2c6ead14a8217c5514dd2c6d5a78f", size = 5342265, upload-time = "2026-07-31T14:23:41.286Z" }, + { url = "https://files.pythonhosted.org/packages/6b/72/a1116d683a6d7ece94590013882515de087edf9ef0e6292aae615a44df73/cryptography-50.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b42a28c1844fd9de8f3f7d540e36b66f3a9c83fceac7170ebc7a6a19edd9dcae", size = 4734609, upload-time = "2026-07-31T14:23:43.139Z" }, + { url = "https://files.pythonhosted.org/packages/15/37/36a9c479bbe49acea2636c7fd3360d20f7b7e079c300352011c44850b181/cryptography-50.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:900131fafd8aead39ac7dd3a7e833be754c17a95cfd91221636949fe4eb0aa8a", size = 4356517, upload-time = "2026-07-31T14:23:44.939Z" }, + { url = "https://files.pythonhosted.org/packages/32/98/8a151d64367204cbc63ec65d37502f1d9c53cf4bfc6ec3c532614dbec60d/cryptography-50.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:07949c449a1abcf60d1ee6e88956d89404c7df3c8258f46589e912988e551987", size = 4724529, upload-time = "2026-07-31T14:23:46.93Z" }, + { url = "https://files.pythonhosted.org/packages/22/f6/ec13b470172126464a86bf54d2294a46d29837fc51ba3e45d4047946fb5e/cryptography-50.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f89831ef99dd7dd169ab06d63a831adb9e20a87aac6d380266bbda5823349169", size = 5299852, upload-time = "2026-07-31T14:23:48.851Z" }, + { url = "https://files.pythonhosted.org/packages/da/3a/f05e32c99d440c9bb891ea0e36c9091891e36be5a9a87ab2ee6ea20729f6/cryptography-50.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:82148ec5bddac30b51a5b3c1945075f896fa022cb93f8e4a01e9f6ee95292c5f", size = 4734462, upload-time = "2026-07-31T14:23:50.861Z" }, + { url = "https://files.pythonhosted.org/packages/ca/dc/bd72b26be8953f80625f63151efd38eee71c76ca6cf591c08ff34615a79e/cryptography-50.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1489e263a8048bb8b6a8bac662eb2d402ea5d2b7b4699b72f385f1e2772db105", size = 4852708, upload-time = "2026-07-31T14:23:52.715Z" }, + { url = "https://files.pythonhosted.org/packages/27/20/c930314a2ab476d15dec966ec87e2e9637bb02b06106b12c0396c57bb603/cryptography-50.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7cec5b856506da6defb290f30c9ee687d5f5e8cb0bd3f6459dde43b0b4fa40ef", size = 5004179, upload-time = "2026-07-31T14:23:54.887Z" }, + { url = "https://files.pythonhosted.org/packages/32/2e/c9db68a0c4bfa28e310707527c0ee3a2bd254104d2e02e68f368e197aa4c/cryptography-50.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", size = 3840395, upload-time = "2026-07-31T14:23:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ccdc4a71a4dabae05de219404f9f4abc38e3b58422177ff93d0da05967dafa07", size = 4036009, upload-time = "2026-07-31T14:24:24.122Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c6/7a6202a534e32103a285b7834a120869557fe198d51d7cfe59754c8bda9c/cryptography-50.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:910e1d2668e7de9648f2bcee30e180db2a6b15c30f887d7c4c93ddf96e3992e3", size = 4745252, upload-time = "2026-07-31T14:24:26.118Z" }, + { url = "https://files.pythonhosted.org/packages/85/4f/0fa8c2f4428198f15d9ff8d63400e27afbf94ce833f6108da1eb3753f945/cryptography-50.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a91296cb61e8df6f86d0c19cc4068228da256bf59bf86049fbd821084565327f", size = 4728939, upload-time = "2026-07-31T14:24:27.994Z" }, + { url = "https://files.pythonhosted.org/packages/d1/63/54dd723490ba2dc09b299682c10b38db38f159728bcaae8c591b8af2f22d/cryptography-50.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e722f16708d854fe924790e051061f6704a472c3bac347b6fd88033ea8dd0dc5", size = 4748483, upload-time = "2026-07-31T14:24:30.254Z" }, + { url = "https://files.pythonhosted.org/packages/1d/dd/7c77d26285cc7f6991efce64a0f5b4f9383bfa5dd8c5033003eaf7db4cdb/cryptography-50.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d764dcf130c428ef66786f866dd750f53182bc608813489915e9fc106bb0c82f", size = 5367599, upload-time = "2026-07-31T14:24:32.457Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/f60aed34c013f317f92817b6c171c2d22a78270fa41109bd4b08af26b194/cryptography-50.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:105110f43a471dbd0060b9c9516cb8a6a79233631a04cc2ba16f28323ac6e025", size = 4762647, upload-time = "2026-07-31T14:24:34.599Z" }, + { url = "https://files.pythonhosted.org/packages/be/f3/f9a0173b139372c3a48ed98154b45cc6b9de17c789d5ab552e621c293609/cryptography-50.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:828743d939e9629bc267b8e2d08d8bb67cd4319c771a33d4b18b22dd8fb7440a", size = 4385197, upload-time = "2026-07-31T14:24:36.647Z" }, + { url = "https://files.pythonhosted.org/packages/d8/36/83bb81f6e569bc38e1e4a7bc80f29b46bb9601920bc455fc8e888f5d5742/cryptography-50.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a8183b489dc1f7f80f135780fadc1108f14b31b8a40411c7a5b17425f65f28b", size = 4748095, upload-time = "2026-07-31T14:24:39.493Z" }, + { url = "https://files.pythonhosted.org/packages/6b/16/d3008eff98c764979865834c3d386d4fd041b5f52e7f34fc29ac1a5eb515/cryptography-50.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6e7d61120573a7f2cd94cc095f9e81f6967c61ccdf194285aa143ecec8e0b708", size = 5325948, upload-time = "2026-07-31T14:24:41.556Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f8/d97f9603efda3888187bfdb893f26c41be4735c10631d05d284ee6b047c4/cryptography-50.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:37fdb0d0111f1e2ff07139dfb79f1b49531f8e213c46f1163dd7642979b58c47", size = 4762400, upload-time = "2026-07-31T14:24:43.636Z" }, + { url = "https://files.pythonhosted.org/packages/64/a2/4615c8f7d81a00b1d6e6afe19f694e1543582349fb5f4076f6cb5dc36485/cryptography-50.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87f62a3d3b9888ed0fdde100ec06aa61ca9cd44bad9057d1dff9a516b5f5bb9", size = 4878208, upload-time = "2026-07-31T14:24:45.522Z" }, + { url = "https://files.pythonhosted.org/packages/d2/1a/efcfb02f91407149a0dacffffab791f7e19bf6385f63b3666dc8b5e5c9c8/cryptography-50.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:65c2c3add92b45fd0709db8594536aea39c2a67af0e27ffcf049c498501140b7", size = 5037050, upload-time = "2026-07-31T14:24:47.697Z" }, + { url = "https://files.pythonhosted.org/packages/57/30/4a22984d4f1bdfb8c054f07a92bc176b97a3134cc1d6c4b3bffb1f3688b4/cryptography-50.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:d24fead1d4d076e1bfb006dcec392074a3cd8d7b4fc8a595aa64073b2b7a96ba", size = 3874135, upload-time = "2026-07-31T14:24:50.085Z" }, + { url = "https://files.pythonhosted.org/packages/9d/3e/e54cde8c01631a5a8226ccd617eab9e57fd5cfdad90f1a9e6bb570794631/cryptography-50.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5e34edd123674534acd70147f0ca331eaa2c74e6325fb2028c886aa26ba0b68c", size = 3963170, upload-time = "2026-07-31T14:24:51.968Z" }, + { url = "https://files.pythonhosted.org/packages/01/b6/0b9e125e90f3d2dcf599a218a899cda7326a3158cfa258723f0b398b08f6/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8eb5e1172eb569ea8a872796576e6a67c276351728b6455d5beb01242b027c6a", size = 4692441, upload-time = "2026-07-31T14:24:53.743Z" }, + { url = "https://files.pythonhosted.org/packages/53/c9/a5151588710785a96d7bc4de27d4cd62f263bbbcb203cfe29df537eb6505/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:910d11e1a385c654bf738bf3e6b8e6ed5de0f5610fcae2be9e5b398d8081d20e", size = 4699810, upload-time = "2026-07-31T14:24:55.746Z" }, + { url = "https://files.pythonhosted.org/packages/c7/1a/15b92b25eb6ce3089cd49377ae990a0f3ad485a510f968aed1f19dbdcdf2/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:62598a8a57f815db4c6259a4e97d857dab56697e7de8e8ab02352ab74da1995d", size = 4691924, upload-time = "2026-07-31T14:24:58.082Z" }, + { url = "https://files.pythonhosted.org/packages/62/15/219075012ab13e8905f3cd572204f4acb4b111df787104346b9bc0cea789/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:07479a1cb08219ab719147e742e76090c9c773321959bb94946fffdd397a6437", size = 4699593, upload-time = "2026-07-31T14:24:59.951Z" }, + { url = "https://files.pythonhosted.org/packages/8e/b5/c2c5fce26f0ee40d21bafe7f191d29a34b35a65ac4fe8a1191d1983612e9/cryptography-50.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c99c003e088647b8a5b7c145d6f78c335f6348332b62e142d411c4b63d1460b9", size = 3813796, upload-time = "2026-07-31T14:25:02.298Z" }, +] + +[[package]] +name = "environmentcommon" +version = "1.0.2" +source = { path = "../../../../packages/envcommon/whls/EnvironmentCommon-1.0.2-py2.py3-none-any.whl" } +wheels = [ + { filename = "environmentcommon-1.0.2-py2.py3-none-any.whl", hash = "sha256:a31d611ddf539fb081cfe9423a8d506d198fb5aefdb225c5534904ef9d80aaaa" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + +[[package]] +name = "google-api-core" +version = "2.30.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/502a57fb0ec752026d24df1280b162294b22a0afb98a326084f9a979138b/google_api_core-2.30.3.tar.gz", hash = "sha256:e601a37f148585319b26db36e219df68c5d07b6382cff2d580e83404e44d641b", size = 177001, upload-time = "2026-04-10T00:41:28.035Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/15/e56f351cf6ef1cfea58e6ac226a7318ed1deb2218c4b3cc9bd9e4b786c5a/google_api_core-2.30.3-py3-none-any.whl", hash = "sha256:a85761ba72c444dad5d611c2220633480b2b6be2521eca69cca2dbb3ffd6bfe8", size = 173274, upload-time = "2026-04-09T22:57:16.198Z" }, +] + +[[package]] +name = "google-api-python-client" +version = "2.198.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-auth-httplib2" }, + { name = "httplib2" }, + { name = "uritemplate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6b/53/0cd38e3a29d72ce45e27feba2ce1cd8049d69af9c48cb14fb164f1be9133/google_api_python_client-2.198.0.tar.gz", hash = "sha256:dfe3e16fb241af6e9c460a33f65085b3450e05cea09364f6b5d8997fb7e43e2a", size = 15060142, upload-time = "2026-06-25T14:32:42.953Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/92/0fc9e7a09eb240c31b879bd8d2e43f81ed1f86c4798b79ead4a083921ab3/google_api_python_client-2.198.0-py3-none-any.whl", hash = "sha256:fabac935474e817da5e662ff61bf7139439d6f92b32d332a7318a2d45931e03e", size = 15644203, upload-time = "2026-06-25T14:32:39.963Z" }, +] + +[[package]] +name = "google-auth" +version = "2.56.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyasn1-modules" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/4c/fa42116a48bab3f7a143cf5042ecff7df9c8b73f8a376203cd534d1dc966/google_auth-2.56.3.tar.gz", hash = "sha256:40e229fc901f0a305b553050e5fce562d509bee0435be053abfa91582b51b90c", size = 367110, upload-time = "2026-08-06T06:24:01.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/b3/6117b2f24065cd7e2c4f140e9a193e215f089ca8ba314cf91eb9d0b7fe0a/google_auth-2.56.3-py3-none-any.whl", hash = "sha256:8ec438808f813ad034535000261eed1067475d229d05bbf4216e78c3f2362e53", size = 259116, upload-time = "2026-08-06T06:22:51.788Z" }, +] + +[[package]] +name = "google-auth-httplib2" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "httplib2" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/11/46/79983cb738f0eb14e6ab4f43457aa9652f8d46bc4376b178f676b68c5c37/google_auth_httplib2-0.4.1.tar.gz", hash = "sha256:125b1bb4fcfdd2d97f19b673c1f46f831603d0acaffe415c8a35dadb312552a1", size = 11158, upload-time = "2026-08-06T06:24:00.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/8a/96410d0c3e02b584d1e7f5d4000b2e1710855650b226cd0601f2b154940a/google_auth_httplib2-0.4.1-py3-none-any.whl", hash = "sha256:67088a8387dc3f66016a690634f1cb9b7a48a31406f8998e088efc64203e7a12", size = 9529, upload-time = "2026-08-06T06:22:50.53Z" }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.75.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/73/74bcab964c9a7a61f2bb71e8179b0f13e6fa98f7ce00fd168aab291e4a2e/googleapis_common_protos-1.75.1.tar.gz", hash = "sha256:d3042c6c5a2d4e67113104d6b6818b59b6bd92a197f2a91508e801fe815cf071", size = 150967, upload-time = "2026-08-06T06:24:51.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/51/186c02b8549b69ccda44429cf6ff5081e4b61a602ddfe6a8020d1be31d1b/googleapis_common_protos-1.75.1-py3-none-any.whl", hash = "sha256:28a1934bcd33b9c9da66ac301a0a4227e3367f095a17d0375cb98f0a09d93b79", size = 300626, upload-time = "2026-08-06T06:23:46.696Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httplib2" +version = "0.32.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyparsing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/f5/ccf58de92d61e3ad921119668f54ed36ca1d0cf5dcc5c1657dfb164fd78b/httplib2-0.32.0.tar.gz", hash = "sha256:48a0ef30a42db65d8f3399045e1d09ab0ba66e3b9efc360d07f80ea55d286025", size = 254283, upload-time = "2026-06-26T10:13:56.265Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/a0/550eec327e5f5c7b732531c489f5307efec41f047b0d703bd4ca1e5ad2db/httplib2-0.32.0-py3-none-any.whl", hash = "sha256:dc6705cacdf3fb0a2aba7629fa33c90fd93e30035db0c157325826be177e4816", size = 93148, upload-time = "2026-06-26T10:13:54.985Z" }, +] + +[[package]] +name = "httpx" +version = "0.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, +] + +[[package]] +name = "idna" +version = "3.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5f/f7/abb373e5757eaec4b922b92f97ec8d6d7e057cf06778247604fbc4e7c3f3/idna-3.19.tar.gz", hash = "sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15", size = 215237, upload-time = "2026-08-18T05:14:24.27Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl", hash = "sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4", size = 68550, upload-time = "2026-08-18T05:14:22.343Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "integration-testing" +version = "2.2.12" +source = { path = "../../../../packages/integration_testing_whls/integration_testing-2.2.12-py3-none-any.whl" } +dependencies = [ + { name = "aiohttp" }, + { name = "environmentcommon" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "soar-sdk" }, + { name = "tipcommon" }, + { name = "yarl" }, +] +wheels = [ + { filename = "integration_testing-2.2.12-py3-none-any.whl", hash = "sha256:3882108614f63282bb27d906aba7e21f15a1b93a693b072fcc92c32b819af43e" }, +] + +[package.metadata] +requires-dist = [ + { name = "aiohttp", specifier = ">=3.12.13" }, + { name = "environmentcommon" }, + { name = "pyyaml", specifier = ">=6.0.2" }, + { name = "requests", specifier = ">=2.32.3" }, + { name = "soar-sdk" }, + { name = "tipcommon" }, + { name = "yarl", specifier = ">=1.20.1" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + +[[package]] +name = "packaging" +version = "26.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "propcache" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/f1/8a8cc1c2c7e7934ab77e0163414f736fadbc0f5e8dd9673b952355ac175b/propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78", size = 90744, upload-time = "2026-05-08T20:59:45.799Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f4/651b1225e976bd1a2ba5cfba0c29d096581c2636b437e3a9a7ab6276270a/propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959", size = 52033, upload-time = "2026-05-08T20:59:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7", size = 52754, upload-time = "2026-05-08T20:59:49.202Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fe/b3551b41bbc2f5b5bb088fc6920567cd43101253e68fbaa261339eb96fe1/propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511", size = 57573, upload-time = "2026-05-08T20:59:50.778Z" }, + { url = "https://files.pythonhosted.org/packages/83/27/ab851ebd1b7172e3e161f5f8d39e315d54a91bea246f01f4d872d3376aef/propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660", size = 60645, upload-time = "2026-05-08T20:59:52.227Z" }, + { url = "https://files.pythonhosted.org/packages/95/7d/466b3d18022e9897cbda9c735c493c5bd747d7a4c6f5ea1480b4cec434b6/propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66", size = 61563, upload-time = "2026-05-08T20:59:53.866Z" }, + { url = "https://files.pythonhosted.org/packages/27/1b/16ab7f2cf2041da2f60d156ba64c2484eadf9168075b4ff43c3ef60045af/propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b", size = 58888, upload-time = "2026-05-08T20:59:55.457Z" }, + { url = "https://files.pythonhosted.org/packages/0a/67/bb777ffd907633563bf35fd859c4ce97b0512c32f4633cf5d1eb7c33512b/propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67", size = 59253, upload-time = "2026-05-08T20:59:57.075Z" }, + { url = "https://files.pythonhosted.org/packages/b9/42/64f8d90b73fd9cdc1499b48057ff6d9cd2a98a25734c9bb62ecf07e87061/propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f", size = 57558, upload-time = "2026-05-08T20:59:58.602Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/dba5bc03c9041f2092ea55a449caf5dfe68352c6654511b29ba0654ddb69/propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c", size = 55007, upload-time = "2026-05-08T20:59:59.837Z" }, + { url = "https://files.pythonhosted.org/packages/14/c0/43f649c7aa2a77a3b100d84e9dea3a483120ecb608bfe36ce49eaff517fe/propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0", size = 60355, upload-time = "2026-05-08T21:00:01.144Z" }, + { url = "https://files.pythonhosted.org/packages/83/c0/435dafd27f1cb4a495381dae60e25883ccfe4020bb72818e8184c1678092/propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6", size = 59057, upload-time = "2026-05-08T21:00:02.401Z" }, + { url = "https://files.pythonhosted.org/packages/53/ae/6e292df9135d659944e96cb3389258e4a663e5b2b5f6c217ef0ddc8d2f73/propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27", size = 61938, upload-time = "2026-05-08T21:00:03.638Z" }, + { url = "https://files.pythonhosted.org/packages/0b/42/314ebc50d8159055411fd6b0bda322ff510e4b1f7d2e4927940ad0f6af20/propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f", size = 59731, upload-time = "2026-05-08T21:00:04.881Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9b/2da6dee38871c3c8772fabc2758325a5c9077d6d18c597737dc04dd884cd/propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0", size = 38966, upload-time = "2026-05-08T21:00:06.511Z" }, + { url = "https://files.pythonhosted.org/packages/42/4e/f17363fb58c0afe05b067361cb6d86ed2d29de6506779a27547c4d183075/propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82", size = 42135, upload-time = "2026-05-08T21:00:08.088Z" }, + { url = "https://files.pythonhosted.org/packages/c6/eb/6af6685077d22e8b33358d3c548e3282706a0b3cd85044ffba4e5dd08e3b/propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab", size = 38381, upload-time = "2026-05-08T21:00:09.692Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, +] + +[[package]] +name = "proto-plus" +version = "1.28.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/6a/056256feb4bd000869aba5c16cf2aa911572ca2a2feb185f86e457b5171e/proto_plus-1.28.3.tar.gz", hash = "sha256:5f91b30dafa6bb38d432c5557a6ee1d35ffd40b4b1e0e3ca27260448560b91d9", size = 58051, upload-time = "2026-08-06T06:24:55.581Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/3a/cfee3c50294f55a2f0f9575052dec2c2a48891ad4b1c2a133b05a87026cd/proto_plus-1.28.3-py3-none-any.whl", hash = "sha256:dc76880b8ee951cca002098574376cf71e055f9f16d9ba6570fb8a06f726d281", size = 50795, upload-time = "2026-08-06T06:23:50.653Z" }, +] + +[[package]] +name = "protobuf" +version = "7.35.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/01/9ef0afd7999eb9badb3a768b4aedd78c86d4c65cfaf1958ab276199e76b4/protobuf-7.35.1.tar.gz", hash = "sha256:ce115a26fe0c39a2c29973d914d327e516a6455464489fe3cd1e51a1b354f81a", size = 458717, upload-time = "2026-06-11T21:55:40.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/03/8aeeb7458d22546bf64b5250ca1daeb5ff757d900e8e4a7476c6f0db843e/protobuf-7.35.1-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:24f857477359a85c0c235261b8ba905fd51b2562f4a64ca1df5473f29850cbf6", size = 433226, upload-time = "2026-06-11T21:55:31.719Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/dfb89eb0e652a1ff073c39a59fb5e3a83cfe9b57a2c83fa6d78270101767/protobuf-7.35.1-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:11d6b0ec246892d85215b0a13ca6e0233cf5284b68f0ac02646427f4ff88a799", size = 328847, upload-time = "2026-06-11T21:55:34.035Z" }, + { url = "https://files.pythonhosted.org/packages/0f/58/dc12f2cd484951524af6e3382c785869b9b3fb5e52ee95ae23add53ee8f9/protobuf-7.35.1-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:b73f9489a4b8b1c9cb1f8ed951c736392592edb24b9d6819f36d2e10b171d5b4", size = 344030, upload-time = "2026-06-11T21:55:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/e4/be/5b3cfe508bfab6761414ff944e3366eb13be4fd71efcd69450f89ba39f43/protobuf-7.35.1-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:74758715c53d7158fb76caf4f0cfdacc5329a4b1bb994f865d6cf302d413a1c4", size = 327130, upload-time = "2026-06-11T21:55:35.921Z" }, + { url = "https://files.pythonhosted.org/packages/d8/bc/6d6c7ba8709c85f8f2c390b2b118d6fb08a783676a572271851bf45a7d22/protobuf-7.35.1-cp310-abi3-win32.whl", hash = "sha256:353652e4efd0bca5b5fc2656abf8307ef351f0cf938c9eba09f0e09c20a25c30", size = 428945, upload-time = "2026-06-11T21:55:37.034Z" }, + { url = "https://files.pythonhosted.org/packages/0a/19/8d0cb6f20a1ef7b18f1c8986ad5783f22f84cce39c6ce9a6e645ea55192e/protobuf-7.35.1-cp310-abi3-win_amd64.whl", hash = "sha256:230a75ddfc2de4806e56696ce9640c1cdfdb6543b7cfce98d42a4c0a0e7bdb87", size = 439996, upload-time = "2026-06-11T21:55:38.123Z" }, + { url = "https://files.pythonhosted.org/packages/19/c7/5f7c636ec43e0c545e28d1f1db71990108306f7bdcb89f069ba97e428e7f/protobuf-7.35.1-py3-none-any.whl", hash = "sha256:4bc97768d8fe4ad6743c8a19403e314511ed9f6d13205b687e52421c023ac1b9", size = 171659, upload-time = "2026-06-11T21:55:39.155Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a4/9a/23310166d960def5897e91fe20e5b724601b02a22e84ba1f94232c0b7f67/pyasn1-0.6.4.tar.gz", hash = "sha256:9c447d8431c947fe4c8febc4ed9e760bc29011a5b01e5c74b67025bd9fb8ce81", size = 151262, upload-time = "2026-07-09T01:12:33.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3b/6163796d69c3977d1e4287bea4a6979161cbbdd170ebb430511e8e1999ce/pyasn1-0.6.4-py3-none-any.whl", hash = "sha256:deda9277cfd454080ec40b207fb6df82206a3a2688735233cdcd8d3d565f088b", size = 84410, upload-time = "2026-07-09T01:12:32.92Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + +[[package]] +name = "pycryptodome" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, + { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, + { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, + { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, + { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, + { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, + { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, + { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, +] + +[[package]] +name = "pygments" +version = "2.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" }, +] + +[[package]] +name = "pyopenssl" +version = "26.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/e8/7325d258199b159eb2c03fe32107533e2832e70e63f4fb88a6aa00023201/pyopenssl-26.4.0.tar.gz", hash = "sha256:28dfcce0162b9211413e26dfbfdf1d24317fbeba18fc93c12400a1856b2a0bc7", size = 182046, upload-time = "2026-08-01T19:50:50.512Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/ad/2cf6d3fa2fae5c79e1ed9960c0d42badd0f94d81dd12b50604cdc839e648/pyopenssl-26.4.0-py3-none-any.whl", hash = "sha256:f0eb0cb2d581d3ad2b9c489468485e7f2ab6727d08401bcf9d824c3caddf3c1c", size = 56026, upload-time = "2026-08-01T19:50:48.94Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pytest" +version = "9.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, +] + +[[package]] +name = "pytest-json-report" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, + { name = "pytest-metadata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/d3/765dae9712fcd68d820338908c1337e077d5fdadccd5cacf95b9b0bea278/pytest-json-report-1.5.0.tar.gz", hash = "sha256:2dde3c647851a19b5f3700729e8310a6e66efb2077d674f27ddea3d34dc615de", size = 21241, upload-time = "2022-03-15T21:03:10.2Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/35/d07400c715bf8a88aa0c1ee9c9eb6050ca7fe5b39981f0eea773feeb0681/pytest_json_report-1.5.0-py3-none-any.whl", hash = "sha256:9897b68c910b12a2e48dd849f9a284b2c79a732a8a9cb398452ddd23d3c8c325", size = 13222, upload-time = "2022-03-15T21:03:08.65Z" }, +] + +[[package]] +name = "pytest-metadata" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/85/8c969f8bec4e559f8f2b958a15229a35495f5b4ce499f6b865eac54b878d/pytest_metadata-3.1.1.tar.gz", hash = "sha256:d2a29b0355fbc03f168aa96d41ff88b1a3b44a3b02acbe491801c98a048017c8", size = 9952, upload-time = "2024-02-12T19:38:44.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/43/7e7b2ec865caa92f67b8f0e9231a798d102724ca4c0e1f414316be1c1ef2/pytest_metadata-3.1.1-py3-none-any.whl", hash = "sha256:c8e0844db684ee1c798cfa38908d20d67d0463ecb6137c72e91f418558dd5f4b", size = 11428, upload-time = "2024-02-12T19:38:42.531Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pytz" +version = "2026.3.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/48/fb042503b6ca6cd271261dc559fd6432f7d8c713153e9ec5c591af4dfc1c/pytz-2026.3.post1.tar.gz", hash = "sha256:2211d3fcf9a797d3405cac96ac7f61d80e6a644f72a3309607282fe8a2010c5d", size = 319745, upload-time = "2026-07-25T15:12:07.385Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/7b/39c34ca613b0b198cb866466651b26b045e2009864c5183c979a3b83f383/pytz-2026.3.post1-py2.py3-none-any.whl", hash = "sha256:dd95840dd199baea12d9cc096a1d452caa6596a1c1e4b5f3dbd1541855d5e815", size = 508283, upload-time = "2026-07-25T15:12:05.782Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", size = 185826, upload-time = "2025-09-25T21:31:58.655Z" }, + { url = "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", size = 175577, upload-time = "2025-09-25T21:32:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", size = 775556, upload-time = "2025-09-25T21:32:01.31Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", size = 882114, upload-time = "2025-09-25T21:32:03.376Z" }, + { url = "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", size = 806638, upload-time = "2025-09-25T21:32:04.553Z" }, + { url = "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", size = 767463, upload-time = "2025-09-25T21:32:06.152Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", size = 794986, upload-time = "2025-09-25T21:32:07.367Z" }, + { url = "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl", hash = "sha256:8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", size = 142543, upload-time = "2025-09-25T21:32:08.95Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", size = 158763, upload-time = "2025-09-25T21:32:09.96Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "soar-sdk" +version = "0.2.0" +source = { git = "https://github.com/chronicle/soar-sdk.git#5c563da488afa729eeba2195d3569de1370ab106" } +dependencies = [ + { name = "arrow" }, + { name = "chardet" }, + { name = "cryptography" }, + { name = "google-auth" }, + { name = "pyopenssl" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "six" }, +] + +[[package]] +name = "tipcommon" +version = "2.2.12" +source = { path = "../../../../packages/tipcommon/whls/TIPCommon-2.2.12-py2.py3-none-any.whl" } +dependencies = [ + { name = "google-api-python-client" }, + { name = "google-auth" }, + { name = "google-auth-httplib2" }, + { name = "httpx" }, + { name = "pycryptodome" }, + { name = "requests" }, +] +wheels = [ + { filename = "tipcommon-2.2.12-py2.py3-none-any.whl", hash = "sha256:48f5ebffdfc0d61d4429d8c7861ee5bfae1b66c78b83ed9664024c4d4454b6a7" }, +] + +[package.metadata] +requires-dist = [ + { name = "google-api-python-client" }, + { name = "google-auth" }, + { name = "google-auth-httplib2" }, + { name = "httpx" }, + { name = "pycryptodome" }, + { name = "requests" }, +] + +[[package]] +name = "typing-extensions" +version = "4.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" }, +] + +[[package]] +name = "uritemplate" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, +] + +[[package]] +name = "urllib3" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size = 433602, upload-time = "2026-05-07T16:13:18.596Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size = 131087, upload-time = "2026-05-07T16:13:17.151Z" }, +] + +[[package]] +name = "yarl" +version = "1.24.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/db/3cb5df059756a45761cc3dee8fd25ec82b83a6585ea3542b969fda850f99/yarl-1.24.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c1fe720934a16ea8e7146175cba2126f87f54912c8c5435e7f7c7a51ef808d3", size = 135043, upload-time = "2026-07-20T02:04:52.39Z" }, + { url = "https://files.pythonhosted.org/packages/44/f8/767d6bd5a03db63bc467df2fb56d6fafeae9667d74aea92cd6af399f828b/yarl-1.24.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c687ed078e145f5fd53a14854beff320e1d2ab76df03e2009c98f39a0f68f39a", size = 96942, upload-time = "2026-07-20T02:04:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:709f1efed56c4a145793c046cd4939f9959bcd818979a787b77d8e09c57a0840", size = 97046, upload-time = "2026-07-20T02:04:56.638Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7a/b410dbe39b6255c55fb2a2bcee96eb844d0789235ddc381a889a90dc72d6/yarl-1.24.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874019bd513008b009f58657134e5d0c5e030b3559bd0553976837adf52fe966", size = 110512, upload-time = "2026-07-20T02:04:58.955Z" }, + { url = "https://files.pythonhosted.org/packages/83/c7/da591971f78a5617e1f21f5699858ebccd836fe181a6493788ffc91ba69b/yarl-1.24.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4582acf7ef76482f6f511ebaf1946dae7f2e85ec4728b81a678c01df63bd723", size = 102454, upload-time = "2026-07-20T02:05:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8e/73b0ed4de47289a78a96045d76d1cfe5e41848bf0da59ce25b2ec87ee05d/yarl-1.24.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cabe6546e41dabe439999a23fcb5246e0c3b595b4315b96ef755252be90caeb", size = 117617, upload-time = "2026-07-20T02:05:02.325Z" }, + { url = "https://files.pythonhosted.org/packages/cf/14/b744747bc4f57a8d55bd744df463457524583e1e9f7538b5ace0346ab92e/yarl-1.24.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:17f57620f5475b3c69109376cc87e42a7af5db13c9398e4292772a706ff10780", size = 116135, upload-time = "2026-07-20T02:05:04.05Z" }, + { url = "https://files.pythonhosted.org/packages/66/ca/95aa4d0e5b7ea4f20e4d577c42d001ed9df207569fdb063cc5ed4ebb496b/yarl-1.24.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:570fec8fbd22b032733625f03f10b7ff023bc399213db15e72a7acaef28c2f4e", size = 111935, upload-time = "2026-07-20T02:05:05.738Z" }, + { url = "https://files.pythonhosted.org/packages/72/0d/d2ad8d6b147832d177a4e720ba1962fe686eb0913b74503b3eca094b8bba/yarl-1.24.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5fede79c6f73ff2c3ef822864cb1ada23196e62756df53bc6231d351a49516a2", size = 110010, upload-time = "2026-07-20T02:05:07.471Z" }, + { url = "https://files.pythonhosted.org/packages/50/18/eb335e4120903903f4865041355ae46256a2406eb2865bc24827f4f27b61/yarl-1.24.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ccf9aca873b767977c73df497a85dbedee4ee086ae9ae49dc461333b9b79f58", size = 110058, upload-time = "2026-07-20T02:05:09.246Z" }, + { url = "https://files.pythonhosted.org/packages/44/70/97353add32c62ad6f206d948ac5a5ee84398225e534dc6ed6433d1b335b6/yarl-1.24.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ad5d8201d310b031e6cd839d9bac2d4e5a01533ce5d3d5b50b7de1ef3af1de61", size = 103308, upload-time = "2026-07-20T02:05:11.31Z" }, + { url = "https://files.pythonhosted.org/packages/68/39/5e7398d4b6f6b3c9062823ebc60802df5b272e3fe9e788f9734c6ee46c85/yarl-1.24.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:841f0852f48fefea3b12c9dfec00704dfa3aef5215d0e3ce564bb3d7cd8d57c6", size = 116898, upload-time = "2026-07-20T02:05:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/09e52f2239e8b96357eccca05915382e4ba5405ebfb623b6036040d99654/yarl-1.24.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:9baafc71b04f8f4bb0703b21d6fc9f0c30b346c636a532ff16ec8491a5ea4b1f", size = 109400, upload-time = "2026-07-20T02:05:14.821Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6a/e94133d4c2d1a14d2384310bf3e79d9cf32c9d1eae1c6f034fb80d098fa1/yarl-1.24.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d897129df1a22b12aeed2c2c98df0785a2e8e6e0bde87b389491d0025c187077", size = 115934, upload-time = "2026-07-20T02:05:17.78Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/34955ed967b976fc38edcbb6d538dee79dbda4cb7fc7f72a0907a7c78e0f/yarl-1.24.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd625535328fd9882374356269227670189adfcc6a2d90284f323c05862eecbd", size = 112178, upload-time = "2026-07-20T02:05:19.675Z" }, + { url = "https://files.pythonhosted.org/packages/f5/46/d7bd3a8859d47dcfaffd7127af7076032a7da278a9a02e17b5f37bfb6712/yarl-1.24.5-cp311-cp311-win_amd64.whl", hash = "sha256:f4239bbec5a3577ddb49e4b50aeb32d8e5792098262ae2f63723f916a29b1a25", size = 97544, upload-time = "2026-07-20T02:05:21.523Z" }, + { url = "https://files.pythonhosted.org/packages/01/69/c1bfd21e32c638974ea2c542a0b8c53ef1fa9eff336020f5d014f9503ff2/yarl-1.24.5-cp311-cp311-win_arm64.whl", hash = "sha256:3ac6aff147deb9c09461b2d4bbdf6256831198f5d8a23f5d37138213090b6d8a", size = 93359, upload-time = "2026-07-20T02:05:23.493Z" }, + { url = "https://files.pythonhosted.org/packages/61/02/962c1cbfc401a30c1d034dc67ff395f64b52302c6d62de556c1fca99acc0/yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7", size = 58612, upload-time = "2026-07-20T02:07:43.461Z" }, +] diff --git a/content/response_integrations/google/azure_monitor/widgets/search_logs.html b/content/response_integrations/google/azure_monitor/widgets/search_logs.html new file mode 100644 index 0000000000..f42df4ff80 --- /dev/null +++ b/content/response_integrations/google/azure_monitor/widgets/search_logs.html @@ -0,0 +1,1006 @@ + + + + + +
+ + + + +