Skip to content

feat(gooddata-sdk): [AUTO] Add IP allowlist policy CRUD endpoints to metadata API#1621

Open
yenkins-admin wants to merge 1 commit into
masterfrom
auto/openapi-sync-C005-20260518-r25465
Open

feat(gooddata-sdk): [AUTO] Add IP allowlist policy CRUD endpoints to metadata API#1621
yenkins-admin wants to merge 1 commit into
masterfrom
auto/openapi-sync-C005-20260518-r25465

Conversation

@yenkins-admin
Copy link
Copy Markdown
Contributor

Summary

Added IP allowlist policy CRUD endpoints to the Python SDK. Created entity model CatalogIpAllowlistPolicy and CatalogIpAllowlistPolicyTargets, extended GoodDataApiClient with _do_get_request/_do_put_request/_do_delete_request HTTP helpers, added 7 service methods to CatalogOrganizationService (get, list with pagination, create, update, delete, addTargets, removeTargets), exported new classes from gooddata_sdk.init, and added an integration test plus parametrized unit test for from_api deserialization.

Impact: new_feature | Services: gooddata-metadata-client

Source commits (gdc-nas):

  • 147ec88 by Peter Plocháň — Merge pull request #22741 from gooddata/dnik/md-allowlist-crud

Files changed

  • packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/entity_model/ip_allowlist_policy.py
  • packages/gooddata-sdk/src/gooddata_sdk/client.py
  • packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py
  • packages/gooddata-sdk/src/gooddata_sdk/__init__.py
  • packages/gooddata-sdk/tests/catalog/test_catalog_organization.py
  • packages/gooddata-sdk/tests/catalog/unit_tests/test_ip_allowlist_policy.py

Agent decisions

Decisions (4)

raw HTTP vs waiting for api-client regeneration — Wrap raw HTTP via new _do_get_request/_do_put_request/_do_delete_request helpers on GoodDataApiClient

  • Alternatives: Set status=error and wait for api-client regeneration cycle, Hand-write generated model files (blocked by security hook)
  • Why: The generated api-client has no JsonApiIpAllowlistPolicy* models or EntitiesApi methods yet. Per the instructions, wrapping raw HTTP is the preferred path for new endpoints when the generated client is missing symbols.

reusing CatalogAssigneeIdentifier — Import existing CatalogAssigneeIdentifier from catalog.identifier instead of creating a new class

  • Alternatives: Create a new CatalogIpAllowlistAssigneeIdentifier with a unique name, Use plain dicts for targets
  • Why: catalog.identifier already exports CatalogAssigneeIdentifier backed by the generated AssigneeIdentifier model with proper enum validation. Creating a duplicate class would shadow the existing export in init.py.

pagination in list_ip_allowlist_policies — Follow JSON:API links.next transparently in a while loop

  • Alternatives: Return only the first page (breaks consumer expectations), Expose page/size parameters
  • Why: Consistent with the SDK contract of returning all entities from list_* methods. Uses urlparse to extract the path from the next URL returned by the server.

from_api signature override — Override from_api with signature matching the base class pattern (entity: dict[str, Any]) returning the concrete type

  • Alternatives: Use cattrs.structure() with a custom converter, Flatten the entity structure
  • Why: The API response is raw JSON (camelCase keys), not a generated model object. Custom deserialization is needed for nested attributes and relationships.
Assumptions to verify (4)
  • The JSON:API response for ipAllowlistPolicy entities uses camelCase keys (allowedSources, userGroups) as standard for GoodData APIs
  • The addTargets/removeTargets endpoints return 204 No Content on success
  • The create endpoint returns 201 with the created entity body
  • Relationships in the entity response follow the JSON:API {data: [{id, type}]} format
Risks (3)
  • The API may return relationships in a format other than standard JSON:API {data:[{id,type}]} shape — from_api would silently produce empty users/user_groups lists
  • PUT update endpoint may require all relationship fields even if not originally set; policies without relationships may fail on update
  • response.reason attribute on requests.Response may be None for some HTTP implementations, causing NotFoundException(reason=None)
Layers touched (3)
  • entity_model — New entity model; reuses existing CatalogAssigneeIdentifier from catalog.identifier to avoid name collision
    • packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/entity_model/ip_allowlist_policy.py
  • public_api — HTTP helpers added to GoodDataApiClient; CRUD service methods added to CatalogOrganizationService
    • packages/gooddata-sdk/src/gooddata_sdk/__init__.py
    • packages/gooddata-sdk/src/gooddata_sdk/client.py
    • packages/gooddata-sdk/src/gooddata_sdk/catalog/organization/service.py
  • tests — Integration test + parametrized unit test for from_api deserialization
    • packages/gooddata-sdk/tests/catalog/test_catalog_organization.py
    • packages/gooddata-sdk/tests/catalog/unit_tests/test_ip_allowlist_policy.py
OpenAPI diff
--- a/gooddata-metadata-client.json
+++ b/gooddata-metadata-client.json
@@ -7119,6 +7184,21 @@
+      "IpAllowlistPolicyTargets": {
+        "description": "Target delta for IP allowlist policy actions.",
+        "properties": {
+          "targets": {
+            "items": { "$ref": "#/components/schemas/AssigneeIdentifier" },
+            "type": "array"
+          }
+        },
+        "required": [ "targets" ],
+        "type": "object"
+      },
@@ -16067,6 +16147,230 @@
+      "JsonApiIpAllowlistPolicyIn": { ... },
+      "JsonApiIpAllowlistPolicyInDocument": { ... },
+      "JsonApiIpAllowlistPolicyOut": { ... },
+      "JsonApiIpAllowlistPolicyOutDocument": { ... },
+      "JsonApiIpAllowlistPolicyOutIncludes": { ... },
+      "JsonApiIpAllowlistPolicyOutList": { ... },
+      "JsonApiIpAllowlistPolicyOutWithLinks": { ... },
@@ -28269,6 +28549,76 @@
+    "/api/v1/actions/ipAllowlistPolicies/{id}/addTargets": {
+      "post": {
+        "operationId": "addTargets",
+        "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IpAllowlistPolicyTargets" } } }, "required": true },
+        "responses": { "204": { "description": "No Content" } },
+        "summary": "Add targets to IP allowlist policy"
+      }
+    },
+    "/api/v1/actions/ipAllowlistPolicies/{id}/removeTargets": {
+      "post": {
+        "operationId": "removeTargets",
+        "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/IpAllowlistPolicyTargets" } } }, "required": true },
+        "responses": { "204": { "description": "No Content" } },
+        "summary": "Remove targets from IP allowlist policy"
+      }
+    },
@@ -33206,6 +33556,345 @@
+    "/api/v1/entities/ipAllowlistPolicies": {
+      "get": { "operationId": "getAllEntities@IpAllowlistPolicies", "summary": "Get all IpAllowlistPolicy entities", ... },
+      "post": { "operationId": "createEntity@IpAllowlistPolicies", "summary": "Post IpAllowlistPolicy entities", ... }
+    },
+    "/api/v1/entities/ipAllowlistPolicies/{id}": {
+      "delete": { "operationId": "deleteEntity@IpAllowlistPolicies", "summary": "Delete IpAllowlistPolicy entity" },
+      "get": { "operationId": "getEntity@IpAllowlistPolicies", "summary": "Get IpAllowlistPolicy entity" },
+      "put": { "operationId": "updateEntity@IpAllowlistPolicies", "summary": "Put IpAllowlistPolicy entity" }
+    },

Workflow run


Generated by SDK OpenAPI Sync workflow

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant