Repository: hyperledger/aries-cloudagent-python

Issue:
`connection_protocol` should be set when only one `handshake_protocol` specified
@nodlesh reported that there are some failing tests in AATH as a result of a change I made in #2748:

The `connection_protocol` property is omitted from the webhook topic `connections` during the `invitation` state. This is a breaking change for controllers that depended on that value being set at the invitation phase.

### Background to the change

OOB permits specifying one or more `handshake_protocols`. If more than one protocol is specified, at the invitation phase, we don't know what connection protocol will be used. We have to wait until we receive a request from either the `connections/1.0`, `didexchange/1.0`, or `didexchage/1.1` protocol to know for sure. Before #2748, we did not have `didexchange/1.1` but we still had the two other options. Despite this uncertainty during the invitation phase, ACA-Py was emitting `didexchange/1.0`, even though the receiver of the invitation could use `connections/1.0` instead.

I "fixed" the bug by omitting the `connection_protocol` from the connection record until the request phase since that's the point at which we would know for sure what the protocol used actually was.

### Solution

The proposed solution is to try to not lie about the protocol but still include the `connection_protocol` at the invitation phase if we can, i.e. when there is only one handshake protocol selected. Assuming controllers are likely using OOB for DID Exchange only, the `connection_protocol` can be set to `didexchange/1.0` at the invitation phase and they can continue on their merry way.

When multiple `handshake_protocols` are specified, however, I believe we should omit the value from the webhook rather than "lie" to the controller about which protocol the connection is using.

This would still constitute a breaking change but would hopefully cover the most common case of using OOB for DID Exchange only (or even OOB for connections only, though I find this an unlikely combination).

cc: @swcurran @ianco 


Discussion:
Side note that I did a quick scan through a "real world" controller and found that we don't depend on the value of `connection_protocol` until the connection has completed, just to offer a data point.
I think that sounds right. Thanks for the analysis. In the changeling, let’s add a reference to this issue as the background to the change and what to do if upgrading and adding multiple `handshake_protocols` at the same time.

Resolving patch:
diff --git a/aries_cloudagent/protocols/out_of_band/v1_0/manager.py b/aries_cloudagent/protocols/out_of_band/v1_0/manager.py
--- a/aries_cloudagent/protocols/out_of_band/v1_0/manager.py
+++ b/aries_cloudagent/protocols/out_of_band/v1_0/manager.py
@@ -302,6 +302,13 @@ async def handle_handshake_protos(
         no connection is created, representing a connectionless exchange.
         """
         assert self.handshake_protocols
+
+        if len(self.handshake_protocols) == 1:
+            connection_protocol = DIDCommPrefix.unqualify(self.handshake_protocols[0])
+        else:
+            # We don't know which protocol will be used until the request is received
+            connection_protocol = None
+
         conn_rec = ConnRecord(
             invitation_key=invitation_key,
             invitation_msg_id=self.msg_id,
@@ -310,6 +317,7 @@ async def handle_handshake_protos(
             state=ConnRecord.State.INVITATION.rfc23,
             accept=self.auto_accept,
             alias=self.alias,
+            connection_protocol=connection_protocol,
         )
 
         async with self.profile.transaction() as session:


Test patch: