Repository: hyperledger/aries-cloudagent-python

Issue:
LegacyPeerDIDResolver: erroneously assigning same ID to multiple services
This appears to be the underlying issue to both:
- https://github.com/bcgov/DITP-DevOps/issues/109
- https://github.com/hyperledger/aries-cloudagent-python/issues/2474

The LegacyPeerDIDResolver is assigning the same ID to multiple services (converted from `IndyAgent` services). This results in resolved DID Docs like the following:

```json
{
  "did_document": {
    "@context": "https://w3id.org/did/v1",
    "id": "did:sov:4wvr7DC2XUtsHbpUpYaKvM",
    "authentication": [
      "did:sov:4wvr7DC2XUtsHbpUpYaKvM#1"
    ],
    "service": [
      {
        "id": "did:sov:4wvr7DC2XUtsHbpUpYaKvM#didcomm",
        "type": "did-communication",
        "priority": 0,
        "recipientKeys": [
          "did:sov:4wvr7DC2XUtsHbpUpYaKvM#1"
        ],
        "serviceEndpoint": "https://aries-endorser-agent-dev.apps.silver.devops.gov.bc.ca"
      },
      {
        "id": "did:sov:4wvr7DC2XUtsHbpUpYaKvM#didcomm",
        "type": "did-communication",
        "priority": 0,
        "recipientKeys": [
          "did:sov:4wvr7DC2XUtsHbpUpYaKvM#1"
        ],
        "serviceEndpoint": "wss://aries-endorser-agent-dev.apps.silver.devops.gov.bc.ca"
      }
    ],
    "verificationMethod": [
      {
        "id": "did:sov:4wvr7DC2XUtsHbpUpYaKvM#1",
        "type": "Ed25519VerificationKey2018",
        "controller": "did:sov:4wvr7DC2XUtsHbpUpYaKvM",
        "publicKeyBase58": "39msujHp1jPTPbWA5Ry9BnwGvbVw8WYGh8WYjoEryyQp"
      }
    ]
  },
  "metadata": {
    "resolver_type": "native",
    "resolver": "LegacyPeerDIDResolver",
    "retrieved_time": "2023-09-07T12:53:06Z",
    "duration": 42
  }
}
```

The corrections should be assigning unique IDs to the two services in this example.

This will require a patch release to be pushed out. This will be the first release after the Poetry conversion. We should get #2471 merged in support of this release as well.

@swcurran @WadeBarnes @usingtechnology 


Discussion:

Resolving patch:
diff --git a/aries_cloudagent/resolver/default/legacy_peer.py b/aries_cloudagent/resolver/default/legacy_peer.py
--- a/aries_cloudagent/resolver/default/legacy_peer.py
+++ b/aries_cloudagent/resolver/default/legacy_peer.py
@@ -115,13 +115,13 @@ def authentication_is_list_of_verification_methods_and_refs(value: dict) -> dict
     def didcomm_services_use_updated_conventions(value: dict) -> dict:
         """Update DIDComm services to use updated conventions."""
         if "service" in value:
-            for service in value["service"]:
+            for index, service in enumerate(value["service"]):
                 if "type" in service and service["type"] == "IndyAgent":
                     service["type"] = "did-communication"
                     if ";" in service["id"]:
-                        service["id"] = value["id"] + "#didcomm"
+                        service["id"] = value["id"] + f"#didcomm-{index}"
                     if "#" not in service["id"]:
-                        service["id"] += "#didcomm"
+                        service["id"] += f"#didcomm-{index}"
                     if "priority" in service and service["priority"] is None:
                         service.pop("priority")
         return value


