fix(client): normalize malformed agent card parsing errors - #1307
Conversation
🧪 Code Coverage (vs
|
There was a problem hiding this comment.
Checking isinstance(agent_card_data, dict) catches non-object root responses, but the _handle_*_compatibility helpers below still raise uncaught AttributeError/TypeError when nested fields have wrong types:
{"supportsAuthenticatedExtendedCard": true, "capabilities": null}(TypeErroron'extendedAgentCard' not in capabilities){"supportsAuthenticatedExtendedCard": true, "capabilities": []}(TypeErroron item assignment){"url": "https://example.com", "additionalInterfaces": [null]}(AttributeErroroniface.get){"skills": null}or{"skills": [null]}(TypeError/AttributeError){"security": "invalid"}(AttributeErroronsec_dict.items())
Could we catch (TypeError, AttributeError) in parse_agent_card and raise ParseError(...) from e (or explicitly raise ParseError for invalid nested types in the compatibility helpers) and add a couple of test cases for malformed nested fields?
Assisted-by: OpenAI GPT-6 <noreply@openai.com>
|
@mykytanetipa Thanks for the review. fdd70db wraps the |
Description
When an agent-card endpoint returns HTTP 200 with valid JSON such as
null, an array, a string, a number, or a boolean, the compatibility helpers raiseAttributeErrororTypeError. Malformed nested legacy fields can raise the same exceptions even when the root is an object. These exceptions escapeA2ACardResolver.get_agent_card()instead of the documentedAgentCardResolutionError.Validate that the decoded value is a JSON object at the parser boundary. Convert
TypeErrorandAttributeErrorfrom the three compatibility helpers intoParseError, retaining their original cause. The resolver already wrapsParseErrorintoAgentCardResolutionError; protobuf parsing and signature verification retain their existing exception handling.Regression tests use
httpx.MockTransportwith real JSON decoding: eight non-object roots and all six malformed nested cases from the review (null/list capabilities, a null additional interface, null skills/a null skill, and string security). Every new case failed before its corresponding fix. The nested-field tests also verify the full exception cause chain.Validation
scripts/lint.sh(uv run --locked ruff check --fix,ruff format, andty check) passed.tyexits successfully with three existing unused-ignore warnings.uv run --locked pytest tests/client/test_card_resolver.py -q: 46 passed.uv run --locked pytest --ignore=tests/integration --cov=src --cov-report=term-missing -q: 1,788 passed, 169 skipped, 3 xfailed; 91% coverage.card_resolver.pyhas 100% statement and branch coverage.PYTHONIOENCODING=utf-8, sample integration smoke tests: 3 passed.os.killpg) and push-notification fixtures (a FastAPI local callable cannot be pickled under Windows multiprocessing). These platform limitations are outside this change.AI assistance: OpenAI Codex (GPT-6) was used to implement, reproduce, and test this change under the account owner's explicit authorization. The follow-up implements the human maintainer's review request and received another independent review before submission.