Skip to content

v2.5.1

Choose a tag to compare

@github-actions github-actions released this 26 Jun 18:08
194d8bb

Code quality patch — behavior-preserving refactor of the transport, storage, auth, and integration layers accumulated through v2.5.0, plus six correctness and security fixes. No wire-protocol, manifest schema, or public API breaking changes.

Deprecated import paths keep working via shims until v2.6.0.

Fixed

  • revoke_cascade atomicity: delegation revocation now runs in a single SQLite transaction (BEGIN→walk→COMMIT, rollback on failure); the in-memory store holds an asyncio.Lock across the cascade so concurrent register_issued can't leave children un-revoked.
  • usage_events schema: one canonical DDL owner in state/stores/sqlite.py; both indexes created with IF NOT EXISTS regardless of store init order, fixing schema/query-plan divergence.
  • Host-JWT verifier: collapsed the divergent verifiers into one verify_host_bearer; revoked hosts now return 403 (was 401) on every protected route, including /asap/agent/reactivate.
  • WebSocket OAuth2 bypass: /asap/ws no longer skips OAuth2Middleware. In OAuth2-only deployments the WS path now requires a Bearer JWT in the handshake Authorization header and rejects with close code 4401 when absent or invalid. Deploys without an OAuth2 IdP are unchanged.
  • OpenAPI handler: hoisted the inline format_www_authenticate_asap import to module top; OpenAPIPathParameterError.__init__ no longer raises (validation moved to for_missing()/for_invalid() factories). resolve_headers stays as documented public API.
  • Client correlation binding: the client now asserts response.correlation_id == request.id in send(), batch(), and the WS recv loop, raising ProtocolCorrelationError (previously only checked non-empty).

Changed

  • Storage consolidation: six SQLite backends (snapshot, metering, delegation, SLA, audit, plus the economics metering store) now subclass a shared AsyncSqliteRepository (state/stores/_sqlite_base.py) with one WAL setup, transaction(), parse_iso, and build_where. server.py uses the new MeteringStorageBridge directly; metering_storage_adapter is kept as a one-line shim.
  • server.py decomposition: split into create_*_router factories plus routes/{health,jsonrpc,websocket,audit}.py (2256 → 1000 LOC); create_app is thin wiring. Shared request prep (parse→auth→envelope→timestamp→nonce) moved to ASAPRequestHandler._prepare_request.
  • client.py decomposition: split into a client/ package (_core, _send, _discovery, _helpers); get_manifest/discover now share _fetch_and_cache_manifest, and send's Retry-After parser is extracted. from asap.transport.client import ASAPClient is unchanged.
  • websocket.py decomposition: split into asap/transport/ws/ (codecs, client, server, pool, _recv, _ack, _dispatch, _actions, _errors); _make_fake_request is gone and WS dispatches envelopes directly through _prepare_request. websocket.py stays as a re-export shim.
  • Integrations: shared asap/integrations/_base.py centralizes JSON-schema→Pydantic conversion, URN-scoped skill resolve cache, and per-exception error formatting; langchain/crewai/llamaindex/smolagents slimmed to glue-only (71–80 LOC each).
  • OAuth2Middleware JWKS: delegates to one shared JWKSValidator instead of its own cache; HTTP and WS now use the same validator and TTL (JWKS_CACHE_TTL_SECONDS=86400).
  • MCPServer tool registration: the untyped 5-tuple is now a frozen ToolRegistration dataclass with per-tool capability metadata.
  • RemoteRPCError: RemoteFatalRPCError/RemoteRecoverableRPCError collapse into one RemoteRPCError with an is_recoverable property; the old names stay as deprecated subclasses.
  • Identity rate limiting: the 9 inline limiter checks now use Depends(require_identity_limiter); a missing limiter returns 503 (was AttributeError → 500).
  • auth/ modules: claimsjwks/middleware, utilsscopes, lifecycleidentity; WebAuthnSelfAuthVerifier deleted (WebAuthnVerifierImpl satisfies the protocol directly).
  • MCP Auth Bridge: folded asap.adapters.mcp.* into asap.mcp.auth.*; asap.adapters.mcp stays as a re-export shim.

Removed

  • asap.transport root re-exports: start_periodic_cleanup, WebhookDelivery, RetryPolicy, compute_signature, and other tuning/webhook internals are no longer re-exported from asap.transport.__init__ — import them from their owning modules (asap.transport.cache, asap.transport.webhook).
  • asap.transport.codecs package: inlined into asap.transport.lambda_codec; WS framing primitives moved to asap.transport.ws.codecs. No shim (grep-verified zero external callers).
  • NonceStore.is_used / mark_used: replaced by the atomic check_and_mark. Custom nonce stores should switch to the one-method protocol.
  • OpenAPIExecutionKind.ASYNC_POLLING: pruned; a 202 + Location OpenAPI operation now classifies as SYNC.
  • Dead binary/base64 WS framing: frames are JSON text only.

Deprecated (remove in v2.6.0)

  • from asap.transport.websocket import ... — use asap.transport.ws directly.
  • from asap.adapters.mcp import ... — use asap.mcp.auth directly.
  • RemoteFatalRPCError / RemoteRecoverableRPCError — use RemoteRPCError + is_recoverable.
  • metering_storage_adapter — use MeteringStorageBridge.
  • FRAME_ENCODING_BINARY — binary framing is gone; the literal remains on the shim for import compat only.

Migration

  • v2.5.0 → v2.5.1: No breaking changes. Update deprecated import paths at your convenience (removed in v2.6.0). If you run an OAuth2-only deployment, note that /asap/ws now requires a Bearer JWT in the handshake — see migration guide.


Full Changelog: v0.1.0...v2.5.1