Test patch:
diff --git a/aries_cloudagent/resolver/default/tests/test_legacy_peer.py b/aries_cloudagent/resolver/default/tests/test_legacy_peer.py
--- a/aries_cloudagent/resolver/default/tests/test_legacy_peer.py
+++ b/aries_cloudagent/resolver/default/tests/test_legacy_peer.py
@@ -173,7 +173,7 @@ async def test_resolve_x_not_found(
                     "authentication": ["did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1"],
                     "service": [
                         {
-                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#didcomm",
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#didcomm-0",
                             "type": "did-communication",
                             "priority": 0,
                             "recipientKeys": ["did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1"],
@@ -229,7 +229,7 @@ async def test_resolve_x_not_found(
                     "authentication": ["did:sov:5qXMeLdyWEQhieFUBNw5ux#1"],
                     "service": [
                         {
-                            "id": "did:sov:5qXMeLdyWEQhieFUBNw5ux#didcomm",
+                            "id": "did:sov:5qXMeLdyWEQhieFUBNw5ux#didcomm-0",
                             "type": "did-communication",
                             "recipientKeys": ["did:sov:5qXMeLdyWEQhieFUBNw5ux#1"],
                             "serviceEndpoint": "http://172.17.0.1:9031/a2a/5b6dyY6PndLaCnWxZbeEYW/5b6dyY6PndLaCnWxZbeEYW/2f6aae0c-6b04-40ff-a25e-faecaea39f83",
@@ -276,7 +276,7 @@ async def test_resolve_x_not_found(
                     "authentication": [],
                     "service": [
                         {
-                            "id": "did:sov:1H6d1WS29Bcfr7Bb9tZxA#didcomm",
+                            "id": "did:sov:1H6d1WS29Bcfr7Bb9tZxA#didcomm-0",
                             "type": "did-communication",
                             "priority": 0,
                             "recipientKeys": ["did:sov:1H6d1WS29Bcfr7Bb9tZxA#cSwsDbSW"],
@@ -338,7 +338,7 @@ async def test_resolve_x_not_found(
                     "authentication": ["did:sov:PkWfCgY4SSAYeSoaWx3RFP#1"],
                     "service": [
                         {
-                            "id": "did:sov:PkWfCgY4SSAYeSoaWx3RFP#didcomm",
+                            "id": "did:sov:PkWfCgY4SSAYeSoaWx3RFP#didcomm-0",
                             "type": "did-communication",
                             "priority": 0,
                             "recipientKeys": ["did:sov:PkWfCgY4SSAYeSoaWx3RFP#1"],
@@ -409,6 +409,87 @@ async def test_resolve_x_not_found(
                     ],
                 },
             ),
+            (  # Doc with multiple services
+                {
+                    "@context": "https://w3id.org/did/v1",
+                    "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ",
+                    "publicKey": [
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1",
+                            "type": "Ed25519VerificationKey2018",
+                            "controller": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ",
+                            "publicKeyBase58": "AU2FFjtkVzjFuirgWieqGGqtNrAZWS9LDuB8TDp6EUrG",
+                        }
+                    ],
+                    "authentication": [
+                        {
+                            "type": "Ed25519SignatureAuthentication2018",
+                            "publicKey": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1",
+                        }
+                    ],
+                    "service": [
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ;indy",
+                            "type": "IndyAgent",
+                            "priority": 0,
+                            "recipientKeys": [
+                                "AU2FFjtkVzjFuirgWieqGGqtNrAZWS9LDuB8TDp6EUrG"
+                            ],
+                            "routingKeys": [
+                                "9NnKFUZoYcCqYC2PcaXH3cnaGsoRfyGgyEHbvbLJYh8j"
+                            ],
+                            "serviceEndpoint": "http://bob:3000",
+                        },
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ;indy-ws",
+                            "type": "IndyAgent",
+                            "priority": 1,
+                            "recipientKeys": [
+                                "AU2FFjtkVzjFuirgWieqGGqtNrAZWS9LDuB8TDp6EUrG"
+                            ],
+                            "routingKeys": [
+                                "9NnKFUZoYcCqYC2PcaXH3cnaGsoRfyGgyEHbvbLJYh8j"
+                            ],
+                            "serviceEndpoint": "ws://bob:3000",
+                        },
+                    ],
+                },
+                {
+                    "@context": "https://w3id.org/did/v1",
+                    "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ",
+                    "verificationMethod": [
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1",
+                            "type": "Ed25519VerificationKey2018",
+                            "controller": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ",
+                            "publicKeyBase58": "AU2FFjtkVzjFuirgWieqGGqtNrAZWS9LDuB8TDp6EUrG",
+                        }
+                    ],
+                    "authentication": ["did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1"],
+                    "service": [
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#didcomm-0",
+                            "type": "did-communication",
+                            "priority": 0,
+                            "recipientKeys": ["did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1"],
+                            "routingKeys": [
+                                "did:key:z6Mknq3MqipEt9hJegs6J9V7tiLa6T5H5rX3fFCXksJKTuv7#z6Mknq3MqipEt9hJegs6J9V7tiLa6T5H5rX3fFCXksJKTuv7"
+                            ],
+                            "serviceEndpoint": "http://bob:3000",
+                        },
+                        {
+                            "id": "did:sov:JNKL9kJxQi5pNCfA8QBXdJ#didcomm-1",
+                            "type": "did-communication",
+                            "priority": 1,
+                            "recipientKeys": ["did:sov:JNKL9kJxQi5pNCfA8QBXdJ#1"],
+                            "routingKeys": [
+                                "did:key:z6Mknq3MqipEt9hJegs6J9V7tiLa6T5H5rX3fFCXksJKTuv7#z6Mknq3MqipEt9hJegs6J9V7tiLa6T5H5rX3fFCXksJKTuv7"
+                            ],
+                            "serviceEndpoint": "ws://bob:3000",
+                        },
+                    ],
+                },
+            ),
         ],
     )
     def test_corrections(self, input_doc: dict, expected: dict):