Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions cloudpub/ms_azure/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,12 @@ def _contains_certification_error(item: Any) -> bool:
message: str = item.get("message", "")
if code == "invalidState" and "certification" in message.lower():
return True
if not isinstance(item.get('details'), list):
details = item.get('details')
if details is None:
return False
Comment on lines +559 to +561

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): An explicitly present "details": null value is treated as equivalent to an omitted field and returns False instead of raising InvalidSchema, even though the Azure schema defines details as an optional array rather than a nullable value. This silently accepts malformed error payloads and can cause certification failures hidden behind such a payload to be classified as retryable.

Triggers: When Azure returns an error object containing "details": null.

Suggested fix: Check if "details" not in item for the omitted-field case, then retain the non-list validation so an explicit null remains invalid unless the schema is confirmed to allow it.

Suggested change
details = item.get('details')
if details is None:
return False
if "details" not in item:
return False
details = item.get('details')

if not isinstance(details, list):
raise InvalidSchema(f"Invalid schema for 'details' inside error object: {item}")
for detail in item.get("details") or []:
for detail in details:
if _contains_certification_error(detail):
return True
return False
Expand Down
16 changes: 16 additions & 0 deletions tests/ms_azure/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,8 +522,24 @@ def test_is_certification_error(cert_error_failure: list[Dict[str, Any]]) -> Non
],
}
]
# Inner-errors (in "details") may omit their own "details" field. This must not raise
# InvalidSchema — it just means no further nesting, so it's not a certification error.
no_details_non_certification_error: list[Dict[str, Any]] = [
{
"resourceId": "virtual-machine-plan-technical-configuration/test",
"code": "conflict",
"message": "PackageSet failed CreateUpdate with response code: BadRequest",
"details": [
{
"code": "invalidState",
"message": "PackageSet failed CreateUpdate with response code: BadRequest",
}
],
}
]
assert is_certification_error(cert_error_failure) is True
assert is_certification_error(valid_non_certification_errors) is False
assert is_certification_error(no_details_non_certification_error) is False
assert is_certification_error([]) is False


Expand Down
Loading