From 708fb7f0fed800076bcf2f492d3f618725c20b9a Mon Sep 17 00:00:00 2001 From: Jan Soubusta Date: Mon, 11 May 2026 13:35:28 +0200 Subject: [PATCH 1/2] chore(openapi-codegen): drop spec post-processing workarounds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Upstream gdc-nas (DX-346) cleaned the OpenAPI spec so the regen pipeline no longer needs local repairs: - Drop the NUL-stripping `tr` after the jq merge — `DeclarativeColumn.name` no longer carries a `^[^NUL]*$` pattern that leaked literal NUL bytes through jq decoding. - Drop the jq cycle-break on `DashboardCompoundComparisonCondition` / `DashboardCompoundRangeCondition` — Springdoc no longer emits the redundant child-to-parent `allOf: [{$ref: ...}]` that crashed openapi-generator-cli v6.6.0 with StackOverflowError in `recursiveGetDiscriminator`. - Drop the `scripts/postprocess_api_client.py` invocation and delete the script — it only existed to repair regex patterns mangled by the now-absent NUL escape. - Repoint `make api-client STAGING=1` from `demo-cicd.cloud.gooddata.com` (production) to `staging.dev-latest.stg11.panther.intgdc.com` (actual staging). The previous URL silently regenerated against production and would re-introduce the workarounds. Verified by regenerating the client against staging with the workarounds removed: no StackOverflowError, no NUL bytes in the merged spec, no mangled regex in the generated Python. JIRA: DX-346 risk: low --- Makefile | 20 ++--------- scripts/postprocess_api_client.py | 58 ------------------------------- 2 files changed, 3 insertions(+), 75 deletions(-) delete mode 100755 scripts/postprocess_api_client.py diff --git a/Makefile b/Makefile index 3ca21151b..7d5139fab 100644 --- a/Makefile +++ b/Makefile @@ -8,9 +8,9 @@ NO_CLIENT_GD_PROJECTS_ABS = $(filter-out %client, $(wildcard $(CURDIR)/packages/ NO_CLIENT_GD_PROJECTS_DIRS = $(foreach dir, $(NO_CLIENT_GD_PROJECTS_ABS), $(notdir $(dir))) # TODO: replace API_VERSION in the future by call to API API_VERSION="v1" -# Default: generate from localhost; use `make api-client STAGING=1` to download from remote +# Default: generate from localhost; use `make api-client STAGING=1` to download from staging ifdef STAGING -BASE_URL="https://demo-cicd.cloud.gooddata.com" +BASE_URL="https://staging.dev-latest.stg11.panther.intgdc.com" else BASE_URL="http://localhost:3000" endif @@ -61,22 +61,8 @@ endef .PHONY: _api-client-generate _api-client-generate: rm -f schemas/gooddata-api-client.json - # Merge per-domain specs and strip literal NUL bytes that jq decoded from - # escapes in the source (the previous `sed '/.../d'` pattern was a no-op: - # sed BRE/ERE doesn't interpret \uNNNN, so it never matched anything). - cat schemas/gooddata-*.json | jq -S -s 'reduce .[] as $$item ({}; . * $$item) + { tags : ( reduce .[].tags as $$item (null; . + $$item) | unique_by(.name) ) }' | tr -d '\000' > "schemas/gooddata-api-client.json" - # Break the DashboardCompoundConditionItem ↔ children oneOf/allOf cycle that - # crashes openapi-generator-cli v6.6.0 with StackOverflowError in - # recursiveGetDiscriminator (its walker has no visited-set). Parent has no - # own properties, so dropping the redundant `allOf: [{$$ref: parent}]` from - # each child is semantically a no-op. - jq '(.components.schemas.DashboardCompoundComparisonCondition.allOf) |= map(select(.["$$ref"] != "#/components/schemas/DashboardCompoundConditionItem")) | (.components.schemas.DashboardCompoundRangeCondition.allOf) |= map(select(.["$$ref"] != "#/components/schemas/DashboardCompoundConditionItem"))' schemas/gooddata-api-client.json > schemas/gooddata-api-client.json.tmp && mv schemas/gooddata-api-client.json.tmp schemas/gooddata-api-client.json + cat schemas/gooddata-*.json | jq -S -s 'reduce .[] as $$item ({}; . * $$item) + { tags : ( reduce .[].tags as $$item (null; . + $$item) | unique_by(.name) ) }' > "schemas/gooddata-api-client.json" $(call generate_client,api) - # Repair regex patterns of the form ^[^\x00]*$ that openapi-generator mangles - # in two ways: sometimes it drops the NUL (leaving the invalid `^[^]*$`), - # sometimes it embeds a literal NUL byte (producing a Python source that - # fails to import with SyntaxError). The helper handles both shapes. - ./scripts/postprocess_api_client.py gooddata-api-client/gooddata_api_client .PHONY: api-client api-client: download _api-client-generate diff --git a/scripts/postprocess_api_client.py b/scripts/postprocess_api_client.py deleted file mode 100755 index 6f8eafbd6..000000000 --- a/scripts/postprocess_api_client.py +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env python3 -# (C) 2026 GoodData Corporation -"""Post-process the generated `gooddata-api-client` Python sources. - -Two issues from openapi-generator-cli v6.6.0 with the `python-prior` generator -need patching after every regen — both relate to the regex pattern -`^[^\\u0000]*$` that the upstream OpenAPI spec uses on identifier fields: - -1. The generator sometimes drops the `\\x00` literal from the character class, - leaving the invalid Python regex `^[^]*$` (empty char class). -2. The generator sometimes embeds a literal NUL byte between the brackets, - producing a Python source file with a NUL — which fails to import with - `SyntaxError: source code string cannot contain null bytes`. - -This script handles both shapes by rewriting any byte sequence resembling the -broken regex into the canonical `^[^\\\\x00]*$` form, and stripping any -remaining stray NULs from the generated tree. -""" - -from __future__ import annotations - -import sys -from pathlib import Path - -BROKEN_NUL = b"[^\x00]" # literal NUL inside char class -BROKEN_EMPTY = b"[^]" # NUL was dropped entirely -FIXED = b"[^\\x00]" # canonical Python escape - - -def patch(path: Path) -> bool: - raw = path.read_bytes() - new = raw.replace(BROKEN_NUL, FIXED).replace(BROKEN_EMPTY, FIXED) - # Defensive: any stray NUL that wasn't inside the regex pattern. There - # should be none after the replace above, but generated docstrings have - # historically carried odd byte sequences. - if b"\x00" in new: - new = new.replace(b"\x00", b"") - if new == raw: - return False - path.write_bytes(new) - return True - - -def main(root: str) -> int: - base = Path(root) - if not base.is_dir(): - print(f"error: {root} is not a directory", file=sys.stderr) - return 1 - fixed = 0 - for py in base.rglob("*.py"): - if patch(py): - fixed += 1 - print(f"postprocess_api_client: patched {fixed} file(s) under {root}") - return 0 - - -if __name__ == "__main__": - sys.exit(main(sys.argv[1] if len(sys.argv) > 1 else "gooddata-api-client/gooddata_api_client")) From 194436fe4a509a0064fb10877960d44415a1483a Mon Sep 17 00:00:00 2001 From: Jan Soubusta Date: Mon, 11 May 2026 13:35:38 +0200 Subject: [PATCH 2/2] chore(api-client): regenerate against staging Regenerate `gooddata-api-client` against `staging.dev-latest.stg11.panther.intgdc.com` after the DX-346 spec cleanup landed there. Run with the previous commit's slimmed-down `_api-client-generate` (no NUL stripping, no jq cycle-break, no postprocess script) to confirm the workarounds are no longer needed. Notable spec drift picked up incidentally: - `DeclarativeColumn.name`: drops the `regex` validation block; the NUL constraint is now carried in the field description (`Must not contain NUL (0x00) characters.`). - New `DeclarativeIpAllowlistPolicy` model exposed under `DeclarativeOrganization` (added on staging since the previous regen). JIRA: DX-346 risk: low --- gooddata-api-client/.openapi-generator/FILES | 2 + gooddata-api-client/README.md | 1 + gooddata-api-client/docs/DeclarativeColumn.md | 2 +- .../docs/DeclarativeIpAllowlistPolicy.md | 16 + .../docs/DeclarativeOrganization.md | 1 + gooddata-api-client/docs/LayoutApi.md | 18 ++ .../docs/OrganizationDeclarativeAPIsApi.md | 18 ++ .../model/declarative_column.py | 7 +- .../model/declarative_ip_allowlist_policy.py | 297 ++++++++++++++++++ .../model/declarative_organization.py | 6 + .../gooddata_api_client/models/__init__.py | 1 + schemas/gooddata-api-client.json | 52 ++- schemas/gooddata-automation-client.json | 6 - schemas/gooddata-export-client.json | 6 - schemas/gooddata-metadata-client.json | 58 +++- schemas/gooddata-scan-client.json | 3 +- 16 files changed, 464 insertions(+), 30 deletions(-) create mode 100644 gooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md create mode 100644 gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py diff --git a/gooddata-api-client/.openapi-generator/FILES b/gooddata-api-client/.openapi-generator/FILES index 2213f7b0f..d17296698 100644 --- a/gooddata-api-client/.openapi-generator/FILES +++ b/gooddata-api-client/.openapi-generator/FILES @@ -291,6 +291,7 @@ docs/DeclarativeFilterContext.md docs/DeclarativeFilterView.md docs/DeclarativeIdentityProvider.md docs/DeclarativeIdentityProviderIdentifier.md +docs/DeclarativeIpAllowlistPolicy.md docs/DeclarativeJwk.md docs/DeclarativeJwkSpecification.md docs/DeclarativeLabel.md @@ -1831,6 +1832,7 @@ gooddata_api_client/model/declarative_filter_context.py gooddata_api_client/model/declarative_filter_view.py gooddata_api_client/model/declarative_identity_provider.py gooddata_api_client/model/declarative_identity_provider_identifier.py +gooddata_api_client/model/declarative_ip_allowlist_policy.py gooddata_api_client/model/declarative_jwk.py gooddata_api_client/model/declarative_jwk_specification.py gooddata_api_client/model/declarative_label.py diff --git a/gooddata-api-client/README.md b/gooddata-api-client/README.md index 8e763cf23..9624c00f0 100644 --- a/gooddata-api-client/README.md +++ b/gooddata-api-client/README.md @@ -1577,6 +1577,7 @@ Class | Method | HTTP request | Description - [DeclarativeFilterView](docs/DeclarativeFilterView.md) - [DeclarativeIdentityProvider](docs/DeclarativeIdentityProvider.md) - [DeclarativeIdentityProviderIdentifier](docs/DeclarativeIdentityProviderIdentifier.md) + - [DeclarativeIpAllowlistPolicy](docs/DeclarativeIpAllowlistPolicy.md) - [DeclarativeJwk](docs/DeclarativeJwk.md) - [DeclarativeJwkSpecification](docs/DeclarativeJwkSpecification.md) - [DeclarativeLabel](docs/DeclarativeLabel.md) diff --git a/gooddata-api-client/docs/DeclarativeColumn.md b/gooddata-api-client/docs/DeclarativeColumn.md index 090ebe2ac..57c43dc06 100644 --- a/gooddata-api-client/docs/DeclarativeColumn.md +++ b/gooddata-api-client/docs/DeclarativeColumn.md @@ -6,7 +6,7 @@ A table column. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **data_type** | **str** | Column type | -**name** | **str** | Column name | +**name** | **str** | Column name. Must not contain NUL (0x00) characters. | **description** | **str** | Column description/comment from database | [optional] **is_nullable** | **bool** | Column is nullable | [optional] **is_primary_key** | **bool** | Is column part of primary key? | [optional] diff --git a/gooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md b/gooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md new file mode 100644 index 000000000..37b867753 --- /dev/null +++ b/gooddata-api-client/docs/DeclarativeIpAllowlistPolicy.md @@ -0,0 +1,16 @@ +# DeclarativeIpAllowlistPolicy + +A declarative form of an IP allowlist policy. + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**allowed_sources** | **[str]** | Allowed source IP addresses or CIDR ranges. | +**id** | **str** | Identifier of an IP allowlist policy. | +**user_groups** | [**[DeclarativeUserGroupIdentifier]**](DeclarativeUserGroupIdentifier.md) | Target user groups this policy applies to. | [optional] +**users** | [**[DeclarativeUserIdentifier]**](DeclarativeUserIdentifier.md) | Target users this policy applies to. | [optional] +**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/gooddata-api-client/docs/DeclarativeOrganization.md b/gooddata-api-client/docs/DeclarativeOrganization.md index fd43d03fa..1d1e16783 100644 --- a/gooddata-api-client/docs/DeclarativeOrganization.md +++ b/gooddata-api-client/docs/DeclarativeOrganization.md @@ -11,6 +11,7 @@ Name | Type | Description | Notes **data_sources** | [**[DeclarativeDataSource]**](DeclarativeDataSource.md) | | [optional] **export_templates** | [**[DeclarativeExportTemplate]**](DeclarativeExportTemplate.md) | | [optional] **identity_providers** | [**[DeclarativeIdentityProvider]**](DeclarativeIdentityProvider.md) | | [optional] +**ip_allowlist_policies** | [**[DeclarativeIpAllowlistPolicy]**](DeclarativeIpAllowlistPolicy.md) | | [optional] **jwks** | [**[DeclarativeJwk]**](DeclarativeJwk.md) | | [optional] **notification_channels** | [**[DeclarativeNotificationChannel]**](DeclarativeNotificationChannel.md) | | [optional] **user_groups** | [**[DeclarativeUserGroup]**](DeclarativeUserGroup.md) | | [optional] diff --git a/gooddata-api-client/docs/LayoutApi.md b/gooddata-api-client/docs/LayoutApi.md index 0761dba01..8f6828387 100644 --- a/gooddata-api-client/docs/LayoutApi.md +++ b/gooddata-api-client/docs/LayoutApi.md @@ -4435,6 +4435,24 @@ with gooddata_api_client.ApiClient() as api_client: saml_metadata="saml_metadata_example", ), ], + ip_allowlist_policies=[ + DeclarativeIpAllowlistPolicy( + allowed_sources=["203.0.113.10/32","198.51.100.0/24"], + id="admin-vpn-only", + user_groups=[ + DeclarativeUserGroupIdentifier( + id="group.admins", + type="userGroup", + ), + ], + users=[ + DeclarativeUserIdentifier( + id="employee123", + type="user", + ), + ], + ), + ], jwks=[ DeclarativeJwk( content=DeclarativeJwkSpecification(), diff --git a/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md b/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md index 103c248e8..7c4ef6863 100644 --- a/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md +++ b/gooddata-api-client/docs/OrganizationDeclarativeAPIsApi.md @@ -582,6 +582,24 @@ with gooddata_api_client.ApiClient() as api_client: saml_metadata="saml_metadata_example", ), ], + ip_allowlist_policies=[ + DeclarativeIpAllowlistPolicy( + allowed_sources=["203.0.113.10/32","198.51.100.0/24"], + id="admin-vpn-only", + user_groups=[ + DeclarativeUserGroupIdentifier( + id="group.admins", + type="userGroup", + ), + ], + users=[ + DeclarativeUserIdentifier( + id="employee123", + type="user", + ), + ], + ), + ], jwks=[ DeclarativeJwk( content=DeclarativeJwkSpecification(), diff --git a/gooddata-api-client/gooddata_api_client/model/declarative_column.py b/gooddata-api-client/gooddata_api_client/model/declarative_column.py index 4b2900902..fccfe03ee 100644 --- a/gooddata-api-client/gooddata_api_client/model/declarative_column.py +++ b/gooddata-api-client/gooddata_api_client/model/declarative_column.py @@ -71,9 +71,6 @@ class DeclarativeColumn(ModelNormal): validations = { ('name',): { 'max_length': 255, - 'regex': { - 'pattern': r'^[^\x00]*$', # noqa: E501 - }, }, ('description',): { 'max_length': 10000, @@ -143,7 +140,7 @@ def _from_openapi_data(cls, data_type, name, *args, **kwargs): # noqa: E501 Args: data_type (str): Column type - name (str): Column name + name (str): Column name. Must not contain NUL (0x00) characters. Keyword Args: _check_type (bool): if True, values for parameters in openapi_types @@ -239,7 +236,7 @@ def __init__(self, data_type, name, *args, **kwargs): # noqa: E501 Args: data_type (str): Column type - name (str): Column name + name (str): Column name. Must not contain NUL (0x00) characters. Keyword Args: _check_type (bool): if True, values for parameters in openapi_types diff --git a/gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py b/gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py new file mode 100644 index 000000000..c6bf07056 --- /dev/null +++ b/gooddata-api-client/gooddata_api_client/model/declarative_ip_allowlist_policy.py @@ -0,0 +1,297 @@ +""" + OpenAPI definition + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) # noqa: E501 + + The version of the OpenAPI document: v0 + Contact: support@gooddata.com + Generated by: https://openapi-generator.tech +""" + + +import re # noqa: F401 +import sys # noqa: F401 + +from gooddata_api_client.model_utils import ( # noqa: F401 + ApiTypeError, + ModelComposed, + ModelNormal, + ModelSimple, + cached_property, + change_keys_js_to_python, + convert_js_args_to_python_args, + date, + datetime, + file_type, + none_type, + validate_get_composed_info, + OpenApiModel +) +from gooddata_api_client.exceptions import ApiAttributeError + + +def lazy_import(): + from gooddata_api_client.model.declarative_user_group_identifier import DeclarativeUserGroupIdentifier + from gooddata_api_client.model.declarative_user_identifier import DeclarativeUserIdentifier + globals()['DeclarativeUserGroupIdentifier'] = DeclarativeUserGroupIdentifier + globals()['DeclarativeUserIdentifier'] = DeclarativeUserIdentifier + + +class DeclarativeIpAllowlistPolicy(ModelNormal): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + + Attributes: + allowed_values (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + with a capitalized key describing the allowed value and an allowed + value. These dicts store the allowed enum values. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + discriminator_value_class_map (dict): A dict to go from the discriminator + variable value to the discriminator class name. + validations (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + that stores validations for max_length, min_length, max_items, + min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, + inclusive_minimum, and regex. + additional_properties_type (tuple): A tuple of classes accepted + as additional properties values. + """ + + allowed_values = { + } + + validations = { + ('id',): { + 'regex': { + 'pattern': r'^(?!\.)[.A-Za-z0-9_-]{1,255}$', # noqa: E501 + }, + }, + } + + @cached_property + def additional_properties_type(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + """ + lazy_import() + return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 + + _nullable = False + + @cached_property + def openapi_types(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + + Returns + openapi_types (dict): The key is attribute name + and the value is attribute type. + """ + lazy_import() + return { + 'allowed_sources': ([str],), # noqa: E501 + 'id': (str,), # noqa: E501 + 'user_groups': ([DeclarativeUserGroupIdentifier],), # noqa: E501 + 'users': ([DeclarativeUserIdentifier],), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + + attribute_map = { + 'allowed_sources': 'allowedSources', # noqa: E501 + 'id': 'id', # noqa: E501 + 'user_groups': 'userGroups', # noqa: E501 + 'users': 'users', # noqa: E501 + } + + read_only_vars = { + } + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, allowed_sources, id, *args, **kwargs): # noqa: E501 + """DeclarativeIpAllowlistPolicy - a model defined in OpenAPI + + Args: + allowed_sources ([str]): Allowed source IP addresses or CIDR ranges. + id (str): Identifier of an IP allowlist policy. + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + user_groups ([DeclarativeUserGroupIdentifier]): Target user groups this policy applies to.. [optional] # noqa: E501 + users ([DeclarativeUserIdentifier]): Target users this policy applies to.. [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', True) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + self = super(OpenApiModel, cls).__new__(cls) + + if args: + for arg in args: + if isinstance(arg, dict): + kwargs.update(arg) + else: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + self.allowed_sources = allowed_sources + self.id = id + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + return self + + required_properties = set([ + '_data_store', + '_check_type', + '_spec_property_naming', + '_path_to_item', + '_configuration', + '_visited_composed_classes', + ]) + + @convert_js_args_to_python_args + def __init__(self, allowed_sources, id, *args, **kwargs): # noqa: E501 + """DeclarativeIpAllowlistPolicy - a model defined in OpenAPI + + Args: + allowed_sources ([str]): Allowed source IP addresses or CIDR ranges. + id (str): Identifier of an IP allowlist policy. + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + user_groups ([DeclarativeUserGroupIdentifier]): Target user groups this policy applies to.. [optional] # noqa: E501 + users ([DeclarativeUserIdentifier]): Target users this policy applies to.. [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + if args: + for arg in args: + if isinstance(arg, dict): + kwargs.update(arg) + else: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + self.allowed_sources = allowed_sources + self.id = id + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + if var_name in self.read_only_vars: + raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " + f"class with read only attributes.") diff --git a/gooddata-api-client/gooddata_api_client/model/declarative_organization.py b/gooddata-api-client/gooddata_api_client/model/declarative_organization.py index 7e9468441..04d299759 100644 --- a/gooddata-api-client/gooddata_api_client/model/declarative_organization.py +++ b/gooddata-api-client/gooddata_api_client/model/declarative_organization.py @@ -36,6 +36,7 @@ def lazy_import(): from gooddata_api_client.model.declarative_data_source import DeclarativeDataSource from gooddata_api_client.model.declarative_export_template import DeclarativeExportTemplate from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider + from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy from gooddata_api_client.model.declarative_jwk import DeclarativeJwk from gooddata_api_client.model.declarative_notification_channel import DeclarativeNotificationChannel from gooddata_api_client.model.declarative_organization_info import DeclarativeOrganizationInfo @@ -48,6 +49,7 @@ def lazy_import(): globals()['DeclarativeDataSource'] = DeclarativeDataSource globals()['DeclarativeExportTemplate'] = DeclarativeExportTemplate globals()['DeclarativeIdentityProvider'] = DeclarativeIdentityProvider + globals()['DeclarativeIpAllowlistPolicy'] = DeclarativeIpAllowlistPolicy globals()['DeclarativeJwk'] = DeclarativeJwk globals()['DeclarativeNotificationChannel'] = DeclarativeNotificationChannel globals()['DeclarativeOrganizationInfo'] = DeclarativeOrganizationInfo @@ -116,6 +118,7 @@ def openapi_types(): 'data_sources': ([DeclarativeDataSource],), # noqa: E501 'export_templates': ([DeclarativeExportTemplate],), # noqa: E501 'identity_providers': ([DeclarativeIdentityProvider],), # noqa: E501 + 'ip_allowlist_policies': ([DeclarativeIpAllowlistPolicy],), # noqa: E501 'jwks': ([DeclarativeJwk],), # noqa: E501 'notification_channels': ([DeclarativeNotificationChannel],), # noqa: E501 'user_groups': ([DeclarativeUserGroup],), # noqa: E501 @@ -136,6 +139,7 @@ def discriminator(): 'data_sources': 'dataSources', # noqa: E501 'export_templates': 'exportTemplates', # noqa: E501 'identity_providers': 'identityProviders', # noqa: E501 + 'ip_allowlist_policies': 'ipAllowlistPolicies', # noqa: E501 'jwks': 'jwks', # noqa: E501 'notification_channels': 'notificationChannels', # noqa: E501 'user_groups': 'userGroups', # noqa: E501 @@ -193,6 +197,7 @@ def _from_openapi_data(cls, organization, *args, **kwargs): # noqa: E501 data_sources ([DeclarativeDataSource]): [optional] # noqa: E501 export_templates ([DeclarativeExportTemplate]): [optional] # noqa: E501 identity_providers ([DeclarativeIdentityProvider]): [optional] # noqa: E501 + ip_allowlist_policies ([DeclarativeIpAllowlistPolicy]): [optional] # noqa: E501 jwks ([DeclarativeJwk]): [optional] # noqa: E501 notification_channels ([DeclarativeNotificationChannel]): [optional] # noqa: E501 user_groups ([DeclarativeUserGroup]): [optional] # noqa: E501 @@ -293,6 +298,7 @@ def __init__(self, organization, *args, **kwargs): # noqa: E501 data_sources ([DeclarativeDataSource]): [optional] # noqa: E501 export_templates ([DeclarativeExportTemplate]): [optional] # noqa: E501 identity_providers ([DeclarativeIdentityProvider]): [optional] # noqa: E501 + ip_allowlist_policies ([DeclarativeIpAllowlistPolicy]): [optional] # noqa: E501 jwks ([DeclarativeJwk]): [optional] # noqa: E501 notification_channels ([DeclarativeNotificationChannel]): [optional] # noqa: E501 user_groups ([DeclarativeUserGroup]): [optional] # noqa: E501 diff --git a/gooddata-api-client/gooddata_api_client/models/__init__.py b/gooddata-api-client/gooddata_api_client/models/__init__.py index 31bfa2b11..557074746 100644 --- a/gooddata-api-client/gooddata_api_client/models/__init__.py +++ b/gooddata-api-client/gooddata_api_client/models/__init__.py @@ -249,6 +249,7 @@ from gooddata_api_client.model.declarative_filter_view import DeclarativeFilterView from gooddata_api_client.model.declarative_identity_provider import DeclarativeIdentityProvider from gooddata_api_client.model.declarative_identity_provider_identifier import DeclarativeIdentityProviderIdentifier +from gooddata_api_client.model.declarative_ip_allowlist_policy import DeclarativeIpAllowlistPolicy from gooddata_api_client.model.declarative_jwk import DeclarativeJwk from gooddata_api_client.model.declarative_jwk_specification import DeclarativeJwkSpecification from gooddata_api_client.model.declarative_label import DeclarativeLabel diff --git a/schemas/gooddata-api-client.json b/schemas/gooddata-api-client.json index 5dfbfb283..652e4a393 100644 --- a/schemas/gooddata-api-client.json +++ b/schemas/gooddata-api-client.json @@ -5697,10 +5697,9 @@ "type": "boolean" }, "name": { - "description": "Column name", + "description": "Column name. Must not contain NUL (0x00) characters.", "example": "customer_id", "maxLength": 255, - "pattern": "^[^\u0000]*$", "type": "string" }, "referencedTableColumn": { @@ -6746,6 +6745,49 @@ ], "type": "object" }, + "DeclarativeIpAllowlistPolicy": { + "description": "A declarative form of an IP allowlist policy.", + "properties": { + "allowedSources": { + "description": "Allowed source IP addresses or CIDR ranges.", + "example": [ + "203.0.113.10/32", + "198.51.100.0/24" + ], + "items": { + "description": "Allowed source IP addresses or CIDR ranges.", + "example": "[\"203.0.113.10/32\",\"198.51.100.0/24\"]", + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Identifier of an IP allowlist policy.", + "example": "admin-vpn-only", + "pattern": "^(?!\\.)[.A-Za-z0-9_-]{1,255}$", + "type": "string" + }, + "userGroups": { + "description": "Target user groups this policy applies to.", + "items": { + "$ref": "#/components/schemas/DeclarativeUserGroupIdentifier" + }, + "type": "array" + }, + "users": { + "description": "Target users this policy applies to.", + "items": { + "$ref": "#/components/schemas/DeclarativeUserIdentifier" + }, + "type": "array" + } + }, + "required": [ + "allowedSources", + "id" + ], + "type": "object" + }, "DeclarativeJwk": { "description": "A declarative form of the JWK.", "properties": { @@ -7289,6 +7331,12 @@ }, "type": "array" }, + "ipAllowlistPolicies": { + "items": { + "$ref": "#/components/schemas/DeclarativeIpAllowlistPolicy" + }, + "type": "array" + }, "jwks": { "items": { "$ref": "#/components/schemas/DeclarativeJwk" diff --git a/schemas/gooddata-automation-client.json b/schemas/gooddata-automation-client.json index fa23dc610..3b9d67f80 100644 --- a/schemas/gooddata-automation-client.json +++ b/schemas/gooddata-automation-client.json @@ -1460,9 +1460,6 @@ }, "DashboardCompoundComparisonCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "operator": { @@ -1503,9 +1500,6 @@ }, "DashboardCompoundRangeCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "from": { diff --git a/schemas/gooddata-export-client.json b/schemas/gooddata-export-client.json index e741ebbe7..f7e71ab37 100644 --- a/schemas/gooddata-export-client.json +++ b/schemas/gooddata-export-client.json @@ -913,9 +913,6 @@ }, "DashboardCompoundComparisonCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "operator": { @@ -956,9 +953,6 @@ }, "DashboardCompoundRangeCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "from": { diff --git a/schemas/gooddata-metadata-client.json b/schemas/gooddata-metadata-client.json index e9182d080..4241117c7 100644 --- a/schemas/gooddata-metadata-client.json +++ b/schemas/gooddata-metadata-client.json @@ -1713,9 +1713,6 @@ }, "DashboardCompoundComparisonCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "operator": { @@ -1756,9 +1753,6 @@ }, "DashboardCompoundRangeCondition": { "allOf": [ - { - "$ref": "#/components/schemas/DashboardCompoundConditionItem" - }, { "properties": { "from": { @@ -3223,10 +3217,9 @@ "type": "boolean" }, "name": { - "description": "Column name", + "description": "Column name. Must not contain NUL (0x00) characters.", "example": "customer_id", "maxLength": 255, - "pattern": "^[^\u0000]*$", "type": "string" }, "referencedTableColumn": { @@ -4272,6 +4265,49 @@ ], "type": "object" }, + "DeclarativeIpAllowlistPolicy": { + "description": "A declarative form of an IP allowlist policy.", + "properties": { + "allowedSources": { + "description": "Allowed source IP addresses or CIDR ranges.", + "example": [ + "203.0.113.10/32", + "198.51.100.0/24" + ], + "items": { + "description": "Allowed source IP addresses or CIDR ranges.", + "example": "[\"203.0.113.10/32\",\"198.51.100.0/24\"]", + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Identifier of an IP allowlist policy.", + "example": "admin-vpn-only", + "pattern": "^(?!\\.)[.A-Za-z0-9_-]{1,255}$", + "type": "string" + }, + "userGroups": { + "description": "Target user groups this policy applies to.", + "items": { + "$ref": "#/components/schemas/DeclarativeUserGroupIdentifier" + }, + "type": "array" + }, + "users": { + "description": "Target users this policy applies to.", + "items": { + "$ref": "#/components/schemas/DeclarativeUserIdentifier" + }, + "type": "array" + } + }, + "required": [ + "allowedSources", + "id" + ], + "type": "object" + }, "DeclarativeJwk": { "description": "A declarative form of the JWK.", "properties": { @@ -4815,6 +4851,12 @@ }, "type": "array" }, + "ipAllowlistPolicies": { + "items": { + "$ref": "#/components/schemas/DeclarativeIpAllowlistPolicy" + }, + "type": "array" + }, "jwks": { "items": { "$ref": "#/components/schemas/DeclarativeJwk" diff --git a/schemas/gooddata-scan-client.json b/schemas/gooddata-scan-client.json index bfe56b5be..cb3612cf0 100644 --- a/schemas/gooddata-scan-client.json +++ b/schemas/gooddata-scan-client.json @@ -234,10 +234,9 @@ "type": "boolean" }, "name": { - "description": "Column name", + "description": "Column name. Must not contain NUL (0x00) characters.", "example": "customer_id", "maxLength": 255, - "pattern": "^[^\u0000]*$", "type": "string" }, "referencedTableColumn": {