sailpoint-oss / python-sdk

MIT License
4 stars 3 forks source link

sailpoint.beta.IdentityHistoryApi.get_historical_identity fails to deserialize results #9

Open rob-buskens-sp opened 2 months ago

rob-buskens-sp commented 2 months ago

Problem: using a valid account id (see postman output below) the following API call fails.

identity_snapshot = sailpoint.beta.IdentityHistoryApi(beta_client).get_historical_identity(id=deleted_account.id) results in: Traceback (most recent call last): File "", line 1, in File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/pydantic/validate_call_decorator.py", line 59, in wrapper_function return validate_call_wrapper(*args, **kwargs) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/pydantic/_internal/_validate_call.py", line 81, in call res = self.pydantic_validator.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/api/identity_history_api.py", line 893, in get_historical_identity return self.api_client.response_deserialize( File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/api_client.py", line 316, in response_deserialize return_data = self.deserialize(response_text, response_type) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/api_client.py", line 392, in deserialize return self.deserialize(data, response_type) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/api_client.py", line 431, in deserialize return self.deserialize_model(data, klass) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/api_client.py", line 733, in deserialize_model return klass.from_dict(data) File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/sailpoint/beta/models/identity_history_response.py", line 89, in from_dict _obj = cls.model_validate({ File "/Users/rob.buskens/Documents/Code/isc-hidden-identities/venv/lib/python3.9/site-packages/pydantic/main.py", line 551, in model_validate return cls.pydantic_validator.validate_python( pydantic_core._pydantic_core.ValidationError: 5 validation errors for IdentityHistoryResponse accessItemCount.app Input should be a valid string [type=string_type, input_value=0, input_type=int] For further information visit https://errors.pydantic.dev/2.7/v/string_type accessItemCount.role Input should be a valid string [type=string_type, input_value=0, input_type=int] For further information visit https://errors.pydantic.dev/2.7/v/string_type accessItemCount.entitlement Input should be a valid string [type=string_type, input_value=0, input_type=int] For further information visit https://errors.pydantic.dev/2.7/v/string_type accessItemCount.accessProfile Input should be a valid string [type=string_type, input_value=0, input_type=int] For further information visit https://errors.pydantic.dev/2.7/v/string_type accessItemCount.account Input should be a valid string [type=string_type, input_value=0, input_type=int] For further information visit https://errors.pydantic.dev/2.7/v/string_type

in postman for that API and id: { "snapshot": "2024-04-16T17:10:15.485Z", "id": "a772b05d2d1d400a873985f4261a9323", "displayName": "10 Black", "attributes": {}, "deletedDate": "2024-04-16T17:10:15.485Z", "latestEventSnapshotDate": null, "accessItemCount": { "app": 0, "role": 0, "entitlement": 0, "accessProfile": 0, "account": 0 } }

doesn't like the counts coming back as numbers? may be other issues as the response object is doing validation for strings.

class IdentityHistoryResponse(BaseModel): """ IdentityHistoryResponse """ # noqa: E501 id: Optional[StrictStr] = Field(default=None, description="the identity ID") display_name: Optional[StrictStr] = Field(default=None, description="the display name of the identity", alias="displayName") snapshot: Optional[StrictStr] = Field(default=None, description="the date when the identity record was created") deleted_date: Optional[StrictStr] = Field(default=None, description="the date when the identity was deleted", alias="deletedDate") access_item_count: Optional[Dict[str, StrictStr]] = Field(default=None, description="A map containing the count of each access item", alias="accessItemCount") attributes: Optional[Dict[str, StrictStr]] = Field(default=None, description="A map containing the identity attributes") __properties: ClassVar[List[str]] = ["id", "displayName", "snapshot", "deletedDate", "accessItemCount", "attributes"]

using 1.0.4 of the python-sdk running under Python 3.9.6 in a venv used the sail cli to create the project.

rob-buskens-sp commented 2 months ago

code sample fails on deleted identities that have accounts.

  1. access item counts, are numbers, not strings.
  2. deleted identities don't have attributes
import sailpoint.v3
import sailpoint.beta
from sailpoint.configuration import Configuration
from sailpoint.paginator import Paginator
from sailpoint.v3.models.search import Search
from pprint import pprint

configuration = Configuration()

matches = 0
count = 0

with sailpoint.v3.ApiClient(configuration) as v3_client, \
     sailpoint.beta.ApiClient(configuration) as beta_client:

    deleted_accounts = Paginator.paginate(sailpoint.beta.IdentityHistoryApi(beta_client).list_historical_identities, result_limit=1000, is_deleted=True)

    for deleted_account in deleted_accounts:
        print(f'checking  account {deleted_account.display_name:<60}', end='\r')

        identity_snapshot = sailpoint.beta.IdentityHistoryApi(beta_client).get_historical_identity(id=deleted_account.id)

        if (identity_snapshot.access_item_count["account"] > 0):
            matches += 1
            print(identity_snapshot.id, identity_snapshot.display_name, "is deleted but has accounts")

        count += 1

print(f'{count} accounts were checked')

Changing two of the StrictStr to Any highlights what's off in the generated code as this allows the code to run:

class IdentityHistoryResponse(BaseModel): IdentityHistoryResponse

access_item_count: Optional[Dict[str, ***Any***]] = Field(default=None, description="A map containing the count of each access item", alias="accessItemCount")
attributes: Optional[Dict[str, ***Any***]] = Field(default=None, description="A map containing the identity attributes")
__properties: ClassVar[List[str]] = ["id", "displayName", "snapshot", "deletedDate", "accessItemCount", "attributes"]

Seems something needs to be tweaked in the api spec, or the generator config.