asap-protocol 0.3.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. asap_protocol-0.5.0/.cursor/dev-planning/code-review/v0.5.0/sprint-s3-code-review.md +284 -0
  2. asap_protocol-0.5.0/.cursor/dev-planning/code-review/v0.5.0/sprint-s4-code-review.md +99 -0
  3. asap_protocol-0.5.0/.cursor/dev-planning/code-review/v0.5.0/sprint-s5-code-review.md +353 -0
  4. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/prd/prd-v1-roadmap.md +73 -11
  5. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-roadmap.md +133 -74
  6. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s3-detailed.md +105 -80
  7. asap_protocol-0.5.0/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s4-detailed.md +323 -0
  8. asap_protocol-0.5.0/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s5-detailed.md +561 -0
  9. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-docs-detailed.md +0 -1
  10. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-dx-detailed.md +0 -1
  11. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-observability-detailed.md +0 -1
  12. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-performance-detailed.md +0 -1
  13. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-release-detailed.md +0 -1
  14. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-roadmap.md +6 -17
  15. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-security-detailed.md +12 -2
  16. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v1.0.0/tasks-v1.0.0-testing-detailed.md +0 -1
  17. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/ISSUE_TEMPLATE/bug_report.yml +1 -1
  18. asap_protocol-0.5.0/.github/README.md +95 -0
  19. asap_protocol-0.5.0/.github/release-notes-v0.5.0.md +61 -0
  20. asap_protocol-0.5.0/.github/workflows/release.yml +88 -0
  21. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/CHANGELOG.md +85 -0
  22. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/PKG-INFO +22 -5
  23. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/README.md +21 -4
  24. asap_protocol-0.5.0/docs/error-handling.md +376 -0
  25. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/migration.md +144 -0
  26. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/security.md +402 -38
  27. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/transport.md +165 -0
  28. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/pyproject.toml +6 -1
  29. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/__init__.py +1 -1
  30. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/errors.py +167 -0
  31. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/examples/README.md +3 -0
  32. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/examples/run_demo.py +9 -2
  33. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/__init__.py +4 -0
  34. asap_protocol-0.5.0/src/asap/models/constants.py +88 -0
  35. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/entities.py +38 -2
  36. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/envelope.py +7 -1
  37. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/__init__.py +3 -0
  38. asap_protocol-0.5.0/src/asap/transport/circuit_breaker.py +193 -0
  39. asap_protocol-0.5.0/src/asap/transport/client.py +934 -0
  40. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/middleware.py +6 -5
  41. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/server.py +80 -3
  42. asap_protocol-0.5.0/src/asap/transport/validators.py +324 -0
  43. asap_protocol-0.5.0/src/asap/utils/__init__.py +7 -0
  44. asap_protocol-0.5.0/src/asap/utils/sanitization.py +139 -0
  45. asap_protocol-0.5.0/tests/compatibility/__init__.py +1 -0
  46. asap_protocol-0.5.0/tests/compatibility/test_v0_1_0_compatibility.py +95 -0
  47. asap_protocol-0.5.0/tests/compatibility/test_v0_3_0_compatibility.py +119 -0
  48. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/e2e/test_two_agents.py +3 -1
  49. asap_protocol-0.5.0/tests/examples/test_run_demo.py +169 -0
  50. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_entities.py +141 -7
  51. asap_protocol-0.5.0/tests/models/test_payloads_validation.py +84 -0
  52. asap_protocol-0.5.0/tests/test_cli_edge_cases.py +113 -0
  53. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/test_version.py +1 -1
  54. asap_protocol-0.5.0/tests/transport/integration/test_validation_order.py +272 -0
  55. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/test_client.py +221 -0
  56. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/test_middleware.py +86 -15
  57. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/test_server.py +85 -0
  58. asap_protocol-0.5.0/tests/transport/unit/test_circuit_breaker.py +391 -0
  59. asap_protocol-0.5.0/tests/transport/unit/test_circuit_breaker_persistence.py +72 -0
  60. asap_protocol-0.5.0/tests/transport/unit/test_client_coverage_gaps.py +300 -0
  61. asap_protocol-0.5.0/tests/transport/unit/test_retry_backoff.py +513 -0
  62. asap_protocol-0.5.0/tests/transport/unit/test_retry_edge_cases.py +134 -0
  63. asap_protocol-0.5.0/tests/transport/unit/test_validators.py +302 -0
  64. asap_protocol-0.5.0/tests/transport/unit/test_validators_edge_cases.py +115 -0
  65. asap_protocol-0.5.0/tests/utils/__init__.py +3 -0
  66. asap_protocol-0.5.0/tests/utils/test_sanitization.py +153 -0
  67. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/uv.lock +33 -1
  68. asap_protocol-0.3.0/.cursor/dev-planning/code-review/v0.1.0/pr-8-review-temp.md +0 -45
  69. asap_protocol-0.3.0/.cursor/dev-planning/tasks/v0.5.0/README-v0.5.0-tasks.md +0 -91
  70. asap_protocol-0.3.0/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s4-detailed.md +0 -209
  71. asap_protocol-0.3.0/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s5-detailed.md +0 -254
  72. asap_protocol-0.3.0/.cursor/dev-planning/tasks/v1.0.0/README-v1.0.0-tasks.md +0 -81
  73. asap_protocol-0.3.0/.github/workflows/release.yml +0 -36
  74. asap_protocol-0.3.0/docs/error-handling.md +0 -49
  75. asap_protocol-0.3.0/src/asap/models/constants.py +0 -15
  76. asap_protocol-0.3.0/src/asap/transport/client.py +0 -399
  77. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/code-quality-review.md +0 -0
  78. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/create-prd.md +0 -0
  79. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/generate-tasks.md +0 -0
  80. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/reflect.md +0 -0
  81. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/security-pr-review.md +0 -0
  82. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/security-review.md +0 -0
  83. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/task-list-development.md +0 -0
  84. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/commands/test-coverage-review.md +0 -0
  85. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/security-review-report.md +0 -0
  86. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.1.0/pre-pypi-release-review.md +0 -0
  87. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.1.0/sprint3-code-review.md +0 -0
  88. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.1.0/sprint4-code-review.md +0 -0
  89. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.1.0/sprint5-code-review.md +0 -0
  90. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.5.0/sprint-s1-code-review.md +0 -0
  91. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.5.0/sprint-s2-code-review.md +0 -0
  92. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/code-review/v0.5.0/sprint-s2.5-code-review.md +0 -0
  93. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/prd/prd-asap-implementation.md +0 -0
  94. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/prd/prd-review-schedule.md +0 -0
  95. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.1.0/sprint-planning-v0.1.0.md +0 -0
  96. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.1.0/tasks-prd-asap-implementation.md +0 -0
  97. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.1.0/tasks-security-review-report.md +0 -0
  98. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.1.0/tasks-sprint3-improvements.md +0 -0
  99. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s1-detailed.md +0 -0
  100. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s2-detailed.md +0 -0
  101. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/dev-planning/tasks/v0.5.0/tasks-v0.5.0-s2.5-detailed.md +0 -0
  102. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/docs/asap-protocol-banner.png +0 -0
  103. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/docs/general-specs.md +0 -0
  104. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/docs/sprint-planning-v0.1.0.md +0 -0
  105. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/rules/architecture-principles.mdc +0 -0
  106. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/rules/git-commits.mdc +0 -0
  107. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.cursor/rules/python-best-practices.mdc +0 -0
  108. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  109. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  110. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/dependabot.yml +0 -0
  111. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/workflows/ci.yml +0 -0
  112. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.github/workflows/docs.yml +0 -0
  113. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/.gitignore +0 -0
  114. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/CODE_OF_CONDUCT.md +0 -0
  115. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/CONTRIBUTING.md +0 -0
  116. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/LICENSE +0 -0
  117. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/SECURITY.md +0 -0
  118. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/benchmarks/README.md +0 -0
  119. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/benchmarks/__init__.py +0 -0
  120. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/benchmarks/benchmark_models.py +0 -0
  121. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/benchmarks/benchmark_transport.py +0 -0
  122. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/benchmarks/conftest.py +0 -0
  123. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/api-reference.md +0 -0
  124. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/index.md +0 -0
  125. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/metrics.md +0 -0
  126. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/observability.md +0 -0
  127. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/state-management.md +0 -0
  128. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/docs/testing.md +0 -0
  129. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/mkdocs.yml +0 -0
  130. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/agent.schema.json +0 -0
  131. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/artifact.schema.json +0 -0
  132. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/conversation.schema.json +0 -0
  133. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/manifest.schema.json +0 -0
  134. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/message.schema.json +0 -0
  135. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/state_snapshot.schema.json +0 -0
  136. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/entities/task.schema.json +0 -0
  137. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/envelope.schema.json +0 -0
  138. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/parts/data_part.schema.json +0 -0
  139. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/parts/file_part.schema.json +0 -0
  140. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/parts/resource_part.schema.json +0 -0
  141. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/parts/template_part.schema.json +0 -0
  142. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/parts/text_part.schema.json +0 -0
  143. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/artifact_notify.schema.json +0 -0
  144. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/mcp_resource_data.schema.json +0 -0
  145. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/mcp_resource_fetch.schema.json +0 -0
  146. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/mcp_tool_call.schema.json +0 -0
  147. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/mcp_tool_result.schema.json +0 -0
  148. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/message_send.schema.json +0 -0
  149. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/state_query.schema.json +0 -0
  150. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/state_restore.schema.json +0 -0
  151. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/task_cancel.schema.json +0 -0
  152. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/task_request.schema.json +0 -0
  153. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/task_response.schema.json +0 -0
  154. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/schemas/payloads/task_update.schema.json +0 -0
  155. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/scripts/export_schemas.py +0 -0
  156. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/cli.py +0 -0
  157. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/examples/__init__.py +0 -0
  158. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/examples/coordinator.py +0 -0
  159. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/examples/echo_agent.py +0 -0
  160. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/base.py +0 -0
  161. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/enums.py +0 -0
  162. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/ids.py +0 -0
  163. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/parts.py +0 -0
  164. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/payloads.py +0 -0
  165. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/models/types.py +0 -0
  166. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/observability/__init__.py +0 -0
  167. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/observability/logging.py +0 -0
  168. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/observability/metrics.py +0 -0
  169. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/schemas.py +0 -0
  170. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/state/__init__.py +0 -0
  171. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/state/machine.py +0 -0
  172. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/state/snapshot.py +0 -0
  173. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/executors.py +0 -0
  174. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/handlers.py +0 -0
  175. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/src/asap/transport/jsonrpc.py +0 -0
  176. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/conftest.py +0 -0
  177. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/e2e/__init__.py +0 -0
  178. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/examples/__init__.py +0 -0
  179. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/examples/test_coordinator.py +0 -0
  180. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/examples/test_echo_agent.py +0 -0
  181. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_base.py +0 -0
  182. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_enums.py +0 -0
  183. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_envelope.py +0 -0
  184. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_ids.py +0 -0
  185. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_parts.py +0 -0
  186. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/models/test_payloads.py +0 -0
  187. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/observability/__init__.py +0 -0
  188. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/observability/test_logging.py +0 -0
  189. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/observability/test_metrics.py +0 -0
  190. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/state/__init__.py +0 -0
  191. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/state/test_machine.py +0 -0
  192. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/state/test_snapshot.py +0 -0
  193. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/test_cli.py +0 -0
  194. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/test_errors.py +0 -0
  195. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/test_schemas.py +0 -0
  196. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/__init__.py +0 -0
  197. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/conftest.py +0 -0
  198. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/e2e/__init__.py +0 -0
  199. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/e2e/test_full_agent_flow.py +0 -0
  200. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/__init__.py +0 -0
  201. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/test_metrics_cardinality.py +0 -0
  202. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/test_rate_limiting.py +0 -0
  203. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/test_request_size_limits.py +0 -0
  204. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/test_server_core.py +0 -0
  205. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/integration/test_thread_pool_bounds.py +0 -0
  206. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/test_handlers.py +0 -0
  207. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/test_jsonrpc.py +0 -0
  208. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/unit/__init__.py +0 -0
  209. {asap_protocol-0.3.0 → asap_protocol-0.5.0}/tests/transport/unit/test_bounded_executor.py +0 -0
