diff --git a/features/a2a_facade_wiring.feature b/features/a2a_facade_wiring.feature index cf27d1eac..c2ee8f207 100644 --- a/features/a2a_facade_wiring.feature +++ b/features/a2a_facade_wiring.feature @@ -34,6 +34,15 @@ Feature: A2A local facade wiring to live services When I dispatch wired operation "session.close" with params {} Then the wired response status should be "error" + # --------------------------------------------------------------- + # Validate session_id at entry — no service scenario (PR #9250) + # --------------------------------------------------------------- + + Scenario: session.close without session_id and no service returns error + Given a wired A2aLocalFacade with no services + When I dispatch wired operation "session.close" with params {"session_id": ""} + Then the wired response status should be "error" + # --------------------------------------------------------------- # Plan lifecycle wiring # --------------------------------------------------------------- diff --git a/src/cleveragents/a2a/facade.py b/src/cleveragents/a2a/facade.py index cde509258..1519c6c35 100644 --- a/src/cleveragents/a2a/facade.py +++ b/src/cleveragents/a2a/facade.py @@ -361,9 +361,13 @@ class A2aLocalFacade: session = svc.create(actor_name=actor_name) return {"session_id": session.session_id, "status": "created"} - def _handle_session_close(self, params: dict[str, Any]) -> dict[str, Any]: + def _handle_session_close(self, params: dict[str, Any]) -> dict[str, Any]: session_id = params.get("session_id", "") + # Validate session_id before any cleanup or service operations. + # This prevents best-effort devcontainer cleanup from running on + # an invalid or omitted session identifier, which could trigger + # incorrect container lifecycle operations on wrong/unknown sessions. if not session_id: raise ValueError("session_id is required")