diff --git a/CHANGELOG.md b/CHANGELOG.md index 9592443e..ddd09982 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Zscaler Python SDK Changelog +## 1.9.15 (February 16, 2026) + +### Notes + +- Python Versions: **v3.9, v3.10, v3.11, v3.12** + +### Enhancements: + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Added support to the following ZIA Endpoints: + - Added `GET /customFileTypes` Retrieves the list of custom file types. Custom file types can be configured as rule conditions in different ZIA policies. + - Added `POST /customFileTypes` Adds a new custom file type. + - Added `PUT /customFileTypes` Updates information for a custom file type based on the specified ID + - Added `DELETE /customFileTypes/{id}` Deletes a custom file type based on the specified ID + - Added `GET /customFileTypes/count` Retrieves the count of custom file types available + - Added `GET /fileTypeCategories` Retrieves the list of all file types, including predefined and custom file types + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Added new attributes `url_type`, `regex_patterns`, and `regex_patterns_retaining_parent_category` to `zia_url_categories` resource to specify whether the category uses exact URLs or regex patterns. Supported values are `EXACT` and `REGEX`. See [Zscaler Release Notes](https://help.zscaler.com/zia/release-upgrade-summary-2026) for details. To enable this feature, contact Zscaler Support. + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Added new attributes to ZIA: + * `ipscontrolpolicies`: `eunEnabled`, and `eunTemplateId` + * `firewalldnscontrolpolicies`: `isWebEunEnabled` and `defaultDnsRuleNameUsed` + * `dlp_web_rules`: `eunTemplateId` + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Added new `tags` field to ZPA `applicationsegment` + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Added new attributes to all ZPA Application Segments: + * `policyStyle` to enable `FQDN-to-IP Policy Evaluation` + +### Bug Fixes + +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Fixed URL formatting parameter for ZIA resource `casb_dlp_rules` +* [PR #459](https://github.com/zscaler/zscaler-sdk-python/pull/459) - Fixed URL formatting parameter for ZIA function `update_dc_exclusion`. API requires the ID as JSON attribute and not as a parameter. + ## 1.9.14 (February 10, 2026) ### Notes diff --git a/docsrc/conf.py b/docsrc/conf.py index fb0faab6..57ba6a38 100644 --- a/docsrc/conf.py +++ b/docsrc/conf.py @@ -28,9 +28,9 @@ html_title = "" # The short X.Y version -version = "1.9.13" +version = "1.9.15" # The full version, including alpha/beta/rc tags -release = "1.9.13" +release = "1.9.15" # -- General configuration --------------------------------------------------- diff --git a/docsrc/zs/guides/release_notes.rst b/docsrc/zs/guides/release_notes.rst index 94351d35..b309bf87 100644 --- a/docsrc/zs/guides/release_notes.rst +++ b/docsrc/zs/guides/release_notes.rst @@ -6,6 +6,44 @@ Release Notes Zscaler Python SDK Changelog ---------------------------- + +1.9.15 (February 16, 2026) +--------------------------- + +Notes +----- + +- Python Versions: **v3.9, v3.10, v3.11, v3.12** + +Enhancements: +------------- + +(`#459 `_) - Added support to the following ZIA Endpoints: + - Added `GET /customFileTypes` Retrieves the list of custom file types. Custom file types can be configured as rule conditions in different ZIA policies. + - Added `POST /customFileTypes` Adds a new custom file type. + - Added `PUT /customFileTypes` Updates information for a custom file type based on the specified ID + - Added `DELETE /customFileTypes/{id}` Deletes a custom file type based on the specified ID + - Added `GET /customFileTypes/count` Retrieves the count of custom file types available + - Added `GET /fileTypeCategories` Retrieves the list of all file types, including predefined and custom file types + +(`#459 `_) - Added new attributes `url_type`, `regex_patterns`, and `regex_patterns_retaining_parent_category` to `zia_url_categories` resource to specify whether the category uses exact URLs or regex patterns. Supported values are `EXACT` and `REGEX`. See [Zscaler Release Notes](https://help.zscaler.com/zia/release-upgrade-summary-2026) for details. To enable this feature, contact Zscaler Support. + +(`#459 `_) - Added new attributes to ZIA: + * `ipscontrolpolicies`: `eunEnabled`, and `eunTemplateId` + * `firewalldnscontrolpolicies`: `isWebEunEnabled` and `defaultDnsRuleNameUsed` + * `dlp_web_rules`: `eunTemplateId` + +(`#459 `_) - Added new `tags` field to ZPA `applicationsegment` + +(`#459 `_) - Added new attributes to all ZPA Application Segments: + * `policyStyle` to enable `FQDN-to-IP Policy Evaluation` + +Bug Fixes: +---------- + +(`#459 `_) - Fixed URL formatting parameter for ZIA resource `casb_dlp_rules` +(`#459 `_) - Fixed URL formatting parameter for ZIA function `update_dc_exclusion`. API requires the ID as JSON attribute and not as a parameter. + 1.9.14 (February 10, 2026) --------------------------- diff --git a/docsrc/zs/zia/custom_file_types.rst b/docsrc/zs/zia/custom_file_types.rst new file mode 100644 index 00000000..ad6b44d7 --- /dev/null +++ b/docsrc/zs/zia/custom_file_types.rst @@ -0,0 +1,14 @@ +custom_file_types +------------------- + +The following methods allow for interaction with the ZIA +Custom File Types API endpoints. + +Methods are accessible via ``zia.custom_file_types`` + +.. _zia-custom_file_types: + +.. automodule:: zscaler.zia.custom_file_types + :members: + :undoc-members: + :show-inheritance: diff --git a/pyproject.toml b/pyproject.toml index 5065a0c8..47769aa3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "zscaler-sdk-python" -version = "1.9.14" +version = "1.9.15" description = "Official Python SDK for the Zscaler Products" authors = ["Zscaler, Inc. "] license = "MIT" diff --git a/tests/integration/zia/test_casb_dlp_rules.py b/tests/integration/zia/test_casb_dlp_rules.py index e5b5410d..56f7ca6a 100644 --- a/tests/integration/zia/test_casb_dlp_rules.py +++ b/tests/integration/zia/test_casb_dlp_rules.py @@ -48,7 +48,7 @@ def test_casb_dlp_rules(self, fs): # Step 2: List CASB DLP rules by type - ITSM try: typed_rules, _, error = client.zia.casb_dlp_rules.list_rules( - query_params={'rule_type': rule_type} + rule_type=rule_type ) assert error is None, f"Error listing CASB DLP rules by type: {error}" except Exception as exc: @@ -57,7 +57,7 @@ def test_casb_dlp_rules(self, fs): # Step 3: List CASB DLP rules by type - FILE try: file_rules, _, error = client.zia.casb_dlp_rules.list_rules( - query_params={'rule_type': 'OFLCASB_DLP_FILE'} + rule_type='OFLCASB_DLP_FILE' ) except Exception: pass @@ -65,7 +65,7 @@ def test_casb_dlp_rules(self, fs): # Step 4: List CASB DLP rules by type - EMAIL try: email_rules, _, error = client.zia.casb_dlp_rules.list_rules( - query_params={'rule_type': 'OFLCASB_DLP_EMAIL'} + rule_type='OFLCASB_DLP_EMAIL' ) except Exception: pass @@ -130,7 +130,7 @@ def test_casb_dlp_rules(self, fs): finally: if rule_id: try: - client.zia.casb_dlp_rules.delete_rule(rule_type=rule_type, rule_id=rule_id) + client.zia.casb_dlp_rules.delete_rule(rule_id=rule_id, rule_type=rule_type) except Exception: pass diff --git a/zscaler/__init__.py b/zscaler/__init__.py index abab34c2..763cb678 100644 --- a/zscaler/__init__.py +++ b/zscaler/__init__.py @@ -29,7 +29,7 @@ __contributors__ = [ "William Guilherme", ] -__version__ = "1.9.14" +__version__ = "1.9.15" from zscaler.oneapi_client import Client as ZscalerClient # noqa diff --git a/zscaler/zia/casb_dlp_rules.py b/zscaler/zia/casb_dlp_rules.py index cac141e0..4343be5e 100644 --- a/zscaler/zia/casb_dlp_rules.py +++ b/zscaler/zia/casb_dlp_rules.py @@ -32,21 +32,23 @@ def __init__(self, request_executor: "RequestExecutor") -> None: def list_rules( self, + rule_type: str, query_params: Optional[dict] = None, ) -> APIResult[List[CasbdDlpRules]]: """ Returns a list of all Casb DLP Rules for the specified rule type. Args: - query_params {dict}: Map of query parameters for the request. + rule_type (str): The type of rules to retrieve (e.g., "OFLCASB_DLP_ITSM"). + Required by the API. - ``[query_params.search]`` {str}: Search string for filtering results. + Supported Values: `ANY`, `NONE`, `OFLCASB_DLP_FILE`, `OFLCASB_DLP_EMAIL`, `OFLCASB_DLP_CRM`, + `OFLCASB_DLP_ITSM`, `OFLCASB_DLP_COLLAB`, `OFLCASB_DLP_REPO`, `OFLCASB_DLP_STORAGE`, + `OFLCASB_DLP_GENAI` - ``[query_params.rule_type]`` {str}: The type of rules to retrieve (e.g., "OFLCASB_DLP_ITSM"). + query_params (dict, optional): Additional query parameters for the request. - Supported Values: `ANY`, `NONE`, `OFLCASB_DLP_FILE`, `OFLCASB_DLP_EMAIL`, `OFLCASB_DLP_CRM`, - `OFLCASB_DLP_ITSM`, `OFLCASB_DLP_COLLAB`, `OFLCASB_DLP_REPO`, `OFLCASB_DLP_STORAGE`, - `OFLCASB_DLP_GENAI` + ``[query_params.search]`` {str}: Search string for filtering results. Returns: tuple: The list of Casb DLP Rules. @@ -55,13 +57,21 @@ def list_rules( List all rules for a specific type:: >>> rules_list, _, error = client.zia.casb_dlp_rules.list_rules( - ... query_params={'rule_type': 'OFLCASB_DLP_ITSM'}) + ... rule_type='OFLCASB_DLP_ITSM' + ... ) >>> if error: - ... print(f"Error listing casb dlp rules rules: {error}") + ... print(f"Error listing casb dlp rules: {error}") ... return ... print(f"Total rules found: {len(rules_list)}") ... for rule in rules_list: ... print(rule.as_dict()) + + List rules with optional search filter:: + + >>> rules_list, _, error = client.zia.casb_dlp_rules.list_rules( + ... rule_type='OFLCASB_DLP_ITSM', + ... query_params={'search': 'MyRule'} + ... ) """ http_method = "get".upper() api_url = format_url( @@ -71,12 +81,15 @@ def list_rules( """ ) - query_params = query_params or {} + params = {"ruleType": rule_type} + if query_params: + extra = {k: v for k, v in query_params.items() if k != "rule_type"} + params.update(extra) body = {} headers = {} - request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params) + request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=params) if error: return (None, None, error) @@ -98,15 +111,16 @@ def list_rules( def get_rule( self, rule_id: int, - rule_type: str, + rule_type: Optional[str] = None, ) -> APIResult[dict]: """ - Returns information for the specified Casb DLP Rule under the specified rule type. + Returns information for the specified Casb DLP Rule. Args: rule_id (int): The unique identifier for the Casb DLP Rule. - rule_type (str): The type of the rule (e.g., "OFLCASB_DLP_ITSM"). + rule_type (str, optional): The type of the rule (e.g., "OFLCASB_DLP_ITSM"). + Optional for GET by ID; when provided, passed as query parameter. Supported Values: `ANY`, `NONE`, `OFLCASB_DLP_FILE`, `OFLCASB_DLP_EMAIL`, `OFLCASB_DLP_CRM`, `OFLCASB_DLP_ITSM`, `OFLCASB_DLP_COLLAB`, `OFLCASB_DLP_REPO`, `OFLCASB_DLP_STORAGE`, @@ -116,11 +130,17 @@ def get_rule( :obj:`Tuple`: The resource record for the Casb DLP Rule. Examples: - Get a specific rule by ID and type:: + Get a specific rule by ID:: >>> fetched_rule, _, error = client.zia.casb_dlp_rules.get_rule( - ... rule_type='OFLCASB_DLP_ITSM', - ... rule_id='1070199' + ... rule_id=1070199 + ... ) + + Get a rule by ID with optional rule type:: + + >>> fetched_rule, _, error = client.zia.casb_dlp_rules.get_rule( + ... rule_id=1070199, + ... rule_type='OFLCASB_DLP_ITSM' ... ) >>> if error: ... print(f"Error fetching rule by ID: {error}") @@ -135,7 +155,7 @@ def get_rule( """ ) - params = {"ruleType": rule_type} + params = {"ruleType": rule_type} if rule_type else {} body = {} headers = {} @@ -169,9 +189,9 @@ def list_all_rules( tuple: The list of all Casb DLP Rules. Examples: - List all rules for a specific type:: + List all rules:: - >>> rules_list, _, error = client.zia.casb_dlp_rules.list_all_rules( + >>> rules_list, _, error = client.zia.casb_dlp_rules.list_all_rules() >>> if error: ... print(f"Error listing all casb dlp rules rules: {error}") ... return @@ -574,10 +594,9 @@ def update_rule(self, rule_id: str, **kwargs) -> APIResult[dict]: ... }, ... ) >>> if error: - ... print(f"Error adding rule: {error}") + ... print(f"Error updating rule: {error}") ... return - ... print(f"Rule added successfully: {added_rule.as_dict()}") - ... ) + ... print(f"Rule updated successfully: {updated_rule.as_dict()}") """ http_method = "put".upper() api_url = format_url( @@ -614,14 +633,15 @@ def update_rule(self, rule_id: str, **kwargs) -> APIResult[dict]: return (None, response, error) return (result, response, None) - def delete_rule(self, rule_type: str, rule_id: int) -> APIResult[dict]: + def delete_rule(self, rule_id: int, rule_type: Optional[str] = None) -> APIResult[dict]: """ Deletes the specified casb dlp rules. Args: rule_id (int): The unique identifier for the casb dlp rules. - rule_type (str): The type of the rule (e.g., "OFLCASB_DLP_ITSM"). + rule_type (str, optional): The type of the rule (e.g., "OFLCASB_DLP_ITSM"). + Optional for DELETE; when provided, passed as query parameter. Supported Values: `ANY`, `NONE`, `OFLCASB_DLP_FILE`, `OFLCASB_DLP_EMAIL`, `OFLCASB_DLP_CRM`, `OFLCASB_DLP_ITSM`, `OFLCASB_DLP_COLLAB`, `OFLCASB_DLP_REPO`, `OFLCASB_DLP_STORAGE`, @@ -631,14 +651,22 @@ def delete_rule(self, rule_type: str, rule_id: int) -> APIResult[dict]: :obj:`int`: The status code for the operation. Examples: - >>> _, _, error = client.zia.casb_dlp_rules.delete_rule( - ... rule_type='OFLCASB_DLP_ITSM', - ... rule_id='1072324' - ... ) - >>> if error: - ... print(f"Error deleting rule: {error}") - ... return - ... print(f"Rule with ID 1072324 deleted successfully.") + Delete a rule by ID:: + + >>> _, _, error = client.zia.casb_dlp_rules.delete_rule( + ... rule_id=1072324 + ... ) + + Delete a rule by ID with optional rule type:: + + >>> _, _, error = client.zia.casb_dlp_rules.delete_rule( + ... rule_id=1072324, + ... rule_type='OFLCASB_DLP_ITSM' + ... ) + >>> if error: + ... print(f"Error deleting rule: {error}") + ... return + ... print(f"Rule with ID 1072324 deleted successfully.") """ http_method = "delete".upper() api_url = format_url( @@ -647,7 +675,7 @@ def delete_rule(self, rule_type: str, rule_id: int) -> APIResult[dict]: /casbDlpRules/{rule_id} """ ) - params = {"ruleType": rule_type} + params = {"ruleType": rule_type} if rule_type else {} request, error = self._request_executor.create_request(http_method, api_url, params=params) if error: diff --git a/zscaler/zia/cloud_firewall.py b/zscaler/zia/cloud_firewall.py index e9fba8db..355a8f8e 100644 --- a/zscaler/zia/cloud_firewall.py +++ b/zscaler/zia/cloud_firewall.py @@ -68,7 +68,7 @@ def list_ip_destination_groups( Gets a list of all IP destination groups by excluding specific type. >>> group_list, response, error = zia.cloud_firewall.list_ip_destination_groups( - query_params={"exclude_type": 'DSTN_DOMAIN'}): + query_params={"name": 'Group01'}): ... if error: ... print(f"Error listing ip destination groups: {error}") ... return diff --git a/zscaler/zia/custom_file_types.py b/zscaler/zia/custom_file_types.py new file mode 100644 index 00000000..53ca83a3 --- /dev/null +++ b/zscaler/zia/custom_file_types.py @@ -0,0 +1,345 @@ +""" +Copyright (c) 2023, Zscaler Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +""" + +from typing import Dict, List, Optional, Any, Union +from zscaler.request_executor import RequestExecutor +from zscaler.utils import format_url +from zscaler.api_client import APIClient +from zscaler.zia.models.custom_file_types import CustomFileTypes +from zscaler.types import APIResult + + +class CustomFileTypesAPI(APIClient): + + _zia_base_endpoint = "/zia/api/v1" + + def __init__(self, request_executor: "RequestExecutor") -> None: + super().__init__() + self._request_executor: RequestExecutor = request_executor + + def list_custom_file_types( + self, + query_params: Optional[dict] = None, + ) -> APIResult[List[CustomFileTypes]]: + """ + Retrieves the list of Custom file types can be configured as rule conditions in different ZIA policies. + + Args: + query_params {dict}: Map of query parameters for the request. + + ``[query_params.search]`` {str}: Search string for filtering results. + ``[query_params.page]`` {int}: Specifies the page offset + ``[query_params.page_size]`` {int}: Specifies the page size. Default value: 250 + + Returns: + tuple: A tuple containing (list of custom file types instances, Response, error). + + Example: + List all custom file types with a specific page size: + + >>> files_list, response, error = zia.custom_file_types.list_custom_file_types( + ... query_params={"page_size": 50} + ... ) + >>> for file in files_list: + ... print(file.as_dict()) + """ + http_method = "get".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes + """ + ) + + query_params = query_params or {} + + body = {} + headers = {} + + request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request) + + if error: + return (None, response, error) + + try: + result = [] + for item in response.get_results(): + result.append(CustomFileTypes(self.form_response_body(item))) + except Exception as error: + return (None, response, error) + + return (result, response, None) + + def get_custom_file_tytpe( + self, + file_id: int, + ) -> APIResult[dict]: + """ + Retrieves information about a custom file type based on the specified ID + + Args: + file_id (str): The unique identifier for the custom file types filter. + + Returns: + tuple: A tuple containing (custom file types instance, Response, error). + + Example: + Retrieve a custom file types by its ID: + + >>> file, response, error = zia.custom_file_types.get_custom_file_tytpe(file_id=123456) + >>> if not error: + ... print(file.as_dict()) + """ + http_method = "get".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes/{file_id} + """ + ) + + body = {} + headers = {} + + request, error = self._request_executor.create_request(http_method, api_url, body, headers) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request, CustomFileTypes) + + if error: + return (None, response, error) + + try: + result = CustomFileTypes(self.form_response_body(response.get_body())) + except Exception as error: + return (None, response, error) + return (result, response, None) + + def add_custom_file_type( + self, + **kwargs, + ) -> APIResult[dict]: + """ + Adds a new custom file type. + + Args: + name (str): Custom file type name + + Keyword Args: + name (str): Custom file type name + description (str): Additional information about the custom file type, if any. + + extension (str): Specifies the file type extension. + The maximum extension length is 10 characters. + Existing Zscaler extensions cannot be added to custom file types. + + file_type_id (int): File type ID. + This ID is assigned and maintained for all file types including predefined and custom file types + and this value is different from the custom file type ID. + + Returns: + tuple: new custom file type resource record. + + Example: + add an a new custom file type: + + >>> zia.custom_file_types.add_custom_file_type( + ... name='FileType02', + ... description='FileType02', + ... extension='tf' + ... ) + """ + http_method = "post".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes + """ + ) + + body = kwargs + + request, error = self._request_executor.create_request( + method=http_method, + endpoint=api_url, + body=body, + ) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request, CustomFileTypes) + if error: + return (None, response, error) + + try: + result = CustomFileTypes(self.form_response_body(response.get_body())) + except Exception as error: + return (None, response, error) + return (result, response, None) + + def update_custom_file_type(self, file_id: int, **kwargs) -> APIResult[dict]: + """ + Updates information for a custom file type based on the specified ID + + Args: + file_id (int): The unique ID for the custom file type that is being updated. + **kwargs: Optional keyword args. + + Keyword Args: + name (str): Custom file type name + description (str): Additional information about the custom file type, if any. + + extension (str): Specifies the file type extension. + The maximum extension length is 10 characters. + Existing Zscaler extensions cannot be added to custom file types. + + file_type_id (int): File type ID. + This ID is assigned and maintained for all file types including predefined and custom file types + and this value is different from the custom file type ID. + + Returns: + tuple: update an existing custom file type resource record. + + Example: + Update an existing custom file type to change its name and action: + + >>> zia.custom_file_types.update_custom_file_type( + ... file_id=123456, + ... name='FileType02', + ... description='FileType02', + ... extension='tf' + ... ) + """ + http_method = "put".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes/{file_id} + """ + ) + + body = kwargs + + request, error = self._request_executor.create_request( + method=http_method, + endpoint=api_url, + body=body, + ) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request, CustomFileTypes) + if error: + return (None, response, error) + + try: + result = CustomFileTypes(self.form_response_body(response.get_body())) + except Exception as error: + return (None, response, error) + return (result, response, None) + + def delete_custom_file_type(self, file_id: int) -> APIResult[dict]: + """ + Deletes a custom file type based on the specified ID + + Args: + file_id (int): The unique identifier for the custom file types + + Returns: + :obj:`int`: The status code for the operation. + + Examples: + >>> zia.custom_file_types.delete_custom_file_type('278454') + + """ + http_method = "delete".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes/{file_id} + """ + ) + + params = {} + + request, error = self._request_executor.create_request(http_method, api_url, params=params) + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request) + if error: + return (None, response, error) + + return (None, response, None) + + def get_custom_file_type_count(self) -> APIResult[int]: + """ + Retrieves the count of custom file types available. + The API returns a scalar (e.g. 1); this method returns it as an int. + + Returns: + tuple: A tuple containing (count of custom file types as int, Response, error). + + Examples: + Retrieve the custom file type count (returns int):: + + >>> count, response, error = zia.custom_file_types.get_custom_file_type_count() + >>> if not error: + ... print(f"Custom file types count: {count}") + """ + http_method = "get".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /customFileTypes/count + """ + ) + + body = {} + headers = {} + + request, error = self._request_executor.create_request(http_method, api_url, body, headers) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request) + + if error: + return (None, response, error) + + try: + body = response.get_body() + if isinstance(body, dict) and "count" in body: + result = int(body["count"]) + elif isinstance(body, (int, float)): + result = int(body) + elif isinstance(body, str): + result = int(body) + else: + result = int(body) if body is not None else 0 + except (TypeError, ValueError) as err: + return (None, response, err) + return (result, response, None) diff --git a/zscaler/zia/file_type_control_rule.py b/zscaler/zia/file_type_control_rule.py index a4f29eff..a2a2a00b 100644 --- a/zscaler/zia/file_type_control_rule.py +++ b/zscaler/zia/file_type_control_rule.py @@ -39,20 +39,13 @@ def list_rules( A subset of file type control rules rules can be returned that match a supported filter expression or query. - Args: - query_params {dict}: Map of query parameters for the request. - - ``[query_params.search]`` {str}: Search string for filtering results. - Returns: tuple: A tuple containing (list of file type control rules rules instances, Response, error). Example: List all file type control rules rules with a specific page size: - >>> rules_list, response, error = zia.file_type_control_rule.list_rules( - ... query_params={"pagesize": 50} - ... ) + >>> rules_list, response, error = zia.file_type_control_rule.list_rules() >>> for rule in rules_list: ... print(rule.as_dict()) """ @@ -66,17 +59,14 @@ def list_rules( query_params = query_params or {} - # Prepare request body and headers body = {} headers = {} - # Create the request request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params) if error: return (None, None, error) - # Execute the request response, error = self._request_executor.execute(request) if error: @@ -361,3 +351,75 @@ def delete_rule(self, rule_id: int) -> APIResult[dict]: return (None, response, error) return (None, response, None) + + def list_file_type_categories( + self, + query_params: Optional[dict] = None, + ) -> APIResult[List[FileTypeControlRules]]: + """ + Retrieves the list of all file types, including predefined and custom file types, + available for configuring rule conditions in different ZIA policies. + You can retrieve predefined file types for specific file categories of policies + by using the enum request parameter and by specifying one of the following values: + + ``ZSCALERDLP``: Web DLP rules with content inspection + ``EXTERNALDLP``: Web DLP rules without content inspection + ``FILETYPECATEGORYFORFILETYPECONTROL``: File Type Control policy + + Args: + query_params {dict}: Map of query parameters for the request. + + ``[query_params.enums]`` {str}: Specifies the file type category for specific policies + to retrieve the corresponding list of predefined file types supported for the policy category + The following values are supported: + + ``ZSCALERDLP``: Web DLP rules with content inspection + ``EXTERNALDLP``: Web DLP rules without content inspection + ``FILETYPECATEGORYFORFILETYPECONTROL``: File Type Control policy + + ``[query_params.exclude_custom_file_types]`` {bool}: + Whether custom file types must be excluded from the list or not. + + Returns: + tuple: A tuple containing (list of file type categories instances, Response, error). + + Example: + List all file type categories: + + >>> categories, response, error = zia.file_type_control_rule.list_file_type_categories( + ... query_params={"enums": 'ZSCALERDLP'} + ) + >>> for category in categories: + ... print(category.as_dict()) + """ + http_method = "get".upper() + api_url = format_url( + f""" + {self._zia_base_endpoint} + /fileTypeCategories + """ + ) + + query_params = query_params or {} + + body = {} + headers = {} + + request, error = self._request_executor.create_request(http_method, api_url, body, headers, params=query_params) + + if error: + return (None, None, error) + + response, error = self._request_executor.execute(request) + + if error: + return (None, response, error) + + try: + result = [] + for item in response.get_results(): + result.append(FileTypeControlRules(self.form_response_body(item))) + except Exception as error: + return (None, response, error) + + return (result, response, None) diff --git a/zscaler/zia/legacy.py b/zscaler/zia/legacy.py index 5949f2a9..77cd712b 100644 --- a/zscaler/zia/legacy.py +++ b/zscaler/zia/legacy.py @@ -112,6 +112,7 @@ from zscaler.zia.saas_security_api import SaaSSecurityAPI from zscaler.zia.cloud_to_cloud_ir import CloudToCloudIRAPI from zscaler.zia.traffic_capture import TrafficCaptureAPI + from zscaler.zia.custom_file_types import CustomFileTypesAPI class LegacyZIAClientHelper: @@ -1241,6 +1242,14 @@ def traffic_capture(self) -> "TrafficCaptureAPI": return TrafficCaptureAPI(self.request_executor) + @property + def custom_file_types(self) -> "CustomFileTypesAPI": + """ + The interface object for the :ref:`ZIA Custom File Types interface `. + + """ + return CustomFileTypesAPI(self.request_executor) + """ Misc """ diff --git a/zscaler/zia/models/casb_dlp_rules.py b/zscaler/zia/models/casb_dlp_rules.py index 8374cc03..a3ff01cd 100644 --- a/zscaler/zia/models/casb_dlp_rules.py +++ b/zscaler/zia/models/casb_dlp_rules.py @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -from typing import Dict, List, Optional, Any, Union +from typing import Dict, Optional, Any from zscaler.oneapi_object import ZscalerObject from zscaler.oneapi_collection import ZscalerCollection from zscaler.zia.models import common @@ -140,6 +140,16 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: config["labels"] if "labels" in config else [], labels.RuleLabels ) + if "receiver" in config: + if isinstance(config["receiver"], CommonIDNameType): + self.receiver = config["receiver"] + elif config["receiver"] is not None: + self.receiver = CommonIDNameType(config["receiver"]) + else: + self.receiver = None + else: + self.receiver = None + if "zscalerIncidentReceiver" in config: if isinstance(config["zscalerIncidentReceiver"], common.CommonIDName): self.zscaler_incident_receiver = config["zscalerIncidentReceiver"] @@ -280,6 +290,7 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.without_content_inspection = None self.entity_groups = [] self.include_entity_groups = None + self.receiver = None def request_format(self) -> Dict[str, Any]: """ @@ -310,6 +321,7 @@ def request_format(self) -> Dict[str, Any]: "buckets": self.buckets, "bucketOwner": self.bucket_owner, "zscalerIncidentReceiver": self.zscaler_incident_receiver, + "receiver": self.receiver, "externalAuditorEmail": self.external_auditor_email, "auditor": self.auditor, "auditorNotification": self.auditor_notification, @@ -339,3 +351,39 @@ def request_format(self) -> Dict[str, Any]: } parent_req_format.update(current_obj_format) return parent_req_format + + +class CommonIDNameType(ZscalerObject): + """ + A class for CommonIDNameType objects. + Handles common block attributes shared across multiple resources + """ + + def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: + """ + Initialize the CommonIDNameType model based on API response. + + Args: + config (dict): A dictionary representing the response. + """ + super().__init__(config) + if config: + self.id = config["id"] if "id" in config else None + self.name = config["name"] if "name" in config else None + self.type = config["type"] if "type" in config else False + else: + self.id = None + self.name = None + self.type = None + + def request_format(self) -> Dict[str, Any]: + """ + Returns the object as a dictionary in the format expected for API requests. + """ + parent_req_format = super().request_format() + current_obj_format = { + "id": self.id, + "name": self.name, + "type": self.type} + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/zscaler/zia/models/custom_file_types.py b/zscaler/zia/models/custom_file_types.py new file mode 100644 index 00000000..2282fdc4 --- /dev/null +++ b/zscaler/zia/models/custom_file_types.py @@ -0,0 +1,64 @@ +""" +Copyright (c) 2023, Zscaler Inc. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +""" + +from typing import Dict, Optional, Any +from zscaler.oneapi_object import ZscalerObject +from zscaler.zia.models import common as common + + +class CustomFileTypes(ZscalerObject): + """ + A class for CustomFileTypes objects. + """ + + def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: + """ + Initialize the CustomFileTypes model based on API response. + + Args: + config (dict): A dictionary representing the Custom File Types configuration. + """ + super().__init__(config) + + if config: + self.id = config["id"] if "id" in config else None + self.name = config["name"] if "name" in config else None + self.description = config["description"] if "description" in config else None + self.extension = config["extension"] if "extension" in config else None + self.file_type_id = config["fileTypeId"] if "fileTypeId" in config else None + + else: + # Initialize with default None or 0 values + self.id = None + self.name = None + self.description = None + self.extension = None + self.file_type_id = None + + def request_format(self) -> Dict[str, Any]: + """ + Return the object as a dictionary in the format expected for API requests. + """ + parent_req_format = super().request_format() + current_obj_format = { + "id": self.id, + "name": self.name, + "description": self.description, + "extension": self.extension, + "fileTypeId": self.file_type_id, + } + parent_req_format.update(current_obj_format) + return parent_req_format diff --git a/zscaler/zia/models/dlp_web_rules.py b/zscaler/zia/models/dlp_web_rules.py index a2c360d8..7c9a2cd4 100644 --- a/zscaler/zia/models/dlp_web_rules.py +++ b/zscaler/zia/models/dlp_web_rules.py @@ -62,7 +62,6 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.parent_rule = config["parentRule"] if "parentRule" in config else None self.sub_rules = config["subRules"] if "subRules" in config else None self.order = config["order"] if "order" in config else None - self.eun_template_id = config["eunTemplateId"] if "eunTemplateId" in config else None self.inspect_http_get_enabled = config["inspectHttpGetEnabled"] if "inspectHttpGetEnabled" in config else None self.zscaler_incident_receiver = config["zscalerIncidentReceiver"] if "zscalerIncidentReceiver" in config else None self.external_auditor_email = config["externalAuditorEmail"] if "externalAuditorEmail" in config else None @@ -209,7 +208,6 @@ def request_format(self) -> Dict[str, Any]: "parentRule": self.parent_rule, "subRules": self.sub_rules, "order": self.order, - "eunTemplateId": self.eun_template_id, "zscalerIncidentReceiver": self.zscaler_incident_receiver, "protocols": self.protocols, "fileTypes": self.file_types, diff --git a/zscaler/zia/models/rule_labels.py b/zscaler/zia/models/rule_labels.py index 5df673bf..2b6113b4 100644 --- a/zscaler/zia/models/rule_labels.py +++ b/zscaler/zia/models/rule_labels.py @@ -57,6 +57,7 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: # Initialize with default None or 0 values self.id = None self.name = None + self.description = None self.last_modified_time = None self.last_modified_by = None self.created_by = None @@ -70,6 +71,7 @@ def request_format(self) -> Dict[str, Any]: current_obj_format = { "id": self.id, "name": self.name, + "description": self.description, "lastModifiedTime": self.last_modified_time, "lastModifiedBy": self.last_modified_by, "createdBy": self.created_by, diff --git a/zscaler/zia/models/subclouds.py b/zscaler/zia/models/subclouds.py index 198c4047..9b1f1dc1 100644 --- a/zscaler/zia/models/subclouds.py +++ b/zscaler/zia/models/subclouds.py @@ -122,8 +122,6 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.last_modified_time = config["lastModifiedTime"] if "lastModifiedTime" in config else None - self.last_modified_time = config["lastModifiedTime"] if "lastModifiedTime" in config else None - if "datacenter" in config: if isinstance(config["datacenter"], Datacenter): self.datacenter = config["datacenter"] @@ -231,21 +229,20 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: if config: self.id = config["id"] if "id" in config else None self.name = config["name"] if "name" in config else None - self.external_id = config["externalId"] if "externalId" in config else None - self.triggers = config if isinstance(config, dict) else {} else: self.id = None self.name = None - self.external_id = None - self.extensions = None def request_format(self) -> Dict[str, Any]: """ Return the object as a dictionary in the format expected for API requests. """ parent_req_format = super().request_format() - current_obj_format = {"id": self.id, "name": self.name, "externalId": self.external_id, "extensions": self.extensions} + current_obj_format = { + "id": self.id, + "name": self.name + } parent_req_format.update(current_obj_format) return parent_req_format diff --git a/zscaler/zia/models/urlcategory.py b/zscaler/zia/models/urlcategory.py index ec49dd51..a67ba670 100644 --- a/zscaler/zia/models/urlcategory.py +++ b/zscaler/zia/models/urlcategory.py @@ -40,9 +40,11 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.urls = ZscalerCollection.form_list(config["urls"] if "urls" in config else [], str) - self.regex_patterns_retaining_parent_category = ZscalerCollection.form_list(config["regexPatternsRetainingParentCategory"] if "regexPatternsRetainingParentCategory" in config else [], str) + self.regex_patterns_retaining_parent_category = ZscalerCollection.form_list + (config["regexPatternsRetainingParentCategory"] if "regexPatternsRetainingParentCategory" in config else [], str) - self.regex_patterns = ZscalerCollection.form_list(config["regexPatterns"] if "regexPatterns" in config else [], str) + self.regex_patterns = ZscalerCollection.form_list + (config["regexPatterns"]if "regexPatterns" in config else [], str) self.db_categorized_urls = ZscalerCollection.form_list( config["dbCategorizedUrls"] if "dbCategorizedUrls" in config else [], str @@ -73,9 +75,7 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.description = config["description"] if "description" in config else None self.type = config["type"] if "type" in config else None self.url_type = config["urlType"] if "urlType" in config else None - - # Handle nested dictionary for urlKeywordCounts - # Handle nested dictionary for urlKeywordCounts + self.url_keyword_counts = ( { "totalUrlCount": ( diff --git a/zscaler/zia/rule_labels.py b/zscaler/zia/rule_labels.py index fba0b571..76b7bac9 100644 --- a/zscaler/zia/rule_labels.py +++ b/zscaler/zia/rule_labels.py @@ -283,7 +283,9 @@ def get_rule_type_label(self, rule_type: str) -> APIResult[List[RuleLabels]]: Retrieves a list of rule labels based on the specified rule type Args: - rule_type (str): The type of rule to retrieve labels for. Only supported values are: URL_FILTERING, FIREWALL, CASB_DLP, CLOUD_APP_CONTROL, DATA_PROTECTION, GENAI, INDUSTRY_PEER, NEWS_FEED, RISK_SCORE, SANDBOX + rule_type (str): The type of rule to retrieve labels for. + Only supported values are: URL_FILTERING, FIREWALL, CASB_DLP, CLOUD_APP_CONTROL, + DATA_PROTECTION, GENAI, INDUSTRY_PEER, NEWS_FEED, RISK_SCORE, SANDBOX Returns: tuple: A tuple containing (list of Rule Labels instances, Response, error) diff --git a/zscaler/zia/traffic_datacenters.py b/zscaler/zia/traffic_datacenters.py index ae89fed4..13d262f0 100644 --- a/zscaler/zia/traffic_datacenters.py +++ b/zscaler/zia/traffic_datacenters.py @@ -175,13 +175,14 @@ def add_dc_exclusion(self, **kwargs) -> APIResult[dict]: except Exception as e: return (None, None, e) - body = [ - { - "dcid": dcid, - "startTime": start_epoch, - "endTime": end_epoch, - } - ] + body_item = { + "dcid": dcid, + "startTime": start_epoch, + "endTime": end_epoch, + } + if kwargs.get("description") is not None: + body_item["description"] = kwargs.get("description") + body = [body_item] request, error = self._request_executor.create_request( method=http_method, @@ -202,13 +203,14 @@ def add_dc_exclusion(self, **kwargs) -> APIResult[dict]: return (result, response, None) - # Submit JIRA Case - Method is returning 405. def update_dc_exclusion(self, dcid: int, **kwargs) -> APIResult[dict]: """ Updates a Zscaler data center DC Exclusion configuration based on the specified ID. + The API expects PUT to /dcExclusions with dcid in the JSON body (not in the URL path). + Args: - dc_id (int): The unique ID for the DC Exclusion. + dcid (int): The unique ID for the DC Exclusion. Returns: tuple: A tuple containing the updated DC Exclusion, response, and error. @@ -217,7 +219,7 @@ def update_dc_exclusion(self, dcid: int, **kwargs) -> APIResult[dict]: api_url = format_url( f""" {self._zia_base_endpoint} - /dcExclusions/{dcid} + /dcExclusions """ ) @@ -232,25 +234,17 @@ def update_dc_exclusion(self, dcid: int, **kwargs) -> APIResult[dict]: start_epoch = int(start_time) end_epoch = int(end_time) - dcid = kwargs.get("dcid") - if not dcid: - dc_list, _, error = self.list_datacenters() - if error: - return (None, None, error) - if not dc_list: - return (None, None, ValueError("No data centers found to use as default.")) - dcid = dc_list[0].id - except Exception as e: return (None, None, e) - body = [ - { - "dcid": dcid, - "startTime": start_epoch, - "endTime": end_epoch, - } - ] + body_item = { + "dcid": dcid, + "startTime": start_epoch, + "endTime": end_epoch, + } + if kwargs.get("description") is not None: + body_item["description"] = kwargs.get("description") + body = [body_item] request, error = self._request_executor.create_request(http_method, api_url, body, {}, {}) if error: @@ -261,7 +255,10 @@ def update_dc_exclusion(self, dcid: int, **kwargs) -> APIResult[dict]: return (None, response, error) try: - result = TrafficDcExclusions(self.form_response_body(response.get_body())) + resp_body = response.get_body() + # API returns list of exclusions; take first item + item = resp_body[0] if isinstance(resp_body, list) and resp_body else resp_body + result = TrafficDcExclusions(self.form_response_body(item)) except Exception as error: return (None, response, error) return (result, response, None) diff --git a/zscaler/zia/url_categories.py b/zscaler/zia/url_categories.py index 81937070..89dc1f18 100644 --- a/zscaler/zia/url_categories.py +++ b/zscaler/zia/url_categories.py @@ -48,7 +48,10 @@ def list_categories( ``[query_params.custom_only]`` {bool}: If set to true, gets information on custom URL categories only. ``[query_params.include_only_url_keyword_counts]`` {bool}: By default this parameter is set to false. - ``[query_params.type]`` {str}: Filter by category type. Supported values: `URL_CATEGORY`, `TLD_CATEGORY` and `ALL`. + + ``[query_params.type]`` {str}: Filter by category type. + Supported values: `URL_CATEGORY`, `TLD_CATEGORY` and `ALL`. + ``[query_params.search]`` {str}: Local client-side search filter (not sent to API). Returns: diff --git a/zscaler/zia/zia_service.py b/zscaler/zia/zia_service.py index 07a56d08..07b9b287 100644 --- a/zscaler/zia/zia_service.py +++ b/zscaler/zia/zia_service.py @@ -44,6 +44,7 @@ from zscaler.zia.device_management import DeviceManagementAPI from zscaler.zia.end_user_notification import EndUserNotificationAPI from zscaler.zia.file_type_control_rule import FileTypeControlRuleAPI +from zscaler.zia.custom_file_types import CustomFileTypesAPI from zscaler.zia.cloud_firewall_dns import FirewallDNSRulesAPI from zscaler.zia.cloud_firewall_ips import FirewallIPSRulesAPI from zscaler.zia.cloud_firewall_rules import FirewallPolicyAPI @@ -310,6 +311,14 @@ def file_type_control_rule(self) -> FileTypeControlRuleAPI: """ return FileTypeControlRuleAPI(self._request_executor) + @property + def custom_file_types(self) -> CustomFileTypesAPI: + """ + The interface object for the :ref:`ZIA Custom File Types interface `. + + """ + return CustomFileTypesAPI(self._request_executor) + @property def ipv6_config(self) -> TrafficIPV6ConfigAPI: """ diff --git a/zscaler/zpa/app_protection.py b/zscaler/zpa/app_protection.py index f830ec81..63d5b810 100644 --- a/zscaler/zpa/app_protection.py +++ b/zscaler/zpa/app_protection.py @@ -14,7 +14,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. """ -from typing import Dict, List, Optional, Any, Union +from typing import List, Optional from zscaler.api_client import APIClient from zscaler.request_executor import RequestExecutor from zscaler.zpa.models.app_protection_profile import AppProtectionProfile @@ -818,7 +818,10 @@ def delete_custom_control(self, control_id: str) -> int: return (None, response, None) - def list_predef_controls(self, query_params: Optional[dict] = None) -> APIResult[List[PredefinedInspectionControlResource]]: + def list_predef_controls( + self, + query_params: Optional[dict] = None + ) -> APIResult[List[PredefinedInspectionControlResource]]: """ Returns a list of predefined ZPA Inspection Controls. diff --git a/zscaler/zpa/models/application_segment.py b/zscaler/zpa/models/application_segment.py index 92f3fd8b..30fe576b 100644 --- a/zscaler/zpa/models/application_segment.py +++ b/zscaler/zpa/models/application_segment.py @@ -19,6 +19,7 @@ from zscaler.oneapi_collection import ZscalerCollection from zscaler.zpa.models import server_group as server_group from zscaler.zpa.models import segment_group as segment_group +from zscaler.zpa.models import common as common class ApplicationSegments(ZscalerObject): @@ -154,6 +155,11 @@ def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: self.application_group = None else: self.application_group = None + + self.tags = ZscalerCollection.form_list( + config["tags"] if "tags" in config else [], Tags + ) + else: self.id = None self.name = None @@ -550,6 +556,58 @@ def request_format(self) -> Dict[str, Any]: return parent_req_format +class Tags(ZscalerObject): + def __init__(self, config: Optional[Dict[str, Any]] = None) -> None: + super().__init__(config) + if config: + if "namespace" in config: + if isinstance(config["namespace"], common.CommonIDName): + self.namespace = config["namespace"] + elif config["namespace"] is not None: + self.namespace = common.CommonIDName(config["namespace"]) + else: + self.namespace = None + else: + self.namespace = None + + if "tagKey" in config: + if isinstance(config["tagKey"], common.CommonIDName): + self.tag_key = config["tagKey"] + elif config["tagKey"] is not None: + self.tag_key = common.CommonIDName(config["tagKey"]) + else: + self.tag_key = None + else: + self.tag_key = None + + if "tagValue" in config: + if isinstance(config["tagValue"], common.CommonIDName): + self.tag_value = config["tagValue"] + elif config["tagValue"] is not None: + self.tag_value = common.CommonIDName(config["tagValue"]) + else: + self.tag_value = None + else: + self.tag_value = None + else: + self.namespace = None + self.tag_key = None + self.tag_value = None + + def request_format(self) -> Dict[str, Any]: + """ + Formats the AppConfig data into a dictionary suitable for API requests. + """ + parent_req_format = super().request_format() + current_obj_format = { + "namespace": self.namespace, + "tagKey": self.tag_key, + "tagValue": self.tag_value, + } + parent_req_format.update(current_obj_format) + return parent_req_format + + class SharedMicrotenantDetails(ZscalerObject): """ A class for SharedMicrotenantDetails objects. diff --git a/zscaler/zpa/models/pra_portal.py b/zscaler/zpa/models/pra_portal.py index 977705e1..08e74187 100644 --- a/zscaler/zpa/models/pra_portal.py +++ b/zscaler/zpa/models/pra_portal.py @@ -18,6 +18,7 @@ from zscaler.oneapi_object import ZscalerObject from zscaler.oneapi_collection import ZscalerCollection + class PrivilegedRemoteAccessPortal(ZscalerObject): """ A class representing the Privileged Remote Access Portal.