@@ -0,0 +1,284 @@
1
+ # Code Review: PR #19 - feat(security): add replay attack prevention and HTTPS enforcement
2
+
3
+ ## 1. Executive Summary
4
+
5
+ * **Impact Analysis:** **Medium Risk**. New security-critical validation code (timestamp and nonce) integrated into the request processing pipeline. HTTPS enforcement affects all client connections.
6
+ * **Architecture Check:** **Yes**. Implementation follows SOLID principles, separates validation logic into dedicated module (`validators.py`), and uses Protocol pattern for extensibility.
7
+ * **Blockers:** **0** critical issues found.
8
+
9
+ ---
10
+
11
+ ## 2. Critical Issues (Must Fix)
12
+
13
+ *No critical security or logic bugs found.* The implementation is solid, properly handles edge cases, and includes comprehensive test coverage.
14
+
15
+ ---
16
+
17
+ ## 3. Improvements & Refactoring (Strongly Recommended)
18
+
19
+ The following are quality improvements that would enhance the robustness and maintainability of the implementation.
20
+
21
+ ### 3.1 [Concurrency] Potential Race Condition in `InMemoryNonceStore` - `src/asap/transport/validators.py`
22
+
23
+ * **Location:** Lines 169-184 (`is_used` method)
24
+ * **Context:** The `is_used` method performs cleanup and check within a lock, but there's a TOCTOU (time-of-check-time-of-use) race condition between `is_used()` and `mark_used()` calls in `validate_envelope_nonce()`.
25
+ * **Problem:** Two concurrent requests with the same nonce could both pass `is_used()` before either calls `mark_used()`.
26
+ * **Risk:** Low. Under typical load, this race is unlikely. However, for a high-security protocol, this should be addressed.
27
+ * **Suggestion:** Combine check-and-mark into a single atomic operation:
28
+
29
+ ```python
30
+ # file: src/asap/transport/validators.py
31
+
32
+ class InMemoryNonceStore:
33
+ # ... existing code ...
34
+
35
+ def check_and_mark(self, nonce: str, ttl_seconds: int) -> bool:
36
+ """Atomically check if nonce is used and mark it if not.
37
+
38
+ Args:
39
+ nonce: The nonce value to check and mark
40
+ ttl_seconds: Time-to-live in seconds for the nonce
41
+
42
+ Returns:
43
+ True if nonce was already used, False if it was newly marked
44
+ """
45
+ with self._lock:
46
+ self._cleanup_expired()
47
+ if nonce in self._store and self._store[nonce] >= time.time():
48
+ return True # Already used
49
+ self._store[nonce] = time.time() + ttl_seconds
50
+ return False # Newly marked
51
+ ```
52
+
53
+ Then in `validate_envelope_nonce()`:
54
+ ```diff
55
+ - if nonce_store.is_used(nonce):
56
+ - raise InvalidNonceError(...)
57
+ - nonce_store.mark_used(nonce, ttl_seconds=600)
58
+ + if nonce_store.check_and_mark(nonce, ttl_seconds=600):
59
+ + raise InvalidNonceError(...)
60
+ ```
61
+
62
+ **Note:** This would require updating the `NonceStore` Protocol to include the atomic method.
63
+
64
+ ---
65
+
66
+ ### 3.2 [Resilience] Missing Empty Nonce String Validation - `src/asap/transport/validators.py`
67
+
68
+ * **Location:** Lines 261-269
69
+ * **Context:** The nonce validation checks for non-string types but doesn't reject empty strings.
70
+ * **Problem:** An empty string `""` would pass validation and be stored, but it offers no replay protection.
71
+ * **Suggestion:**
72
+
73
+ ```diff
74
+ # file: src/asap/transport/validators.py (Line 263-269)
75
+
76
+ # Validate nonce is a string
77
+ - if not isinstance(nonce, str):
78
+ + if not isinstance(nonce, str) or not nonce:
79
+ raise InvalidNonceError(
80
+ nonce=str(nonce),
81
+ - message=f"Nonce must be a string, got {type(nonce).__name__}",
82
+ + message=f"Nonce must be a non-empty string, got {type(nonce).__name__ if not isinstance(nonce, str) else 'empty string'}",
83
+ details={"envelope_id": envelope.id},
84
+ )
85
+ ```
86
+
87
+ ---
88
+
89
+ ### 3.3 [Observability] Nonce Exposed in Log Output - `src/asap/transport/server.py`
90
+
91
+ * **Location:** Lines 885-889
92
+ * **Context:** The nonce value is logged when validation fails.
93
+ * **Problem:** Nonces, while not directly sensitive, could be useful to attackers for reconnaissance if exposed in logs.
94
+ * **Suggestion:** Consider truncating or hashing the nonce in logs:
95
+
96
+ ```diff
97
+ # file: src/asap/transport/server.py (Lines 885-889)
98
+
99
+ except InvalidNonceError as e:
100
+ logger.warning(
101
+ "asap.request.invalid_nonce",
102
+ envelope_id=envelope.id,
103
+ - nonce=e.nonce,
104
+ + nonce_prefix=e.nonce[:8] + "..." if len(e.nonce) > 8 else e.nonce,
105
+ error=e.message,
106
+ )
107
+ ```
108
+
109
+ ---
110
+
111
+ ### 3.4 [Data Integrity] Hardcoded TTL in `validate_envelope_nonce` - `src/asap/transport/validators.py`
112
+
113
+ * **Location:** Line 280
114
+ * **Context:** The nonce TTL is hardcoded to 600 seconds (10 minutes).
115
+ * **Problem:** This should be configurable or derived from `MAX_ENVELOPE_AGE_SECONDS` to ensure consistency.
116
+ * **Suggestion:**
117
+
118
+ ```diff
119
+ # file: src/asap/transport/validators.py (Line 279-280)
120
+
121
+ + # Use 2x envelope age as TTL to ensure nonces expire after the envelope would
122
+ + # have been rejected anyway, providing some buffer
123
+ + nonce_ttl = MAX_ENVELOPE_AGE_SECONDS * 2 # 10 minutes by default
124
+ - nonce_store.mark_used(nonce, ttl_seconds=600)
125
+ + nonce_store.mark_used(nonce, ttl_seconds=nonce_ttl)
126
+ ```
127
+
128
+ ---
129
+
130
+ ### 3.5 [Defensive Coding] IPv6 Localhost Edge Case - `src/asap/transport/client.py`
131
+
132
+ * **Location:** Lines 207-224 (`_is_localhost` method)
133
+ * **Context:** IPv6 localhost detection handles `::1` but not full forms like `[::1]`.
134
+ * **Problem:** URLs like `http://[::1]:8000` would have hostname `[::1]` (with brackets) not `::1`.
135
+ * **Suggestion:**
136
+
137
+ ```diff
138
+ # file: src/asap/transport/client.py (Lines 222-224)
139
+
140
+ hostname_lower = hostname.lower()
141
+ - return hostname_lower in ("localhost", "127.0.0.1", "::1")
142
+ + # Handle both ::1 and [::1] (bracket notation from URL parsing)
143
+ + return hostname_lower in ("localhost", "127.0.0.1", "::1", "[::1]")
144
+ ```
145
+
146
+ ---
147
+
148
+ ### 3.6 [Testing] Missing Integration Test for Validation Order - `tests/transport/`
149
+
150
+ * **Location:** New test file recommended
151
+ * **Context:** Timestamp validation runs before nonce validation in the server handler.
152
+ * **Problem:** No test verifies the validation order or that both validations are consistently applied together.
153
+ * **Suggestion:** Add an integration test that verifies:
154
+ 1. Invalid timestamp is rejected before nonce check
155
+ 2. Valid timestamp with invalid nonce is rejected
156
+ 3. Both validations return appropriate error codes
157
+
158
+ ---
159
+
160
+ ## 4. Nitpicks & Questions
161
+
162
+ ### Code Style
163
+
164
+ * **`src/asap/transport/validators.py` (Line 10):** `datetime, timezone` import could be grouped with stdlib imports for PEP 8 compliance, but current grouping is acceptable.
165
+
166
+ * **`src/asap/errors.py` (Lines 229-234):** The conditional dict merge pattern is creative but slightly hard to read:
167
+ ```python
168
+ **(age_seconds is not None and {"age_seconds": age_seconds} or {})
169
+ ```
170
+ Consider explicit if/else for clarity (but this is a nitpick - current code works correctly).
171
+
172
+ ### Documentation
173
+
174
+ * **`docs/security.md`:** Excellent comprehensive documentation. Minor suggestion: add a "Quick Reference" table at the top summarizing the validation constants and their values.
175
+
176
+ ### Type Annotations
177
+
178
+ * **`src/asap/transport/client.py` (Line 208):** `parsed_url: Any` type annotation loses type safety. Consider using `ParseResult` from `urllib.parse`:
179
+ ```python
180
+ from urllib.parse import ParseResult
181
+
182
+ @staticmethod
183
+ def _is_localhost(parsed_url: ParseResult) -> bool:
184
+ ```
185
+
186
+ ### Test Coverage
187
+
188
+ * **`tests/transport/unit/test_validators.py`:** Tests are well-structured. The `test_expired_nonce_allowed_again` test uses `time.sleep(1.1)` which is acceptable for unit tests but could cause flakiness. Consider using time mocking for more reliable tests.
189
+
190
+ ---
191
+
192
+ ## 5. Domain-Specific Analysis
193
+
194
+ ### 5.1 Replay Attack Prevention
195
+
196
+ **Timestamp Validation:**
197
+ - ✅ Correct implementation of 5-minute age window
198
+ - ✅ Correct implementation of 30-second future tolerance
199
+ - ✅ Timezone handling covers naive and non-UTC timestamps
200
+ - ✅ Error messages include detailed context for debugging
201
+
202
+ **Nonce Validation:**
203
+ - ✅ Optional by design (backward compatible)
204
+ - ✅ Lazy cleanup prevents unbounded memory growth
205
+ - ⚠️ Race condition between `is_used()` and `mark_used()` (see Section 3.1)
206
+ - ⚠️ Hardcoded 10-minute TTL (see Section 3.4)
207
+
208
+ ### 5.2 HTTPS Enforcement
209
+
210
+ **Client-Side Validation:**
211
+ - ✅ Localhost exception for development is appropriate
212
+ - ✅ Clear error messages with override instructions
213
+ - ✅ Warning log for HTTP localhost usage
214
+ - ⚠️ IPv6 localhost edge case (see Section 3.5)
215
+
216
+ ### 5.3 Concurrency Safety
217
+
218
+ | Component | Thread-Safe | Notes |
219
+ |-----------|-------------|-------|
220
+ | `InMemoryNonceStore` | ✅ Yes | Uses `RLock` for all operations |
221
+ | `validate_envelope_timestamp` | ✅ Yes | Stateless function |
222
+ | `validate_envelope_nonce` | ⚠️ Partial | TOCTOU race (see Section 3.1) |
223
+
224
+ ---
225
+
226
+ ## 6. Verification Results
227
+
228
+ ### Automated Tests
229
+
230
+ | Check | Command | Result |
231
+ |-------|---------|--------|
232
+ | Unit Tests | `uv run pytest tests/transport/unit/test_validators.py -v` | ✅ **11/11 passed** |
233
+ | HTTPS Tests | `uv run pytest tests/transport/test_client.py -v -k HTTPS` | ✅ **6/6 passed** |
234
+ | Full Suite | `uv run pytest` | ✅ **627 passed** |
235
+ | Coverage | `pytest --cov` | ✅ **91.90%** |
236
+
237
+ ### Static Analysis
238
+
239
+ | Check | Command | Result |
240
+ |-------|---------|--------|
241
+ | Linting | `uv run ruff check src/asap/transport/` | ✅ **All checks passed** |
242
+ | Type Check | `uv run mypy --strict src/asap/transport/` | ✅ **No issues found** |
243
+
244
+ ### Manual Verification
245
+
246
+ * **Timestamp validation flow:** Traced through `server.py` lines 856-879, confirms early return on validation failure.
247
+ * **Nonce validation flow:** Traced through `server.py` lines 881-904, confirms proper error handling.
248
+ * **HTTPS enforcement:** Traced through `client.py` lines 174-197, confirms localhost exception logic.
249
+
250
+ ---
251
+
252
+ ## 7. Commits Review
253
+
254
+ The PR follows atomic commit principles with clear conventional commit messages:
255
+
256
+ | Commit | Type | Description | Status |
257
+ |--------|------|-------------|--------|
258
+ | `e3ca11a` | feat | Add timestamp validation constants | ✅ Well-scoped |
259
+ | `ffe7127` | feat | Add timestamp validation for replay prevention | ✅ Well-scoped |
260
+ | `57f324d` | feat | Add optional nonce validation | ✅ Well-scoped |
261
+ | `7ba44f6` | feat | Integrate timestamp validation in handler | ✅ Well-scoped |
262
+ | `5e03420` | feat | Enforce HTTPS for production connections | ✅ Well-scoped |
263
+ | `37c9dae` | test | Add timestamp and HTTPS validation tests | ✅ Well-scoped |
264
+ | `97bdbf3` | docs | Add replay prevention and HTTPS docs | ✅ Well-scoped |
265
+ | `57e6f2d` | test | Add edge case tests for improved coverage | ✅ Well-scoped |
266
+
267
+ ---
268
+
269
+ ## 8. Conclusion
270
+
271
+ **APPROVED FOR MERGE** ✅
272
+
273
+ The implementation is production-ready with strong security foundations. The suggestions in Section 3 are improvements for future iterations, not blockers.
274
+
275
+ **Key Strengths:**
276
+ - Clean separation of concerns with dedicated `validators.py` module
277
+ - Comprehensive error handling with detailed context
278
+ - Backward compatible (nonce validation is optional)
279
+ - Thorough documentation and test coverage
280
+
281
+ **Recommended Follow-ups (Post-Merge):**
282
+ 1. Address the TOCTOU race condition in `InMemoryNonceStore` (Priority: Medium)
283
+ 2. Add empty nonce string validation (Priority: Low)
284
+ 3. Make nonce TTL configurable or derived from envelope age constant (Priority: Low)
@@ -0,0 +1,99 @@
1
+ # Code Review: PR #20 (S4 Retry & Auth)
2
+
3
+ ## 1. Executive Summary
4
+ * **Impact Analysis:** **Medium-High Risk**. The core retry and circuit breaker logic is solid, but a critical gap in exception handling (Timeouts) compromises the improved resilience.
5
+ * **Architecture Check:** **Yes**. The implementation aligns well with the planned architecture, utilizing decorators, efficient constants, and proper layering.
6
+ * **Blockers:** **1** critical issue found (Unhandled Timeouts).
7
+
8
+ ## 2. Critical Issues (Must Fix)
9
+ *Issues that cause bugs, security risks, or strictly violate architecture/linting rules.*
10
+
11
+ ### Unhandled Request Timeouts - src/asap/transport/client.py
12
+ * **Location:** Lines 613-800 (`send` method retry loop)
13
+ * **Problem:** The current implementation catches `httpx.ConnectError` but fails to catch `httpx.TimeoutException`. If a request times out (network stall, firewall, slow server), the exception will bubble up immediately, bypassing the retry logic and, critically, **failing to record the failure in the Circuit Breaker**. This defeat the purpose of the circuit breaker for one of its most important use cases (unresponsive services).
14
+ * **Recommendation:** Catch `httpx.TimeoutException`, record the failure, and trigger the retry logic.
15
+
16
+ ```diff
17
+ - except httpx.ConnectError as e:
18
+ - error_msg = (
19
+ - f"Connection error to {self.base_url}: {e}. "
20
+ - f"Verify the agent is running and accessible."
21
+ - )
22
+ - last_exception = ASAPConnectionError(error_msg, cause=e, url=self.base_url)
23
+ - # Log retry attempt
24
+ - if attempt < self.max_retries - 1:
25
+ - delay = self._calculate_backoff(attempt)
26
+ - logger.warning(
27
+ - "asap.client.retry",
28
+ - # ...
29
+ - )
30
+ - logger.info(...)
31
+ - await asyncio.sleep(delay)
32
+ - continue
33
+ + except (httpx.ConnectError, httpx.TimeoutException) as e:
34
+ + is_timeout = isinstance(e, httpx.TimeoutException)
35
+ + error_type = "Timeout" if is_timeout else "Connection error"
36
+ + error_msg = (
37
+ + f"{error_type} to {self.base_url}: {e}. "
38
+ + f"Verify the agent is running and accessible."
39
+ + )
40
+ + last_exception = ASAPConnectionError(error_msg, cause=e, url=self.base_url)
41
+ +
42
+ + # Log retry attempt
43
+ + if attempt < self.max_retries - 1:
44
+ + delay = self._calculate_backoff(attempt)
45
+ + logger.warning(
46
+ + "asap.client.retry",
47
+ + # ... args ...
48
+ + message=f"{error_type}, retrying in {delay:.2f}s..."
49
+ + )
50
+ + await asyncio.sleep(delay)
51
+ + continue
52
+ +
53
+ + # Retries exhausted: Record failure in Circuit Breaker
54
+ + if self._circuit_breaker is not None:
55
+ + self._circuit_breaker.record_failure()
56
+ + # Log circuit state change if needed (copy logic from 5xx handler)
57
+ +
58
+ + raise last_exception
59
+ ```
60
+
61
+ ## 3. Improvements & Refactoring (Strongly Recommended)
62
+
63
+ ### Circuit Breaker Reset on Remote Error - src/asap/transport/client.py
64
+ - **Location:** Lines 741-748 (`ASAPRemoteError` handling)
65
+ - **Context:** If the server responds with a valid JSON-RPC error (e.g., `-32603` or "Method not found"), it means the *connection* and *transport* are healthy. Currently, this path does not call `record_success()`, so the circuit breaker acts as if the request never succeeded (failure count isn't reset). This could lead to a "stale" failure count effectively reducing the threshold for subsequent real failures.
66
+ - **Suggestion:** Consider a valid JSON-RPC error as a "Success" from the Circuit Breaker's perspective (service is reachable).
67
+
68
+ ```diff
69
+ # Check for JSON-RPC error
70
+ if "error" in json_response:
71
+ + # Record success pattern (service is reachable)
72
+ + if self._circuit_breaker is not None:
73
+ + self._circuit_breaker.record_success()
74
+ +
75
+ error = json_response["error"]
76
+ raise ASAPRemoteError(...)
77
+ ```
78
+
79
+ ### Robust Retry-After Parsing - src/asap/transport/client.py
80
+ - **Location:** Line 676
81
+ - **Context:** The HTTP `Retry-After` header can be an HTTP Date string. The current implementation only supports seconds (`float`).
82
+ - **Suggestion:** Add support for Date parsing using `email.utils.parsedate_to_datetime`.
83
+
84
+ ```diff
85
+ - delay = float(retry_after)
86
+ + # Simple check for digit, else try date parsing
87
+ + if retry_after.replace('.', '', 1).isdigit():
88
+ + delay = float(retry_after)
89
+ + else:
90
+ + # Add date parsing logic here (or TODO)
91
+ + # from email.utils import parsedate_to_datetime
92
+ + # ... calculate delta ...
93
+ ```
94
+
95
+ ## 4. Nitpicks & Questions
96
+
97
+ * **[src/asap/transport/client.py] (Line 368)**: `self._request_counter` is updated with `+= 1` which is not atomic across threads. Since `CircuitBreaker` uses `RLock`, there is an implication of thread-safety. If `ASAPClient` is shared across threads, this could cause ID collisions. Consider using `itertools.count` and `next()` or a lock if thread safety is a requirement.
98
+
99
+ * **[src/asap/transport/client.py] (Line 284)**: The `__init__` method argument list is getting very long (11 args). Consider grouping the retry/circuit-breaker configs into a `RetryConfig` dataclass/pydantic model to avoid `False, 5, 60.0` boolean trap issues and clean up the signature.